- 开始之前,我们先在本地新建一个目录,然后
npm init -y
复制代码
生成一个包含package.json的目录结构,然后在目录下新建一个index.js作为入口js文件。新建一个module目录包含index.js及lib.js文件。
之后的目录结构如下:
- 首先我们需要知道的是common.js规范的require是会引入js并 执行
下面是个简单的demo:
module/index.js文件如下:
console.log('start');
require('./lib');
console.log('end');
复制代码
module/lib.js文件如下:
console.log('lib');
复制代码
然后在控制台执行 node module/index.js 结果如下:
显然lib.js被引入并被执行了。
- 其次是require函数是有返回值的
我们修改一下上面的代码如下
console.log('start');
const res = require('./lib');
console.log('libres', res);
console.log('end');
复制代码
再重新执行代码得到的输出结果为:
可以看到reqiure(‘./lib.)得到的返回值是一个空对象。
下面问题就来了,如果我希望得到非空的返回对象应该怎么做?
- exports
node.js提供了输出关键字 exports 。
我们如下修改下lib.js代码
console.log('lib');
exports.lib = 'lib'
复制代码
再次用node执行module目录下面的index.js。
可以看到require的返回res是一个对象,包含了lib属性。
当然我们还可以exports输出更多的其他类型的变量。
console.log('lib');
exports.lib = 'lib'
exports.obj = { a: 1, b: 2 };
exports.fun = (a) => console.log(a)
复制代码
控制台打印的结果如下:
那么exports输出的是对象还是是对象的引用呢?即reqiure得到的对象修改会影响对象的本身吗?测试一下,如下修改module目录下的lib.js和index.js。
index.js
console.log('start');
const res = require('./lib');
res.obj2 = { c: 1, d: 2 }
console.log('end');
复制代码
lib.js
console.log('lib');
exports.lib = 'lib'
exports.obj = { a: 1, b: 2 };
exports.fun = (a) => console.log(a)
setTimeout(() => { console.log('lib-exports', exports), 1000 })
复制代码
node module/index.js控制台输出如下:
可以看到exports和require之间传递的是对象的引用。require对象的修改会影响exports对象。
- module.exports
如果不想导出的始终是个对象。那么可以使用module.exports导出。
lib.js
console.log('lib');
exports.lib = 'lib'
exports.obj = { a: 1, b: 2 };
exports.fun = (a) => console.log(a);
module.exports = () => { console.log('Node.js') };
setTimeout(() => { console.log('lib-exports', exports), 1000 })
复制代码
module/index.js
module/index.js
console.log('start');
const res = require('./lib');
console.log('libres', res);
res.obj2 = { c: 1, d: 2 }
console.log('end');
复制代码
打印结果
可以看到res打印的结果不再是个object而是一个function。
而同时index.js里面对res添加的属性obj2也不会添加到lib里面的exports对象上。
在浏览器端,webpack打包代码时是支持require命令的。那么看下webpack是如何实现require的。
首先安装webpack和webpack-cli。
npm install webpack webpack-cli -D
复制代码
此时的package.json文件如下
{
"name": "nodejs-start-from-0",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {},
"devDependencies": {
"webpack": "^5.37.1",
"webpack-cli": "^4.7.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
复制代码
注意安装的webpack和webpack-cli版本,此版本应该是2021年5月份左右最新的版本
然后执行如下命令:
webpack ./index.js --devtool source-map --mode development --target node
复制代码
输出结果在dist目录下的main.js文件中
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./lib.js":
/*!****************!*\
!*** ./lib.js ***!
\****************/
/***/ ((module, exports) => {
console.log('lib');
exports.lib = 'lib'
exports.obj = { a: 1, b: 2 };
exports.fun = (a) => console.log(a);
module.exports = () => { console.log('Node.js') };
setTimeout(() => { console.log('lib-exports', exports), 1000 })
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
/*!******************!*\
!*** ./index.js ***!
\******************/
console.log('start');
const res = __webpack_require__(/*! ./lib */ "./lib.js");
console.log('libres', res);
res.obj2 = { c: 1, d: 2 }
console.log('end');
})();
/******/ })()
;
//# sourceMappingURL=main.js.map
复制代码
可以看到lib.js被放在了__webpack_modules__对象中,我们写在lib.js里面的代码被放在key为’lib.js’的属性里面。
然后在index.js里面通过执行
const res = __webpack_require__(/*! ./lib */ "./lib.js");
复制代码
导入的lib.js。
下面看看__webpack_require__的实现
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
复制代码
从main.js里面拷出来
前面是判断缓存。后面__webpack_modules__[moduleId](module, module.exports, webpack_require);这一句其实就是执行的lib.js。同时传入了module和module.exports。
在lib.js执行的部分可以看到:
module.exports = () => { console.log('Node.js') };
复制代码
exports最终被module.exports覆盖成了这个。所以输出的是module.exports的这个function。
以上。