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 對於對象里面