1. 问题,import和exports或者module.exports、define等情况混用,会导致exports为undefiend
只要用了import,都会转为__wepack_exports去包裹,则里面的exports会是没有定义的
例如 Input
import CMDModule from './module/CMDModule';
exports.a = {}
Output:
/*! no exports provided */
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _module_CMDModule__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./module/CMDModule */ "./src/module/CMDModule.js");
/* harmony import */ var _module_CMDModule__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_module_CMDModule__WEBPACK_IMPORTED_MODULE_0__);
//可以看出这里的exports就是没有定义的
exports.a = {};
})
(同样,如果用define去转换也是一样的)
这里引申出一个bug: babel-transfromruntime 去转化export * 时出现问题 原因: 根据sokra(webpack负责人说法):
概就是transform-runtime插入的是esm的模块,webpack去转esm。 然后babel将esm转为cjs,转换顺序问题引起的,官方就是说建议将babel的模块转换停了{modules:false},因为webpack2以上已经识别import的esm了
FROM : https://github.com/webpack/webpack/issues/4961
2. webpack打包相互引用的模块时可能会出错
在有2个或2个以上的文件之间的相互依赖关系构成闭环的时候,有时会出现Can't read Property 'xxx' of undefined或者(0,xxx) is not a function这类的错误,
问题原因:
- 当模块还处于第一次执行中的状态时,如果碰到相互引用的情况的话,webpack可能会认为一个没有完全加载完成的模块已经加载完了
当 export function 时
/***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); //注意这里!!! 这里用function定义的方式,一开始就进行了预解析,所以console这里是有定义的, exports._console = _console; var _a = __webpack_require__(2); var _a2 = _interopRequireDefault(_a); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _console() { console.log('this is index.js'); } /***/ }),
export const 时
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
//注意这里,一开始定义为undefined
exports._console = undefined;
//这里去引入模块2, 模块2里面如果又引入了本模块,就会去到上面的undefiend值,
var _a = __webpack_require__(2);
var _a2 = _interopRequireDefault(_a);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
//因为这里用的是variable的方式而不是function,所以没执行到这里就是无定义的
var _console = exports._console = function _console() {
console.log('this is index.js');
};
/***/ }),
使用赋值语句export的代码打包后,对exports上的属性的赋值将在import(也就是webpack_require)后,另一种使用申明函数语句export的代码打包后,对exports上的属性的赋值将在import(也就是webpack_require)前。
这点细微的区别在执行相互引用的代码时会导致执行结果和你想的不一样,试想一下以下的代码执行过程:
- 在installedModules对象上设置index.js的key,加载index.js并执行
- 遇到import a.js
- 在installedModules对象上设置a.js的key,加载a.js并执行
- 遇到import index.js
- 检查,发现installedModules上已经存在index.js的key,直接读对象上缓存的exports(其实这里可能只在6. exports声明了属性名,并没有赋值)
- 执行exports上的_console函数(如果属性还没有被赋值就会出错)
export的方式会影响以上过程的5、6步骤
解决方式
- 打破文件间的依赖关系的闭环
- 依赖关系闭环的情况下,只使用export function funcName(){}