节点:如何根据env需要不同的类
在节点中,模块导入(又名require())被硬编码到需要导入的每个文件(又名模块)中。 这可能是几十个或者在我们的情况下有数百个重复的import。 我们以dynamic方式“要求”的主要是服务,例如“playerService”包含查找,更新,获取方法等,但也可以是域对象或持久性库
关键是我们有这个“playerService”js文件的3个版本。 一个在本地(在内存中)进行开发的东西,一个用本地数据库(testing)完成所有工作的东西,一个用API(live)与外部系统完成所有事情的东西。 在这种情况下开关在环境(开发,testing或生活)。
值得注意的是,我们可以在任何地方使用类,因为我们发现返回函数的函数等的函数是不可读/可维护的(我们是java开发人员真正挣扎于js)
我们也专门在我们的节点应用程序中使用web套接字 – 没有http代码。
所以我们的服务如下所示:
const Player = require("./player") class PlayerService { constructor(timeout) { this.timeout= 3000 // todo, put in a config file if (timeout != null) {this.timeout= timeout} } updatePlayer(player) { // logic to lookup player in local array and change it for dev version. // test version would lookup player in DB and update it. } } module.exports = PlayerService
我们熟悉Grails和Spring的dependency injection,但是还没有发现节点的任何可理解的东西(见下文)。 尽pipe阅读广泛,但我们不是JavaScript,也不是节点大师。
目前我们正在考虑这些选项之一,但希望听到更好的build议:
选项1:
- 硬编码“dev”需要,例如require(“./ dev / playerSerice”)
- 有一个jenkins生成服务器重写每个文件的源代码要求(“./testing/ playerSerice”)。
选项2:
- 硬编码的“dev”要求,例如要求(“./ playerSerice”)
- 有一个jenkins构build服务器交换文件/testing/播放器服务/ playerService“./playerService。
显然,这使得开发人员很难在本地机器上运行testing版或专业版,而不会破坏源代码。
选项3: 1.将所需的模块path放在一个configuration文件中。 2.只换出configuration文件。 例如
let Config = require("./config") let PlayerService = require(Config.playerService)
我们试图使这个依赖于env,并有一个开发,testing和prodconfiguration的全局configuration骑这些,但没有find一个优雅的方式来做到这一点。 一种方法可能是在每个模块的顶部复制这些代码:
let env = process.env.NODE_ENV || 'development' let config = require('./config.'+env); let PlayerService = require("./" + Config.playerService)
然后在config.development.js中:
var config = require("./config.global") config.PlayerService = "devPlayerService" module.exports = config
scheme4:也许这样的事情会起作用:
let env = process.env.NODE_ENV || 'development' require("./" + env + "/playerService")
上述所有的解决scheme都由于缺乏单例而受到影响 – 服务是无状态的。 我们猜测节点将为每个请求(或者我们的例子中的web套接字消息)构造每个服务的新副本。 有没有办法减less这种情况?
很显然,一些简单,可读且正式维护的dependency injectionforms是很好的,有一些方法可以在注入的类集之间切换。
我们已经阅读了以下文章:
- https://blog.risingstack.com/dependency-injection-in-node-js/生成的代码是不可读的(至less对我们来说)。 这样做的例子并没有帮助,团队只是某种用户的代理包装,而不是服务或任何有用的东西。 什么是选项? 为什么select?
- https://medium.com/@Jeffijoe/dependency-injection-in-node-js-2016-edition-f2a88efdd427
但发现他们不可理解。 例如,这些例子中的关键词来自于稀薄的空气 – 它们似乎不是JavaScript或者节点的命令,在文档中没有解释它们来自哪里。
并看了这些项目:
- https://github.com/jaredhanson/electrolyte
- https://www.npmjs.com/package/node-dependency-injection
- https://www.npmjs.com/package/di
但他们似乎要么放弃(二),不维护,或者我们不能弄清楚(电解质)。
是否有一些标准或简单的解决scheme,许多人正在使用,最好logging在凡人和一个非“明确”的依赖的例子?
更新1
看来我用来创build我的服务的模式创build一个新的实例,它被使用/调用。 服务应该是单身人士。 简单的解决scheme是将其添加到我的服务的底部:
let playerService = new PlayerService(); module.exports = playerService;
显然,这只会创build对象的一个实例,不pipe现在多次需要(“./ playerService”)被调用。
为了保持每个env的configuration,正确的方法可能是(类似于你的build议) – 保持一个configuration/ env目录,并把每个env的文件,如development.js,test.js等,并在每个把正确的价值观。 例如:
module.exports = { playerService: 'dev/PlayerService' }
并要求:
let env = process.env.NODE_ENV || 'development' , envConfig = require("./config/" + env) , playerService = require(envConfig.playerService)
你也可以像这样在一个文件中包含全部内容:config.js:
module.exports = { development:{ playerService: '....' }, test:{ playerService: '....' } }
并要求:
let env = process.env.NODE_ENV || 'development' , config = require("./config") , playerService = require(config[env][playerService])
这是一个常见的用例。
或者,如果每个env都有目录中的所有服务,例如dev一个目录,一个testing等目录,则不需要configuration,您可以这样要求:
let env = process.env.NODE_ENV || 'development' , playerService = require('./' + env + '/playerServcie')
在节点js中创build单例服务应该很简单,看看下面的内容:
https://blog.risingstack.com/fundamental-node-js-design-patterns/
https://www.sitepoint.com/javascript-design-patterns-singleton/
和这个
希望这可以帮助。