问题
我们有两套环境,开发环境和生产环境。同一个功能,在不同的环境中,业务逻辑一模一样,但有些基础性的值不一样(例如IP地址、数据的ID等)。我们会尽可能从环境中动态获取这些值(例如字段ID),使代码能直接跨环境使用,但总有些值无法动态获取(例如后端IP地址),必须对不同环境分别指定。因此,开发框架需要支持环境配置功能。
初步实现
规定:开发环境的标识为dev,生产环境的标识为prod。
目录结构
将脚本目录的结构扩展为如下形式:
config.dev.js:开发环境的配置代码。config.prod.js:生产环境的配置代码。index.js:业务逻辑代码,对所有环境都相同。index.scss/index.css:样式代码,对所有环境都相同。
index.js应尽可能从环境中动态获取所需的值,只有不得不分环境配置时,才使用config.dev.js和config.prod.js。
在config.dev.js和config.prod.js中,通常只有形如const NAME = value;的常量定义,常量名完全相同,只是值不同。
config..js和index.js在构建时会直接拼接在一起,因此它们的代码处在同一个作用域中,index.js中直接使用config..js中的常量名。
构建程序
构建时必须指定对哪个环境构建。让构建程序接收参数--dev或--prod(有且只能有一个),得到当前环境的标识(dev或prod)。
构建脚本目录时,先读取对应环境标识的配置文件config..js(如果有),再读取index.js,然后直接拼接它们得到JSX代码,最后统一做JSX编译得到JS代码。
启动命令
修改package.json:
"scripts": {
"build-dev": "node index.js --dev",
"build-prod": "node index.js --prod",
"watch-dev": "node index.js --watch --dev",
"watch-prod": "node index.js --watch --prod"
}
运行对应的命令执行不同的构建模式和环境配置:
# 一次性构建,开发环境
npm run build-dev
# 一次性构建,生产环境
npm run build-prod
# 持续构建,开发环境
npm run watch-dev
# 持续构建,生产环境
npm run watch-prod
同时构建所有环境
问题
目前dist/的构建结果是只针对一个环境的。但实际开发时,我们经常有如下场景:
- 在生产环境上做一个仅开发人员可见的页面,然后直接在生产环境上开发,因为这样可以使用生产环境的数据直接看到最终效果。
- 生产环境中出了问题,就要在生产环境上调试业务代码。
在这些场景下,经常手上同时还有要在开发环境上做的工作,因此,如果dist/中只有一个环境的构建结果,我们就需要来回切换环境重新构建,很不方便。
解决办法
在dist/下增加dev/和prod/目录。对每个脚本目录,框架都总是输出两个版本的成品JS文件。绝大部分业务代码都是较小的、独立的,与复杂的、整体性的前端工程项目(如create-react-app框架项目)不同,同时构建两个环境并不会很慢。
构建程序不再接收--dev和--prod参数,而是维护一个环境标识的常量列表,这也便于未来增加新的环境。构建源目录时,对每个环境标识都构建一份JS代码。为了提高性能,先对index.js做JSX编译,再分别对每个config..js做JSX编译,然后再拼接,因为index.js最复杂,JSX编译最耗时,只需要编译一次。
内置Web服务器也要修改,将原来的单个服务器改为多个。遍历环境标识列表,为每个环境创建一个Express服务器,响应dist//目录的静态文件,端口号从8000依次顺延。
修改package.json:
"scripts": {
"build": "node index.js",
"watch": "node index.js --watch"
}
部署时,将dist/中对应环境的子目录中的成品文件上传到对应的OA服务器。