动态 require 问题的解决
需求
目前正在开发一个基于element-ui
二次开发的UI库。这个库名字暂且叫etion-ui
实际的项目中需要进行etion-ui
的调试,这个业务项目暂且叫etion-web
,该项目使用的是vue2.x
版本的框架。
etion-ui的打包
为了给 etion-web
的调试,我这里将etion-ui
打包成两个文件夹:
└── etion-ui
└── dist // 生产环境下的压缩后的代码
└── etion-ui.umd.js
└── example // 开发环境下 需要调试无压缩的代码
└── dist
└── etion-ui.umd.js
etion-web的引用处理
具体实现
运行脚本如下:
## 1. 我这里采用的`yalc`做本地环境的映射。需要本地已经启动了 yalc 对 etion-ui的映射
## 2. 添加一个环境变量 VUE_APP_UI_TEST=TRUE,然后在etion-web项目中读取到,引入不同的文件达到调试跟线上环境的区分
yalc add etion-ui && cross-env VUE_APP_UI_TEST=TRUE vue-cli-service serve
main.js
中的处理
import Vue from 'vue'
// 获取到是否是UI测试环境
const isUiTest = process.env.VUE_APP_UI_TEST === 'TRUE'
/**
* 这里采用 require 动态引入的方式
*/
const etionUIPath = isUiTest ? 'etion-ui/example/dist/etion-ui.umd.js' : 'etion-ui/dist/etion-ui.umd.js'
const EtionUI = require(etionUIPath)
Vue.use(EtionUI)
产生的问题
直接运行后直接报错:
Uncaught Error: Cannot find module 'etion-ui/example/dist/etion-ui.umd.js'
at webpackEmptyContext (eval at ./src sync recursive (app.js:2660:1), <anonymous>:2:10)
at eval (main.js?56d7:59:1)
at ./src/main.js (app.js:4923:1)
at __webpack_require__ (app.js:854:30)
at fn (app.js:151:20)
at 1 (app.js:5527:18)
at __webpack_require__ (app.js:854:30)
at checkDeferredModules (app.js:46:23)
at app.js:994:18
at app.js:997:10
解决产生的问题
看到上述报错的时候,我是一脸黑线。地址也都没有写错。为什么不行呢?
产生原因:
webpack本身是一个预编译路径 不能require纯变量的打包工具,无法预测未知变量路径。所以require(path) ,path 至少要有三部分组成, 目录,文件名和后缀
- 目录:webpack 才知道从哪里开始查找
- 文件名:可用变量表示
- 后缀(文件后缀):必须要加上,不然会报错
错误引用
像上面main.js
中的写法是有错误的。因为全变量的时候,webpack找不到具体是哪个模块被引入
const etionUIPath = isUiTest ? 'etion-ui/example/dist/etion-ui.umd.js' : 'etion-ui/dist/etion-ui.umd.js'
const EtionUI = require(etionUIPath)
正确引用
这里放一个范例进行分析:
let imgName = 'a';
let imgAllName = 'a.png';
// example 1
let imgUrl = require('../images/a.png'); // 纯字符串
// example 2
let imgUrl = require('../images/' + imgAllName); // 目录 + 文件全名
// example 3
let imgUrl = require('../images/' + imgName + '.png'); // 目录 + 文件名 + 后缀
鉴于require
在纯变量的情况下找不到模块,所以我们至少要在require参数中写明一个目录(如代码中的example 2
和example 3
),这样的话,虽然不知道具体的模块,但是webpack也会为我们做下述的分析工作:
- 分析目录:
'../images'
- 提取正则表达式 :
/^.*.png$/
此种情况下,webpack生成的上下文模块(context module)。并且对上下文模块做如下处理:
- 它包含目录下的所有模块的引用,是通过一个 request 解析出来的正则表达式,去匹配目录下所有符合的模块,然后都 require 进来。
- 此 context module 包含一个 map 对象,会把 request 中所有模块翻译成对应的模块 id。
- 根据对应模块id,再去获取到相对应需要引用的模块
这里户产生一个问题:所有可能用到的模块都包含在 bundle 中,导致包的体积变大!!!
main.js 代码调整
import Vue from 'vue'
const isUiTest = process.env.VUE_APP_UI_TEST === 'TRUE'
- const etionUIPath = isUiTest ? 'etion-ui/example/dist/etion-ui.umd.js' : 'etion-ui/dist/etion-ui.umd.js'
- const EtionUI = require(etionUIPath)
+ const prefix = isEtionUiTest() ? 'example/' : ''
+ const EtionUI = require(`etion-ui/${prefix}dist/etion-ui.umd.js`)
Vue.use(EtionUI)
写在最后
这个文章主要是分析,动态require的解决以及自己学习的总结。
通过最后的分析之后,发现其实这里使用动态require的方式并不是一个比较好的方案,会导致包变大。
所以,后续会再进行调整使用更合适的方案。
参考文章
blog.csdn.net/liubangbo/a… (动态引入(require, import))