- CommonJS,SeaJS,KissY
- AMD,requireJS
- ES Module
- Webpack
模块Module
- 一个模块本质是一个模块对象,通过 module.exports对外暴露接口
- exports 只是 module.exports 的一个引用
internal/bootstrap/loaders.js
和internal/modules/cjs/loader
都是 Loader- bootstrap/loaders.js 加载 node Native模块
- cjs/loader 加载自定义的 JS 模块
- node 里面
require('./index')
的依赖查找有后缀名的优先级,分别是 .js > .json > .node- 一个模块的入口文件路径,是在 package.json 的 main 里面定义
- node 里面依赖的模块统一在 node_modules 下面管理
- node 里的 modules 已经不再是严格意义的 CommonJS
exports.router = router
module.exports = router
module.exports = { router: router }
console.log(Module)
{
id: '.',
parent: null,
loaded: false,
exports: { steps: '|..........》' },
filename: '/Users/c/d/node-10.x/demo/race.js',
children: [ Module {
id: '/Users/c/d/node-10.x/demo/step.js',
exports: [Object], parent: [Circular],
loaded: true, children: [], paths: [Array]
filename: '/Users/c/d/node-10.x/demo/step.js'
],
paths: [ '.../node_modules' ]
}
- parent 引用它的父亲模块的信息
- children 引用了别的接口的模块
- 一个模块既可以被引用,也可以引用别人
实现 module
- Node 的模块机制
- 拿到代码后的第一件事就是:对代码包裹一个函数表达式,传入一些变量
function Module(id, parent) {
this.id = id;
this.exports = {};
}
Module.wrap = function(script) {
return Module.wrapper[0] + script + Module.wrapper[1];
};
Module.wrapper = [
'(function (exports, require, module, __filename, __dirname) { ',
'\n});'
];
Module.runMain = function() {
Module._load(process.argv[1], null, true);
};
Module._load = function(request, parent, isMain) {
var module = new Module(filename, parent);
tryModuleLoad(module, filename);
};
function tryModuleLoad(module, filename) {
module.load(filename);
}
Module.prototype.load = function(filename) {
Module._extensions['.js'](this, filename);
};
Module._extensions['.js'] = function(module, filename) {
var content = fs.readFileSync(filename, 'utf8');
module._compile(stripBOM(content), filename);
};
Module.prototype._compile = function(content, filename) {
var wrapper = Module.wrap(content);
var compiledWrapper = vm.runInThisContext(wrapper, {
filename: filename,
lineOffset: 0,
displayErrors: true
});
var require = makeRequireFunction(this);
compiledWrapper.call(this.exports, this.exports, require, this, filename, dirname);
};
Module.prototype.require = function(id) {
return Module._load(id, this, /* isMain */ false);
};
Module._resolveFilename = function(request, parent, isMain, options) {};
- 在 node 命令行模式下,输入:来查看包裹的方法
require('module').wrap.toString()
require('module').wrapper
webpack
// ChunkRenderError.js
const WebpackError = require('./WebpackError')
class ChunkRenderError extends WebpackError {
constructor(chunk, file, error) {
super()
this.name = 'ChunkRenderError'
this.error = error
this.message = error.message
this.details = error.stack
this.file = file
this.chunk = chunk
Error.captureStackTrace(this, this.constructor)
}
}
module.exports = ChunkRenderError
node module
(function (exports, require, module, __filename, __dirname) {
const WebpackError = require('./WebpackError')
class ChunkRenderError extends WebpackError {
constructor(chunk, file, error) {
super()
this.name = 'ChunkRenderError'
this.error = error
this.message = error.message
this.details = error.stack
this.file = file
this.chunk = chunk
Error.captureStackTrace(this, this.constructor)
}
}
module.exports = ChunkRenderError
})
commonJS规范
- CommonJS 的前身是 ServerJS
- CommonJS 是一套模块规范:约定了模块如何定义、加载与执行等
node启动流程
- Node 源码有一坨依赖,大部分是 C/C++ 底层
- Node 启动入口是 node_main.cc 的 main 函数
- 入口函数找到 node.cc 的 3 个 Start,依次调用
- node.cc 的第一个 Start 初始化了 v8,调用第二个 Start
- 第二个 Start 让 v8 准备了引擎实例,调用第三个 Start
- 第三个 Start
- 首先准备了 v8 的上下文 Context
- 其次准备了 Node 的启动环境,对各种需要的变量做整理
- 再把 Node 原生模块和我们的 JS 代码都加载进来运行
- 最后把主持人 libuv 请上场,执行 JS 里的各种任务
- libuv 没活干了,就一层层来退出进程、收拾场地,退出程序
webpack编译的 commonJS规范
console.log('this is module');
exports.geekbang = { 'hello': 'haha' }
exports.tencent = function () {
console.log('good')
}
module.exports = function () {
console.log('hello geekbang');
}
index.js webpack编译后的结果
/******/ (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, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __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
/******/ __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 = "./index.js");
/******/ })
/************************************************************************/
/******/ ({
/***/ "./index.js":
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
console.log('start require');
__webpack_require__(/*! ./lib */ "./lib.js")
console.log('end require');
/***/ }),
/***/ "./lib.js":
/*! no static exports found */
/***/ (function(module, exports) {
console.log('this is module');
exports.geekbang = { 'hello': 'haha' }
exports.tencent = function () {
console.log('good')
}
module.exports = function () {
console.log('hello geekbang');
}
})
});