Webpack模块化机制与未模块化库引入
模块化机制
-
非模块化代码
例如下面的js代码
alert('hello world');
经过webpack打包后会生成这样的代码:
(function(modules) {
// 模块缓存
var installedModules = {};
// require方法
function __webpack_require__(moduleId) {
// 检测缓存
if(installedModules[moduleId])
return installedModules[moduleId].exports;
//创建缓存
var module = installedModules[moduleId] = {
exports: {},
id: moduleId,
loaded: false
};
// 执行模块
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// 标记已经加载
module.loaded = true;
// 返回module.exports
return module.exports;
}
// 暴露模块对象 (__webpack_modules__)
__webpack_require__.m = modules;
// 暴露缓存
__webpack_require__.c = installedModules;
// 暴露路径
__webpack_require__.p = "";
// 加载入口并返回
return __webpack_require__(0);
})([function(module, exports) {alert('hello world');}]);
-
AMD
模块
例如下面的AMD代码:
define([], function() {
alert('hello world!');
});
经过webpack打包后变成这样:
function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, // AMD依赖列表
__WEBPACK_AMD_DEFINE_RESULT__; // AMD factory函数的返回值,即模块内容
__WEBPACK_AMD_DEFINE_ARRAY__ = [];
// 执行factory函数,获取返回值作为模块内容
// 函数体使用.apply调用,函数体中this为exports
// 形参则分别对应依赖列表中的各个依赖模块
__WEBPACK_AMD_DEFINE_RESULT__ = function() {
alert('hello world!');
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__);
// 如果模块内容不为空,则通过module.exports返回
// 如果为空,则不处理,在Runtime中声明为{}
if (__WEBPACK_AMD_DEFINE_RESULT__ !== undefined) {
module.exports = __WEBPACK_AMD_DEFINE_RESULT__;
}
}
-
CommonJs
例如下面的CommonJs
代码:
var obj= {
sayHello:function(){
alert('hello world!');
}
};
module.exports = obj;
经过webpack打包后变成这样:
function(module, exports) {
var obj= {
sayHello: function() {
alert('hello world!');
}
};
module.exports = obj;
}
引入未模块化的库,如 Zepto
当我们引入未模块化的库的时候,如zepto的时候,会报这样的错误:
Uncaught TypeError: Cannot read property 'createElement' of undefined
-
原因
首先我们来分析下zepto的源码:
(function(global, factory) {
if (typeof define === 'function' && define.amd)
define(function() { return factory(global) })
else
factory(global)
}(this, function(window) {
var Zepto = (function() {
// ...
return $
})()
window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)
return Zepto
}))
根据打包机制可以知道, modules[moduleId].call
,它会传入新初始化的 module.exports
来作为模块闭包的上下文(context),并运行模块闭包来将模块暴露的对象加入到已加载的模块对象(installedModules)中。
所以对于 Zepto 来说,它初始化时使用的 this
其实就是 module.exports
,但这个 module.exports
没有赋值过任何变量,即 Zepto
初始化使用的 this
为空对象。
所以 factory(global)
中global
为空对象,Zepto
运行函数中的 window
也就变成了空对象,而 var document = window.document
,这个 documen
t 为 undefined
,因此会造成 document.createElement
会报 TypeError
。
-
解决办法
npm install --save-dev script-loader exports-loader
// webpack.config
{
// ...
module: {
loaders: [{
test: require.resolve('zepto'),
loader: 'exports-loader?window.Zepto!script-loader'
}]
}
}