1. 首先配置一个简单的webpack项目
1 const path = require('path') 2 const htmlWebpackPlugin = require('html-webpack-plugin') 3 4 module.exports = { 5 entry: { 6 app: './src/js/index.js' 7 }, 8 output: { 9 path: path.resolve(__dirname, '../dist'), 10 filename: 'js/[name].bundle.js' 11 }, 12 module: { 13 rules: [ 14 { 15 test: /\.js$/, 16 exclude: '/node_modules/', 17 loader: 'babel-loader' 18 } 19 ] 20 }, 21 plugins: [ 22 new htmlWebpackPlugin({ 23 filename: 'index.html', 24 template: './src/index.html' 25 }) 26 ] 27 }
/* index.js */ import * as ejs from './ejs' import cjs from './cjs' const requireCjs = require('./cjs') const requireEjs = require('./ejs') console.log('cjs: ', cjs) console.log('ejs: ', ejs) console.log('requireCjs: ', requireCjs) console.log('requireEjs: ', requireEjs) /* ejs.js ecmaScript */ const a = 12 const b = { a: 1, b: 2 } function fn1 (a) { console.log('fn1 in ejs: ', a) } export default fn1 export { a, b } /* cjs.js -- commonjs */ const a = 1 const b = 2 function fn1 (a) { console.log('fn1 in cjs: ', a) } // module.exports = { // a, b, fn1 // } exports.a = a
2. 通过package.json 里面配置webpack 命令打包,从生成的文件可以看到,webpack 打包之后生成的是一个立即执行函数:
/* 生成一个立即执行函数,函数的参数是一个对象 { key: 文件路径, value: 打包之后的函数,参数为module跟exports,类似 commonjs } */ (function(modules) { // webpackBootstrap // The module cache // 缓存已经加载的模块,避免重复加载 var installedModules = {}; // The require function // 主要功能,用于加载、缓存模块 function __webpack_require__(moduleId) { // Check if module is in cache if(installedModules[moduleId]) { return installedModules[moduleId].exports; } // Create a new module (and put it into the cache) var module = installedModules[moduleId] = { i: moduleId, l: false, exports: {} }; // Execute the module function modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // Flag the module as loaded module.l = true; // Return the exports of the module return module.exports; } // expose the modules object (__webpack_modules__) // 将modules数组参数挂载在属性m上 __webpack_require__.m = modules; // expose the module cache // 将缓存模块挂载在属性c上 __webpack_require__.c = installedModules; // define getter function for harmony exports // 将js模块里面暴露的属性挂载在 module.exports 对象上,主要是给es模块用的 __webpack_require__.d = function(exports, name, getter) { if(!__webpack_require__.o(exports, name)) { Object.defineProperty(exports, name, { enumerable: true, get: getter }); } }; // define __esModule on exports // es模块定义 __esModule 属性,用来标志 es模块 还是 commonjs模块 __webpack_require__.r = function(exports) { if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); }; // create a fake namespace object // mode & 1: value is a module id, require it // mode & 2: merge all properties of value into the ns // mode & 4: return value when already ns object // mode & 8|1: behave like require __webpack_require__.t = function(value, mode) { if(mode & 1) value = __webpack_require__(value); if(mode & 8) return value; if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; var ns = Object.create(null); __webpack_require__.r(ns); Object.defineProperty(ns, 'default', { enumerable: true, value: value }); if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); return ns; }; // getDefaultExport function for compatibility with non-harmony modules // 获取默认导出,es模块是根据 __webpack_require__.d 定义的属性 __esModule 判断,如果true 则返回 export.default 属性值 // 如果 __esModule 不为true 则返回当前模块 __webpack_require__.n = function(module) { var getter = module && module.__esModule ? function getDefault() { return module['default']; } : function getModuleExports() { return module; }; __webpack_require__.d(getter, 'a', getter); return getter; }; // Object.prototype.hasOwnProperty.call __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; // __webpack_public_path__ __webpack_require__.p = ""; // Load entry module and return exports // 加载主模块,然后再在主模块里面加载对应的依赖模块 return __webpack_require__(__webpack_require__.s = "./src/js/index.js"); }) /************************************************************************/ ({ /***/ "./src/js/cjs.js": /*!***********************!*\ !*** ./src/js/cjs.js ***! \***********************/ /*! no static exports found */ /***/ (function(module, exports) { eval("const a = 1;\nconst b = 2;\n\nfunction fn1(a) {\n console.log('fn1 in cjs: ', a);\n} // module.exports = {\n// a, b, fn1\n// }\n\n\nexports.a = a;\n\n//# sourceURL=webpack:///./src/js/cjs.js?"); /***/ }), /***/ "./src/js/ejs.js": /*!***********************!*\ !*** ./src/js/ejs.js ***! \***********************/ /*! exports provided: default, a, b */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return a; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return b; });\nconst a = 12;\nconst b = {\n a: 1,\n b: 2\n};\n\nfunction fn1(a) {\n console.log('fn1 in ejs: ', a);\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (fn1);\n\n\n//# sourceURL=webpack:///./src/js/ejs.js?"); /***/ }), /***/ "./src/js/index.js": /*!*************************!*\ !*** ./src/js/index.js ***! \*************************/ /*! no exports provided */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ejs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ejs */ \"./src/js/ejs.js\");\n/* harmony import */ var _cjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./cjs */ \"./src/js/cjs.js\");\n/* harmony import */ var _cjs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_cjs__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\nconst requireCjs = __webpack_require__(/*! ./cjs */ \"./src/js/cjs.js\");\n\nconst requireEjs = __webpack_require__(/*! ./ejs */ \"./src/js/ejs.js\");\n\nconsole.log('cjs: ', _cjs__WEBPACK_IMPORTED_MODULE_1___default.a);\nconsole.log('ejs: ', _ejs__WEBPACK_IMPORTED_MODULE_0__);\nconsole.log('requireCjs: ', requireCjs);\nconsole.log('requireEjs: ', requireEjs);\n\n//# sourceURL=webpack:///./src/js/index.js?"); /***/ }) });
3. 仔细看下生成之后的 index.js:
/* 每个文件打包之后生成的模块,默认都会传入 module, module.exports, __webpack_require__ 这三个参数 这三个参数是在 modules[moduleId].call(module.exports, module, module.exports, __webpack_require__) 这里传递的 */ /* 通过 __webpack_require__.r 标志该文件为 ECMAScript 模块*/ __webpack_require__.r(__webpack_exports__); /* 通过 __webpack_require__ 引入模块对应的模块 */ /* harmony import */ var _ejs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ejs */ "./src/js/ejs.js"); /* harmony import */ var _cjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./cjs */ "./src/js/cjs.js"); /* 获取模块的默认导出,根据 module.__esModule 兼容 ECMAScript 跟 CommonJs*/ /* harmony import */ var _cjs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_cjs__WEBPACK_IMPORTED_MODULE_1__); const requireCjs = __webpack_require__(/*! ./cjs */ "./src/js/cjs.js"); const requireEjs = __webpack_require__(/*! ./ejs */ "./src/js/ejs.js"); console.log('cjs: ', _cjs__WEBPACK_IMPORTED_MODULE_1__); console.log('ejs: ', _ejs__WEBPACK_IMPORTED_MODULE_0__); console.log('requireCjs: ', requireCjs); console.log('requireEjs: ', requireEjs);
4. 以上可以看出,webpack 对于 CommonJS 跟 ECMAScript 打包是做了兼容的,对于模块暴露的属性,都是统一放在 module.exports 这个属性里面,如果是 ECMAScript 的 export default, 则会放在 module.exports['default'] 这个属性里面,其他的如 export 或者 CommonJs 的 exports, module.exports 都是放在 module.exports 对于对象里面