摘要:如何让运行模块文件,及其原理最新版的支持最新版几乎所有特性,但有一个特性却一直到现在都还没有支持,那就是从开始定义的模块化机制。便是使用这种方式达到运行模块文件的目的的。
如何让 node 运行 es6 模块文件,及其原理
最新版的 node 支持最新版 ECMAScript 几乎所有特性,但有一个特性却一直到现在都还没有支持,那就是从 ES2015 开始定义的模块化机制。而现在我们很多项目都是用 es6 的模块化规范来写代码的,包括 node 项目,所以,node 不能运行 es6 模块文件就会很不便。
让 node 运行 es6 模块文件的方式有两种:
转码 es6 模块为 commonjs 模块
hook node 的 require 机制,直接让 node 的 require 加载 import/export
1. 转码 es6 模块为 commonjs 模块因为 node 支持几乎所有除 import/export 外的语法,所以我们只需要将 import/export 转码成 require/exports,而不需要转码其他语法。
比如下面的项目:
- package.json - src/ - index.js - print.js - ...
# package.json { "main": "lib/index.js" # 由工具转码 src 目录下源文件到 lib 目录下 } # src/index.js import print from "./print"; print("index"); export default print; # src/print.js export default str => { console.log("print: " + str); };
因为 src 目录下的源文件都是 es6 模块化规范的,node 并不能直接运行,所以需要转码成 commonjs 规范的代码。
这个过程有两个方案:
如果不会多带带使用 src 目录下的某个文件,而仅仅是以 src/index.js 为入口文件使用,可以把 src 目录下的文件打包成一个文件到 lib/index.js:这种方式推荐使用工具 rollup
如果需要多带带使用 src 目录下的文件,那就需要把 src 目录下的文件一对一的转码到 lib 目录下:这种方式推荐使用工具 gulp + babel
1.1 用 rollup 把 src 目录下的文件打包成一个文件到 lib/index.js相关文件:
# rollup.config.js export default { input: "src/index.js", output: { file: "lib/index.js", format: "cjs", }, }; # package.json { "scripts": { "build": "rollup -c" }, "devDependencies": { "rollup": "^0.66.4" } }
运行命令:
npm run build
结果:
# lib/index.js "use strict"; var print = str => { console.log("print: " + str); }; print("index"); module.exports = print;1.2 用 gulp + babel 把 src 目录下的文件一对一的转码到 lib 目录下
相关文件:
# build.js const gulp = require("gulp"); const babel = require("gulp-babel"); gulp.task("babel", () => gulp.src("src/**/*.js") .pipe(babel({ plugins: ["@babel/plugin-transform-modules-commonjs"] })) .pipe(gulp.dest("lib")) ); gulp.series("babel")(); # package.json { "scripts": { "build": "node build.js" }, "devDependencies": { "@babel/core": "^7.1.2", "@babel/plugin-transform-modules-commonjs": "^7.2.0", "gulp": "^4.0.0", "gulp-babel": "^8.0.0" } }
运行命令:
npm run build
结果:
# lib/index.js "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _print = _interopRequireDefault(require("./print")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } (0, _print.default)("index"); var _default = _print.default; exports.default = _default; # lib/print.js "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _default = str => { console.log("print: " + str); }; exports.default = _default;2. hook node 的 require 机制,直接加载 import/export
这种机制一般是通过对 node 的 require 机制进行 hook,劫持 require 抓取的源文件代码,把源代码转码成 commonjs 规范之后,再传送给 require 机制原本的代码流中。
pirates 之类的第三方 npm 包提供了这种添加 hook 的功能。
babel-register 便是使用这种方式达到 node 运行 es6 模块文件的目的的。
2.1 使用 babel-register 直接运行 es6 模块文件示例目录:
- package.json - src/ - entry.js # 这里多了一个入口文件,专门用于注册 babel-register - index.js - print.js - ...
相关文件:
# package.json { "scripts": { "run": "node src/entry.js" }, "devDependencies": { "@babel/core": "^7.1.2", "@babel/plugin-transform-modules-commonjs": "^7.2.0", "@babel/register": "^7.0.0" } } # src/entry.js # 入口文件必须使用 commonjs 规范来写,因为还没有注册 hook require("@babel/register")({ plugins: ["@babel/plugin-transform-modules-commonjs"] }); require("./index"); # src/index.js import print from "./print"; print("index"); # src/print.js export default str => { console.log("print: " + str); };
运行:
npm run run
结果:
# 命令行打印 print: index
这种方式因为中间转码会有额外的性能损耗,所以不建议在生产环境下使用,只建议在开发模式下使用。
2.2 使用 babel-node 直接运行 es6 模块文件babel-node 对 babel-register 进行了封装,提供了在命令行直接运行 es6 模块文件的便捷方式。
示例目录:
- package.json - src/ - index.js - print.js - ...
相关文件:
# package.json { "scripts": { "run": "babel-node src/index.js --plugins @babel/plugin-transform-modules-commonjs" }, "devDependencies": { "@babel/core": "^7.1.2", "@babel/node": "^7.2.0", "@babel/plugin-transform-modules-commonjs": "^7.2.0" } } # src/index.js import print from "./print"; print("index"); # src/print.js export default str => { console.log("print: " + str); };
运行:
npm run run
结果:
# 命令行打印 print: index
这种方式也不建议在生产环境下使用,只建议在开发模式下使用。
3. 链接es6 就是指 ECMAScript 2015
es7 就是指 ECMAScript 2016
es8 就是指 ECMAScript 2017
es9 就是指 ECMAScript 2018
到写这篇文章为止,已发布了 ECMAScript 2018。
后续更多博客,查看 https://github.com/senntyou/blogs
作者:深予之 (@senntyou)
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/99876.html
摘要:挂机科了次使用这个结构,匿名函数就有了自己的执行环境或闭包,然后我们立即执行。注意,匿名函数的圆括号是必需的,因为以关键字开头的语句通常被认为是函数声明请记住,中不能使用未命名的函数声明。 这是专门探索 JavaScript 及其所构建的组件的系列文章的第 20 篇。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 如果你错过了前面的章节,可以在这里找到它们: ...
摘要:要想让模块再次运行,必须清除缓存。模块加载的顺序,按照其在代码中出现的顺序。最近参加了公司开展的一次培训,结构性思维培养。 序言 模块化,大家用vue,react等东西,都会接触到像exports,module.exports,export,export default,require,define,import等等字段,感觉很多人对于这些东西还是分不清,概念非常的模糊,便想着写这么一...
摘要:使用要给项目构建接入动态链接库的思想,需要完成以下事情把网页依赖的基础模块抽离出来,打包到一个个单独的动态链接库中去。接入已经内置了对动态链接库的支持,需要通过个内置的插件接入,它们分别是插件用于打包出一个个单独的动态链接库文件。 webpack优化 查看所有文档页面:全栈开发,获取更多信息。原文链接:webpack优化,原文广告模态框遮挡,阅读体验不好,所以整理成本文,方便查找。 ...
摘要:在他的重学前端课程中提到到现在为止,前端工程师已经成为研发体系中的重要岗位之一。大部分前端工程师的知识,其实都是来自于实践和工作中零散的学习。一基础前端工程师吃饭的家伙,深度广度一样都不能差。 开篇 前端开发是一个非常特殊的行业,它的历史实际上不是很长,但是知识之繁杂,技术迭代速度之快是其他技术所不能比拟的。 winter在他的《重学前端》课程中提到: 到现在为止,前端工程师已经成为研...
阅读 3871·2021-09-27 13:35
阅读 1068·2021-09-24 09:48
阅读 2898·2021-09-22 15:42
阅读 2338·2021-09-22 15:28
阅读 3145·2019-08-30 15:43
阅读 2609·2019-08-30 13:52
阅读 2970·2019-08-29 12:48
阅读 1450·2019-08-26 13:55