-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebpack-externals.js
executable file
·80 lines (78 loc) · 4.82 KB
/
webpack-externals.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
const path = require('path');
/** 项目的根目录 */
let _projectRootDir = undefined;
/** 项目的产物目录 */
let _projectDistDir = undefined;
/** webpack.config.output.libaryTarget字段,umd和commonjs[2]和var的处理方式不同 */
let _libraryTarget = undefined;
/** 用户可能指定了解析别名, 比如@指向DIR_SRC */
let _resolve = undefined;
/**
* 该函数混入webpack.config.externals字段中, 可减轻开发时的编译量
* @param {*} param0
* @param {*} callback
* @returns void
*/
function excludeNodeModules({ context, request }, callback) { // 官网和CLI提示不一致,此处遵循CLI标准,从第一个参数解构request
// console.log(`导入:${context} => ${request}`);
// return callback(); // 临时关闭函数以测试
// 由宿主环境提供node_modules下的模块,但进行编译loader加载的模块
// 放行用户模块
if (!path.isAbsolute(request) && !request.match(/^\.\.?[\/\\]/)) { // require目标不是绝对路径,且不以'./'或'../'开头,则大概率就是node_modules请求。
// 要排除入口。直接遍历config.entry字段似乎不太可行,因为有隐含规则,比如缺省值:"./src/index.js"。
// 上下文不可以是项目根目录projectRootDir,从而才能编译入口(此处担心入口是相对路径,且不以'./'或'../'开头,这样会造成编译完成但运行时找不到模块)
if (true /*弃用判断*/ || context !== _projectRootDir) { // 放行webpack.config.js中定义的不以dot开头的相对路径,并警告
// 还有一种情况:在import或require语句中指定了loader,而指定方式又有强制与非强制的区别。
// 一般来说,即便这些依赖项可以在运行时加载,不过我们也希望进行编译打包,从而方便开发,比如说ts-loader
// 如果指定了loader,则一定含有感叹号!这种情况需要排除掉
if (!request.includes('!')) { // 放行loader模块
if (_resolve && _resolve.alias) { // 处理"解析别名"
for (let key in _resolve.alias) {
let value = _resolve.alias[key];
if (key.match(/\$$/) && request + '$' === key) {
request = value;
return excludeNodeModules({ context, request }, callback); // 使用递归, 导致具有重复替换的性质
} else if (request.startsWith(key)) {
request = request.replace(key, value);
return excludeNodeModules({ context, request }, callback);
}
}
}
// 替换node_modules依赖请求
let instruction = `require('${request}')`;
console.log('运行时模块:', `${request}由node_modules提供 => ${request} = ${instruction}`);
if (_libraryTarget === 'umd' || _libraryTarget === 'commonjs' || _libraryTarget === 'commonjs2') {
// console.info('UMD 或 CommonJS 模式');
return void callback(/*没有错误*/null, request); // 直接返回模块名, 而无需通过callback返回字符串`require(${request})`
}
return void callback(/*没有错误*/null, instruction);
} else {
console.log(`导入loader模块:${request}`);
}
} else { // 该警告已弃用
console.warn(`非法的入口模块:${request},请使用绝对路径、以"./"或"../"开头的相对路径定义入口`);
}
} else {
let relativeDist = path.relative(_projectDistDir, path.resolve(context, request));
let relativeRoot = path.relative(_projectRootDir, path.resolve(context, request));
// console.log(`导入用户模块:${path.resolve(context, request)}`);
console.log(`导入用户模块:${relativeRoot}`);
if (!relativeDist.startsWith('..')) {
throw new Error(`不建议使用产物目录 ${_projectDistDir} 中的模块: ${relativeDist}`);
}
}
return void callback(); // 放行入口、loader、用户模块
}
/**
* 初始化projectRootDir, 从而获取excludeNodeModules函数的引用
* @param {string} projectRootDir 项目的根目录
* @param {string} projectDistDir 项目的产物目录
* @param {string} libaryTarget webpack.config.output.libaryTarget字段,umd和commonjs[2]和var的处理方式不同
*/
module.exports = function (projectRootDir, projectDistDir, libraryTarget, resolve) {
_projectRootDir = projectRootDir;
_projectDistDir = projectDistDir;
_libraryTarget = libraryTarget;
_resolve = resolve;
return excludeNodeModules;
};