研究了一下CommonJS规范,用webpack打包之后,得到源码进行分析,只要分析webpack_require与打包的过程。webpack打包的命令(webpack --devtool none --mode development --target node ./src/index.js --output-path='./CommonJS'
)
- webpack的用法自行百度,我只展示打包后的代码(把注释删掉了)
源码
// core.js
console.log('core js')
exports.name = 'Jack'
exports.old = '18'
exports.play = function() {
console.log('play game')
}
module.exports = function() {
console.log('module')
}
// index.js
const Core = require('./core.js')
console.log(Core.name)
console.log(Core.old)
console.log(Core.paly)
console.log(Core)
(function (modules) {
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, { enumerable: true, get: getter });
}
};
__webpack_require__.r = function (exports) {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
__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;
};
__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 = "./src/index.js");
})({
"./src/core.js": (function (module, exports) {
console.log('core js')
exports.name = 'Jack'
exports.old = '18'
exports.play = function () {
console.log('play game')
}
module.exports = function () {
console.log('module')
}
}),
"./src/index.js": (function (module, exports, __webpack_require__) {
const Core = __webpack_require__(/*! ./core.js */ "./src/core.js")
console.log(Core.name)
console.log(Core.old)
console.log(Core.paly)
console.log(Core)
})
});
分析一下结构
1、 './src/core.js'与'./src/index.js'是两个脚本路径,每个参数指向一个函数,每个模块相当于一个作用域,js使用函数创建作用域。
2、打包之后就是个自执行函数,参数就是每个模块的对应的函数
(function (modules) {})({模块1, 模块2,...})
3、installedModules 储存每个模块初始化,判断是否已经初始化,在调用入口文件
4、可以看出来./src/core.js
中module.exports
是被重新赋值,而./src/core.js
内部的module.exports
内被保留在函数内部
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {} // 重新赋值
};
return module.exports// 返回结果
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
关于webpack打包的原理 AST preset-env loader plugins entry output等有兴趣可以了解一下,我只是简单介绍CommonJS规范引入nodeJS是怎么引用的,以及exports的作用域