简介
webpack 的 output.libraryTarget 有多种参数,每种参数都会影响最终编译后的文件。笔者在下文中,将结合实际编译完成后的文件,介绍 libraryTarget 对源代码的实际影响。
前言
webpack 官方文档将 libraryTarget 主要分为三类:
- Expose a Variable: 暴露为一个变量
- Expose Via Object Assignment: 通过对象属性暴露
- Module Definition Systems: 模块定义系统
首先我们将 webpack 编译后的文件进行简化,去除模块系统相关的逻辑,只保留最终导出的结果和赋值语句,最后的代码如下:
--- webpack编译后的文件:dist/index.js
// 构建模块函数
function a() {
...
return __webpack_require__(__webpack_require__.s = "./src/index.js");
}
导出 a() // libraryTarget不同,导出语句不同
--- 其他模块
require('dist/index.js');
由于 libraryTarget 只是影响最后的赋值导出操作,所以我们这里假设构建后的模块固定,只通过对比最终的赋值操作,来描述 library 和 libraryTarget 的实际效果。现假设构建后的模块如下所示:
{
name: 'jack',
age: 24
}
接下来,笔者将结合该返回值,简化描述编译后的实际代码。
第一类:暴露为一个变量
一、libraryTarget: “var”
webpack 配置:
output: {
...
libraryTarget: 'var',
},
编译后的文件如下所示:
(() => {
return {
name: 'jack',
age: 24,
};
})();
特点:
- 没有赋值操作,所以其他文件没法引用该对象
加了 library 之后的 webpack 配置:
output: {
...
library: 'finalModule',
libraryTarget: 'var',
},
编译后的文件如下所示:
var finalModule = (() => {
return {
name: 'jack',
age: 24,
};
})();
特点:
- 有赋值操作,赋值给 library 定义的变量。
二、libraryTarget: “assign”
webpack 配置:
output: {
...
libraryTarget: 'assign',
},
编译后的文件如下所示:
= (() => {
return {
name: 'jack',
age: 24
}
})()
特点:
- 语法错误。可见该值需要绑定 library 属性
加了 library 之后的 webpack 配置:
output: {
...
library: 'finalModule',
libraryTarget: 'assign',
},
编译后的文件如下所示:
finalModule = (() => {
return {
name: 'jack',
age: 24,
};
})();
特点:
- 赋值给全局变量, 可能会覆盖宿主环境下的同名属性值。
第二类:通过对象属性暴露
一、libraryTarget: “this”
webpack 配置:
output: {
...
libraryTarget: 'this',
},
编译后的文件如下所示:
((e, a) => {
for (var i in a) {
e[i] = a[i];
}
})(
this,
(() => {
return {
name: 'jack',
age: 24,
};
})()
);
加了 library 之后的 webpack 配置:
output: {
...
library: 'finalModule',
libraryTarget: 'this',
},
编译后的文件如下所示:
this['finalModule'] = (() => {
return {
name: 'jack',
age: 24,
};
})();
特点:
- 不加 library,则将所有属性 mixin 到 this 上
- 加 library,则将对象挂载到 this[library]字段上
二、libraryTarget: “window”
逻辑同 this,只是将 this 替换成 window
三、libraryTarget: “global”
逻辑同 this,只是将 this 替换成 global(由于 webpack 默认 target 为"web",所以默认即使设置 libraryTarget 为 global,最终的挂载对象仍然是 window。需要先将 target 改为"node",才能使得挂载对象为 global)
四、libraryTarget: “commonjs”
逻辑同 this,只是将 this 替换成 exports
第三类:更符合模块定义系统
一、libraryTarget:“commonjs2”
webpack 配置:
output: {
...
libraryTarget: 'commonjs2',
},
编译后的文件如下所示:
module.exports = (() => {
return {
name: 'jack',
age: 24
}
})());
加了 library 之后的 webpack 配置:
output: {
...
library: 'finalModule',
libraryTarget: 'commonjs2',
},
编译后的文件同上
特点:
- 符合 commonjs 规范
- 加了 library 没有效果
二、libraryTarget:“amd”
webpack 配置:
output: {
...
libraryTarget: 'amd',
},
编译后的文件如下所示:
define(() => {
return (() => {
return {
name: 'jack',
age: 24,
};
})();
});
加了 library 之后的 webpack 配置:
output: {
...
library: 'finalModule',
libraryTarget: 'amd',
},
编译后的文件如下所示:
define('finalModule', [], () => {
return (() => {
return {
name: 'jack',
age: 24,
};
})();
});
特点:
- 符合 amd 规范
- 加了 library,会改为定义 library 模块
三、libraryTarget:“umd”
webpack 配置:
output: {
...
libraryTarget: 'umd',
},
编译后的文件如下所示:
(function webpackUniversalModuleDefinition(root, factory) {
if (typeof exports === 'object' && typeof module === 'object') module.exports = factory();
else if (typeof define === 'function' && define.amd) define([], factory);
else {
var a = factory();
for (var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
}
})(window, () => {
return (() => {
return {
name: 'jack',
age: 24,
};
})();
});
加了 library 之后的 webpack 配置:
output: {
...
library: 'finalModule',
libraryTarget: 'umd',
},
编译后的文件如下所示:
(function webpackUniversalModuleDefinition(root, factory) {
if (typeof exports === 'object' && typeof module === 'object') module.exports = factory();
else if (typeof define === 'function' && define.amd) define([], factory);
else if (typeof exports === 'object') exports['finalModule'] = factory();
else root['finalModule'] = factory();
})(window, () => {
return (() => {
return {
name: 'jack',
age: 24,
};
})();
});
特点:
- 定义了兼容各种模块的执行函数
- 不加 library,则将所有属性 mixin 到导出模块上
- 加 library,则将对象挂载到导出模块的 library 字段上
注意:
同之前的 libraryTarget: "global"一样,需要将 target 改为 node,编译后的 window 才会被改为 global