hbx-env-pack-inject
v1.0.0
Published
hbx-env-pack 的构建侧:按 env-pack.json 的 mode 加载对应 .env,再 DefinePlugin 注入 process.env。HBuilderX 打 App 包和 vue-cli 构建都适用。
Downloads
141
Readme
hbx-env-pack-inject
构建期环境变量注入。按项目根 env-pack.json 的 mode 找到对应环境变量文件,
解析后通过 DefinePlugin 注入 process.env,代码里直接写 process.env.VUE_APP_XXX。
为什么单独一个包:这段逻辑以前住在每个项目的 vue.config.js 里,换个项目就得
再复制一遍。现在只有这一份。
为什么必须有 vue.config.js,且只能留一行
HBuilderX 编译 App 时写死了唯一一个 webpack 配置入口:
// <HBuilderX>/plugins/uniapp-cli/bin/uniapp-cli.js
const vueConfigJsPath = path.resolve(process.env.UNI_INPUT_DIR, 'vue.config.js')
if (fs.existsSync(vueConfigJsPath)) {
process.env.VUE_CLI_SERVICE_CONFIG_PATH = vueConfigJsPath
}HBuilderX 插件没有任何构建期扩展点(contributes 里只有 commands / menus /
launchers / configuration 这些,没有构建钩子),所以 <项目根>/vue.config.js
这个文件躲不掉 —— 但它的内容可以只剩一行,逻辑放在本包里。
用法
项目里加依赖,然后把 vue.config.js 包在 withEnvInject() 外面:
{
"dependencies": {
"hbx-env-pack-inject": "file:../install-App/packages/hbx-env-pack-inject"
}
}// vue.config.js —— 它仍然是项目自己的配置文件,只是外面包了一层
const { withEnvInject } = require('hbx-env-pack-inject')
module.exports = withEnvInject({
// 项目自己的 vue-cli 配置照常写在这里,跟本包互不干扰
devServer: { port: 8080 },
chainWebpack(config) { /* ... */ }
})为什么不让项目直接 module.exports = require('hbx-env-pack-inject'):
vue.config.js 是项目自己的配置文件,直接整个导出本包等于把它占掉了,
以后想加 devServer、加自己的 chainWebpack 就没地方写。所以主 API 是
withEnvInject(userOptions),把注入挂到你那份配置上。
项目还要有:
| 文件 | 作用 |
|---|---|
| env-pack.json | 环境列表 + 当前环境(mode),要提交。由 HBuilderX 插件 hbx-env-pack 维护 |
| .env.<环境> | 各环境的环境变量,只认 VUE_APP_ 前缀 |
改本包的配置(配置文件不叫 env-pack.json、前缀不是 VUE_APP_),第二个参数传进去:
module.exports = withEnvInject(
{ /* 项目自己的配置 */ },
{ configFile: 'env-rc.json', prefix: 'CUSTOM_' }
)三个导出怎么选
| 导出 | 用在什么时候 |
|---|---|
| withEnvInject(userOptions?, pluginOptions?) | 默认选它。项目有自己的 vue-cli 配置时 |
| chainWebpack | 项目确实没有别的配置,且想省掉那层包装 |
| create(pluginOptions) | 只要注入函数本身,chainWebpack 想自己组装 |
顺序
项目自己的 chainWebpack 先跑,注入后跑。因为注入要复用 uni-app 已经注册好的
define 插件(config.plugin('define').tap(...)),先让你那份有机会注册或改写它,
注入再去 tap 才拿得到同一个插件;反过来这里可能自己新挂一个 DefinePlugin,
两个都定义 process.env.X,谁生效就说不清了。
对照 vue-cli 的配置文档
本包只用到 vue.config.js 里两样东西,签名跟文档一致(schema 见
@vue/cli-service/lib/options.js):
// webpack
chainWebpack: joi.func(),
configureWebpack: joi.alternatives().try(joi.object(), joi.func()),
// 3rd party plugin options
pluginOptions: joi.object()本包提供的就是一个 chainWebpack 函数(chainWebpack: joi.func() 那个),
用 withEnvInject() 包一层只是为了它跟你自己的那份不打架。
vue.config.js 本身也可以是函数,@vue/cli-service/lib/Service.js 里:
fileConfig = require(configPath)
if (typeof fileConfig === 'function') {
fileConfig = fileConfig()
}所以本包如果哪天要支持「不传参直接 require」,靠的也是这条,不需要额外机制。
为什么不用 vue-cli 插件那条路(vue-cli-plugin-* 包 + pluginOptions 传参,
文档「插件开发」一节的正规做法):HBuilderX 下走不通。Service.js 的
resolvePlugins 是从它自己所在目录 require 项目声明的插件的,而 HBuilderX 用的是
它自带的那份 @vue/cli-service(在 plugins/uniapp-cli/node_modules 里),
永远解析不到项目的 node_modules。详见下一节。
跨项目复用只有这一条路:vue.config.js 就是个普通 Node 模块,require 一个 npm 包
就行 —— 没有别的共享机制(vue-cli 的 presets 是 vue create 的脚手架模板,跟运行时
注入无关)。所以本包就是个普通 npm 包,不是 vue-cli 插件。
两个坑(改这个包之前先读)
包名不能叫 vue-cli-plugin-*
@vue/cli-service 的 resolvePlugins 会把项目 package.json 里匹配
/^(@vue[\/\\]|vue-cli-plugin-|@[\w-]+\/vue-cli-plugin-)/ 的依赖自动 require:
const projectPlugins = Object.keys(this.pkg.devDependencies || {})
.concat(Object.keys(this.pkg.dependencies || {}))
.filter(isPlugin)
.map(id => idToPlugin(id)) // → { apply: require(id) }而那个 require 是从 Service.js 自己所在的目录解析的 —— HBuilderX 下是
<HBuilderX>/plugins/uniapp-cli/node_modules/@vue/cli-service/lib/,
解析路径永远走不到项目的 node_modules。真取了那个名字,项目一声明该依赖,
HBuilderX 就会在构建最开始抛 MODULE_NOT_FOUND。
现在这个名字不会被自动加载,只能由 vue.config.js 显式 require ——
而那是从项目根解析的,正好命中项目的 node_modules。
项目根不能再靠 __dirname
这段代码以前住在项目的 vue.config.js 里,__dirname 恰好就是项目根。
搬进 node_modules/ 之后 __dirname 是包自己的目录,照着它找 env-pack.json
会找到 node_modules 里去。现在改用 process.env.UNI_INPUT_DIR || process.cwd():
UNI_INPUT_DIR由 HBuilderX 设置(uniapp-cli.js进来第一件事就是path.resolve它, 所以走 HBuilderX 时一定有值)- 脱离 HBuilderX 直接跑
vue-cli-service时退回cwd—— 那种情况下命令就是在项目根敲的
依赖没装会怎样
硬报错,不会静默失效:
// @vue/cli-service/lib/Service.js
} catch (e) {
error(`Error loading ${chalk.bold('vue.config.js')}:`)
throw e
}npm install 没跑,构建会直接失败并打出 Error loading vue.config.js。
这比「静默注入 0 个变量、请求打到 undefined/api」好得多。
