前言
我们都知道,浏览器是无法识别 commonjs 规范的模块和 es6 module 的.将这些规范的模块转化为浏览器认识的语句就是 webpack 做的最基本事情,webpack 本身维护了一套模块系统,这套模块系统兼容了所有前端历史进程下的模块规范,包括 amd commonjs es6 等.当然 babel 也具有将 es6 模块转化的能力 (parcel 我不想提你),但是由于 webpack 具有 tree-shaking 的功能,比起 babel 来更加具有优势.所以一般 babel 配置里都会禁止掉 babel 的 module 功能.(["es2015", {"modules": false}]).
commonjs 规范
项目结构:
打包结果:
app.js(entry):
var c = require('./c')
console.log(c)
c.js(entry):
let c1 = 'c1'
let c2 = 'c2'
module.exports = {
c1,
c2,
}
解析:
(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["app"] = factory();
else root["app"] = factory();
})(typeof self !== 'undefined' ? self: this,
function() {
return (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__)
__webpack_require__.m = modules;
// expose the module cache
__webpack_require__.c = installedModules;
// define getter function for harmony exports
__webpack_require__.d = function(exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
// getDefaultExport function for compatibility with non-harmony modules
__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 = 0);
})
/************************************************************************/
([
/* 0 */
(function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
}),
/* 1 */
(function(module, exports, __webpack_require__) {
"use strict";
var c = __webpack_require__(2);
console.log(c);
module.exports = {
a: '我是a'
};
}),
/* 2 */
(function(module, exports) {
var c1 = 'c1';
var c2 = 'c2';
module.exports = {
c1: c1,
c2: c2
};
})]);
});
打包生成的是个立即执行函数,简化来写就是
})(typeof self !== 'undefined' ? self : this, function() {解析完的模块部分})
(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["app"] = factory();
else
root["app"] = factory();
可以看到模块部分被作为 factory 参数传入了 webpackUniversalModuleDefinition 中,如果检测到 module.exports 有定义,那么模块赋值给 module.exports;如果检测到 amd 的模块系统有定义,赋值给 define 的模块系统;最后如果上述模块系统都未检测到,赋值给 webpack.output.library 定义的全局变量.浏览器可以通过 window.app 拿到解析好的模块.
下面看模块解析部分
解析模块的方法
factory:
function(){
return (function(modules){
})([function(){模块1},function(){模块1},...])
}
factory 方法最后 return 出去的就是 webpack entry 的 js:app.js 暴露的值.
解析模块的方法:
定义了 installedModules ,这个变量被用来缓存已加载的模块.
var installedModules = {};
function __webpack_require__(moduleId) {
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
__webpack_require__.m = modules;
__webpack_require__.c = installedModules;
__webpack_require__.d = function(exports, name, getter) {
if(!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
__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;
};
__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
__webpack_require__.p = "";
return __webpack_require__(__webpack_require__.s = 0);
定义了__webpack_require__ 这个函数,函数参数为模块的 id.这个函数用来实现模块的 require.
webpack_require 函数首先会检查是否缓存了已加载的模块,如果有则直接返回缓存模块的 exports.
如果没有缓存,也就是第一次加载,则首先初始化模块,并将模块进行缓存.初始化 ->
然后调用模块函数,也就是前面 webpack 对我们的模块的包装函数,将 module,module.exports 和__webpack_require__作为参数传入.注意这里做了一个动态绑定,将模块函数的调用对象绑定为 module.exports,这是为了保证在模块中的 this 指向当前模块.
{
i: moduleId,
l: false,
exports: {}
}
调用完成后,模块标记为已加载.
返回模块 exports 的内容.
利用前面定义的__webpack_require__ 函数,require 第 0 个模块,也就是入口模块.
https://segmentfault.com/a/1190000010349749
再看编号为 0 的模块
直接让 expoprts = webpack_require(1), 此时
function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
}
installedModules[0] = {i: 1, l: true, exports: __webpack_require__(1)}
再看编号为 1 的模块
直接让 module.exports = {a:'我是 a', 此时:
function(module, exports, __webpack_require__) {
"use strict";
var c = __webpack_require__(2);
console.log(c);
module.exports = {
a: '我是a'
}
}
installedModules[1] = {i: 1, l: true, exports: {a:'我是a'}
再看编号为 2 的模块
直接让 module.exports = {c1:'c1',c2:'c2', 因为 2 模块没有 require 其他模块,因此没有接收到__webpack_require__.此时:
function(module, exports) {
var c1 = 'c1';
var c2 = 'c2';
module.exports = {
c1: c1,
c2: c2
};
}
installedModules[2] = {i: 2, l: true, exports: {c1: 'c1',c2: 'c2'}
结束,现在 installedModules 的结果是
factory 函数要 return 的是
{
0: {i: 0, l: true, exports: {a:'我是a'}
1: {i: 1, l: true, exports: {a:'我是a'}
2: {i: 2, l: true, exports: {c1: 'c1',c2: 'c2'}
}
return __webpack_require__(__webpack_require__.s = 0);
因此入口模块:app.js 的返回结果是 {a:'我是 a',同时 window.app = {a:'我是 a'
结论:webpack 使用自定义的__webpack_require__函数实现了 commonjs require 的功能,并且使用 installedModules 变量保存了 module.exports 的模块输出.完成了对 commonjs 模块的转化.
webpack 模块化原理 - commonjs
es6 module
项目结构:
打包结果:
app.js(entry):
import c,{c1,c2} from './c';
console.log(c,c1,c2)
export default '我是a';
export let a = '我是aa';
c.js:
import b from './b'
console.log(b)
export let c1 = '我是c111'
export let c2 = '我是c222'
export default '我是c';
b.js:
export default 'bbb';
与 commonjs 部分基本相同,只有模块部分解析的不同
模块 0 与上述相同. 下面看编号为 1 的模块 (app.js)
结论:
function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
__webpack_require__.d(__webpack_exports__, "aaaa", function() { return aaaa; });
var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(2);
console.log(__WEBPACK_IMPORTED_MODULE_0__c__["c" /* default */], __WEBPACK_IMPORTED_MODULE_0__c__["a" /* c1 */], __WEBPACK_IMPORTED_MODULE_0__c__["b" /* c2 */]);
__webpack_exports__["default"] = ('我是a');
var aaaa = '我是aaaa';
因为 app.js 是 es6 的模块,所以 webpack 对该模块增加了__esModule 属性 (true).
由于 es6 模块有 export default 的功能,因此 webpack 把本模块暴露出的 default 属性赋给了 module.exports 的 default 属性.
注意:只有该模块是入口模块,并且是 es6 模块时,该模块 export default 的值才会被转为 module.exports 的 default 属性.
export 暴露的变量被转化成了
__webpack_require__.d(__webpack_exports__, "aaaa", function() { return aaaa; });
,可以发现 export 暴露的变量名 aaaa 被原本的输出了.
import 语句被转成了
var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(2);
,可以看出 import c,{c1,c2} 的语句 webpack 没有处理,而是直接通过新变量__WEBPACK_IMPORTED_MODULE_0__c__接收了 c 模块的 exports 对象.所有用到 c,c1,c2 的地方都到 __WEBPACK_IMPORTED_MODULE_0__c__上取.
此时:
再看模块 2(c.js):
installedModules[1] = {
i: 1,
l: true,
exports: {
default:'我是a',
aaaa:"我是aaaa",
__esModule:true
}
}
结论:
function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.d(__webpack_exports__, "a", function() { return c1; });
__webpack_require__.d(__webpack_exports__, "b", function() { return c2; });
var __WEBPACK_IMPORTED_MODULE_0__b__ = __webpack_require__(3);
console.log(__WEBPACK_IMPORTED_MODULE_0__b__["a" /* default */]);
var c1 = '我是c111';
var c2 = '我是c222';
__webpack_exports__["c"] = ('我是c');
}
export 暴露的变量被转化成了
__webpack_require__.d(__webpack_exports__, "a", function() { return c1; });
,可以发现与入口的 es6 模块不同的是:export 暴露的变量名被随机改变了.default 被转为了 c, c1 被转为了 a,c2 被转为了 b.因此当入口模块 (app.js)import 了本模块并使用 default,c1,c2 属性时,相应的被 webpack 对应改为了 c,a,b(见模块 1 调用的地方)
与入口模块不同的是,本模块的 export default 被转化成了
__webpack_exports__["c"] = ('我是c');
,并没有被转化为 default 属性,而是同样被转成了一个随机属性名.
此时:
再看模块 3
installedModules[2] = {
i: 2,
l: true,
exports: {
a: "我是c111",
b: "我是c222",
c: "我是c"
}
}
结论:
function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_exports__["a"] = ('bbb');
}
模块 3 的 export default 被转化成了__webpack_exports__["a"] = ('bbb'); default 被随机改为了 a,然后调用到地方同样要使用 ['a'] 取值.
综上, installedModules:
结论:
{
0: {i: 0, l: true, exports: {a:'我是a',_esModule:true}}
1: {i: 1, l: true, exports: {a:'我是a',_esModule:true}}
2: {i: 2, l: true, exports: {a:"我是c111", b:"我是c222",c: "我是c"}
3: {i: 3, l: true, exports: {a:"bbb"}
}
入口模块如果为 es6 模块的话,会被添加__esModule ,值为 true,表明这是一个 es 模块.而被入口的 es6 模块引用的其他 es6 模块不会被添加__esModule 属性.
es6 模块作为入口模块时,export 出去的 default 属性和其他属性名都会被原样保留.default 属性通过
__webpack_exports__["default"] = ...
的方式导出,其他属性通过
__webpack_require__.d(__webpack_exports__, "aaaa", function() { return aaaa; });
方式导出.
es6 模块不是入口模块而是被其他 es6 模块引用时,export 出去的 default 属性和其他属性名都会被随机赋予新的属性名称,例如
export default '我是c';
转为了
__webpack_exports__["c"] = ('我是c');
.default 属性同样通过
__webpack_exports__["c"] = ...
的方式导出,其他属性同样通过
__webpack_require__.d(__webpack_exports__, "b", function() { return c2; });
的方式导出.
es6 模块的 import 语法被转化成了
commonjs 模块与 es6 模块混用
var __WEBPACK_IMPORTED_MODULE_0__b__ = __webpack_require__(3);
.
情景一:es6 引用 commonjs
项目结构:
打包结果:
app.js(entry):
import c,{c1,c2} from './c';
console.log(c,c1,c2)
export default '我是a';
export let aaaa = '我是aaaa';
c.js:
let c1 = 'c1'
let c2 = 'c2'
module.exports = {
c1,
c2,
}
入口模块 (app.js) 为 es6 模块,引用的模块 (c.js) 是 commonjs 模块.
(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["app"] = factory();
else
root["app"] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return (function(modules) { // webpackBootstrap
var installedModules = {};
function __webpack_require__(moduleId) {
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
__webpack_require__.m = modules;
__webpack_require__.c = installedModules;
__webpack_require__.d = function(exports, name, getter) {
if(!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
__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;
};
__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
__webpack_require__.p = "";
return __webpack_require__(__webpack_require__.s = 0);
})
/************************************************************************/
([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "aaaa", function() { return aaaa; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(2);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__c___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__c__);
console.log(__WEBPACK_IMPORTED_MODULE_0__c___default.a, __WEBPACK_IMPORTED_MODULE_0__c__["c1"], __WEBPACK_IMPORTED_MODULE_0__c__["c2"]);
/* harmony default export */ __webpack_exports__["default"] = ('我是a');
var aaaa = '我是aaaa';
/***/ }),
/* 2 */
/***/ (function(module, exports) {
var c1 = 'c1';
var c2 = 'c2';
module.exports = {
c1: c1,
c2: c2
};
/***/ })
/******/ ]);
});
模块 0 依旧不变,看模块 1(app.js) 的打包情况
可以发现模块 1 引用 commonjs 模块的地方打包结果发生了改变.
function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
__webpack_require__.d(__webpack_exports__, "aaaa", function() { return aaaa; });
var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(2);
var __WEBPACK_IMPORTED_MODULE_0__c___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__c__);
console.log(__WEBPACK_IMPORTED_MODULE_0__c___default.a, __WEBPACK_IMPORTED_MODULE_0__c__["c1"], __WEBPACK_IMPORTED_MODULE_0__c__["c2"]);
__webpack_exports__["default"] = ('我是a');
var aaaa = '我是aaaa';
}
当发现引用模块是 commonjs 模块时,在调用__webpack_require__() 之后,还会调用__webpack_require__.n,
var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(2);
// 与import es6模块相比增加了以下部分
var __WEBPACK_IMPORTED_MODULE_0__c___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__c__);
本方法的作用是:如果传入模块是 es6 模块转化成的 commonjs 模块,即__esModule=true,那么返回的是该模块的 default 属性的值,如果传入的模块原来就是 commonjs 模块,返回模块本身,并且令该模块的 a 属性 = 模块本身.结果就是生成了两个变量__WEBPACK_IMPORTED_MODULE_0__c__和__WEBPACK_IMPORTED_MODULE_0__c___default.
__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;
};
结论:
__WEBPACK_IMPORTED_MODULE_0__c__={
c1,
c2,
}
__WEBPACK_IMPORTED_MODULE_0__c___default = function getModuleExports(){return module}
__WEBPACK_IMPORTED_MODULE_0__c___default.a = module
es6 模块引用 commonjs 模块时,因为 import name from '..'想取的是模块的 default 属性,而 commonjs 模块没有暴露 default 的方法,所以 webpack 将整个模块作为了 default 属性的值输出.
再看模块 2:
原样输出
function(module, __webpack_exports__) {
"use strict";
var c1 = 'c1';
var c2 = 'c2';
module.exports = {
c1: c1,
c2: c2
};
}
综上:
es6 调用 commonjs 模块,import 默认值的情况会特殊处理
被引用的 commonjs 模块会原样输出.
情景二:commonjs 调用 es6 模块
项目结构:
打包结果:
app.js(entry):
var b = require('./b')
var c = require('./c')
console.log(b.default)
console.log(c)
module.exports = {
a:'我是a'
}
c.js:
import b from './b'
console.log(b)
export let c1 = '我是c111'
export let c2 = '我是c222'
export default '我是c';
入口模块 (app.js) 为 commonjs 模块,引用的模块 (b.js,c.js) 是 es6 模块.
(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["app"] = factory();
else
root["app"] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return (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__)
__webpack_require__.m = modules;
// expose the module cache
__webpack_require__.c = installedModules;
// define getter function for harmony exports
__webpack_require__.d = function(exports, name, getter) {
if(!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
// getDefaultExport function for compatibility with non-harmony modules
__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 = 0);
})
/************************************************************************/
([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var b = __webpack_require__(2);
var c = __webpack_require__(3);
console.log(b.default);
console.log(c);
module.exports = {
a: '我是a'
};
/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
__webpack_exports__["default"] = ('bbb');
/***/ }),
/* 3 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
__webpack_require__.d(__webpack_exports__, "c1", function() { return c1; });
__webpack_require__.d(__webpack_exports__, "c2", function() { return c2; });
var __WEBPACK_IMPORTED_MODULE_0__b__ = __webpack_require__(0);
console.log(__WEBPACK_IMPORTED_MODULE_0__b__["default"]);
var c1 = '我是c111';
var c2 = '我是c222';
/***/ })
/******/ ]);
});
模块 0 依旧不变,看模块 1(app.js) 的打包情况
仅仅是使用__webpack_require__方法替代了原来的 require 方法
function(module, exports, __webpack_require__) {
"use strict";
var b = __webpack_require__(2);
var c = __webpack_require__(3);
console.log(b.default);
console.log(c);
module.exports = {
a: '我是a'
}
}
再看模块 2(b.js) 和模块 3(c.js)
结论:
b.js
function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
__webpack_exports__["default"] = ('bbb');
}
c.js
function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
__webpack_require__.d(__webpack_exports__, "c1", function() { return c1; });
__webpack_require__.d(__webpack_exports__, "c2", function() { return c2; });
var c1 = '我是c111';
var c2 = '我是c222';
__webpack_exports__["default"] = ('我是c');
}
可以发现 commonjs 模块引用 es6 模块,被引用的 es6 模块会被增加__esModule 属性 (true)
export 语法被转为了
export default 语句被转为了
__webpack_require__.d(__webpack_exports__, "c1", function() { return c1; });
.
__webpack_exports__["default"] = ('我是c');
使用 import b from './b'调用 es6 模块,如果需要调用 b 的默认值,需要用
__WEBPACK_IMPORTED_MODULE_0__b__["default"];
使用 import b from './b'调用 commonjs 模块,需要以下方式:
综上:
var __WEBPACK_IMPORTED_MODULE_0__b__ = __webpack_require__(0);
var __WEBPACK_IMPORTED_MODULE_0__b___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__b__);
console.log(__WEBPACK_IMPORTED_MODULE_0__b___default.a);
commonjs 模块被打包时,require 部分会被__webpack_require__函数替代,其他部分原样输出.
commonjs 模块被 import 时,由于 commonjs 模块没有暴露默认值的功能,所以 import 默认值的语法会被解析成:
即使在 es6 模块中使用 require() 引用,不管 require 的是 es6 模块还是 commonjs 模块,都只会被简单的解析成
// import c from './c'被解析成:
var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(2);
var __WEBPACK_IMPORTED_MODULE_0__c___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__c__);
// 使用c时被解析成:
console.log(__WEBPACK_IMPORTED_MODULE_0__c___default.a)
var c = __webpack_require__(2);
.可以认为 commonjs 规范的 require 会被__webpack_require__直接替换.
es6 模块被 require 时 (不论 require 语句出现在 commonjs 还是 es6 的模块里),es6 模块都会被添加__esModule=true.es6 模块被 import 时则都不会添加__esModule 属性.es6 模块被当做入口模块时,也会被添加__esModule=true,可以认为做为入口模块时的命运就是会被打包成 commonjs 模块暴露出去,此时就需要一个变量来标识我以前是 es6 模块,只不过被强行变成了 commonjs 模块,一经打包完成,本模块再被引用时将不会触发 tree-shaking 功能.
es6 模块被直接 import 时,会触发 webpack 的 tree-shaking 功能,可以认为 webpack 只有对 es6 模块进行静态解析后才能调用 tree-shaking.
es6 模块被打包时,export 语句被解析成:
__webpack_require__.d(__webpack_exports__, "a", function() { return c1; });
export default 语句被解析成:
__webpack_exports__["c"] = ('我是c');
当然所有的属性名都是被随机赋予了新的名称,一般是按 a,b,c,d... 的顺序. 例外情况:如果 es6 模块被当做入口模块,export 和 export default 语句暴露的属性名会保留,例如:
es6 模块被 import 时,import 语句会被解析成:
__webpack_require__.d(__webpack_exports__, "aaaa", function() { return aaaa; });
__webpack_exports__["default"] = ('我是a');
var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(2);
不会出现__webpack_require__.n 的使用. 此时调用 es6 模块暴露出的所有属性都通过__WEBPACK_IMPORTED_MODULE_0__c__['随机属性名'] 的方式,例如:
console.log(__WEBPACK_IMPORTED_MODULE_0__c__["c" /* default */])
es6 模块被 require 时,简单的多:
var c = __webpack_require__(2);
调用任何属性都通过 c 直接调用.
简述:
import->__webpack_require__
require->__webpack_require__ 和 __webpack_require__.n
module.exports->不变
export - >__webpack_require__.d export
default - >__webpack_exports__[".."]
webpack 模块化原理 - ES module import,require,export,module.exports 混合使用详解
项目代码
根据以上思路,如果实现了文件按路径加载,就能写出一个简单的模块化工具了.
来源: https://juejin.im/post/5a5ef47c6fb9a01cb13929f5