前言
紧接上文,继续学习模块规范。上文学习了常见的一个规范,而作为一个前端开发起步的程序猿,重点还是放在ESM上了,接下来就学习如何在node中运行ESM。
node对ESM的支持
在以往的node版本中,是不支持ESM规范的。再后来的V8.9.0版本中,执行下面的这行命令,node可以象征性地支持ESM
node --experimental-modules xxx.js
在后面的V13.2.0版本中,node开始支持并默认启动了--experimental-modules。
--experimental-modules特性
- 使用type指定模块方案
- 在package.json中,type指定为Commonjs,则使用CJS
- 在package.json中,type指定为module,则使用ESM-
- 使用--input-type指定入口文件的模块方案,与type一样
- 命令中加上--input-type=commonjs,则使用CJS
- 命令中加上--input-type=module,则使用ESM
- 支持新文件后缀.cjs
- 文件后缀使用.cjs,则使用CJS
- 使用--es-module-specifier-resolution指定文件名称引用方式
- 命令中加上--es-module-specifier-resolution=explicit,则引用模块时必须使用文件后缀(默认)
- 命令中加上--es-module-specifier-resolution=node,则引用模块时无需使用文件后缀
- 使用main根据type指定模块方案加载文件
- 在
package.json
中指定mian
后会根据type
指定模块方案加载文件
- 在
node判断是否是ESM的规则
在V13.2.0版本后,相当于说node默认支持了ESM规范,那怎么判断是否是ESM呢?
- 文件名后缀是.mjs(使用import/export一定要使用这个后缀,要么就是下面这种方法)
- 如果文件名后缀是js,那需要在package.json中配置type为module(其他使用CJS的话,后缀就需要改成.cjs)
- 命令中加上--input-type=module
- 命令中加上--eval cmd 如果没有改后缀,也没有指定规则,.js文件默认解析为.cjs文件,采用CJS解析
node部署
大于13.2.0版本原生部署
需要指定node版本及npm的版本,不能低于这个node版本,这是为了原生node环境中能支持ESM。建议不要随便修改后缀,通过在package.josn文件中修改type来指定使用ESM。
在高版本的node中,默认情况下,对import命令引入的文件后缀名具有强制性,引入import "file"应该要写成import "file.js",而CJS的自动后缀处理行为可以通过命令行参数开启:--es-module-specifier-resolution=node
node环境下使用ESM,一些node的特性不能使用(__dirname
、__filename
、require
、module
和exports
),且不能灵活引用json文件。
补救措施:
__filename
与__dirname
可用import.meta
对象重建require
、module
和exports
可用import
与export
代替json文件
的引用可用Fs模块
的readFileSync
与JSON.parse()
代替
import { readFileSync } from "fs";
import { dirname } from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__filename, __dirname);
const json = readFileSync("./info.json");
const info = JSON.parse(json);
低版本Node编译部署
使用babel编译ESM代码是低版本node支持ESM的稳妥方式(高版本中也能用)。
- @babel/cli:提供支持
@babel/core
的命令运行环境 - @babel/core:提供转译函数
- @babel/node:提供支持
ESM
的命令运行环境 - @babel/preset-env:提供预设语法转换集成环境
安装上面的四个babel包,然后修改配置
{
"scripts": {
"start": "babel-node src/index.js"
},
"babel": {
"presets": [ "@babel/preset-env" ]
}
}
如果要兼容再更低版本,则需要:
{
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "8.0.0"
}
}
]
]
}
}
nodemon
是一个自动检测项目文件发生变化就重启服务的npm模块,是node开发的必备工具。修改配置如下:
{
"nodemonConfig": {
"env": {
"NODE_ENV": "dev"
},
"execMap": {
"js": "node --harmony"
},
"ext": "js json",
"ignore": [ "dist/" ],
"watch": [ "src/" ]
}
}
执行命令:start换成nodemon -x babel-node src/index.js
- 基于Node原生部署方案改造
Node项目
,适合在高版本Node环境
中使用 - 基于Node编译部署方案改造
Node项目
,适合在低版本Node环境
或任何版本Node环境
中使用 - 基于监听脚本自动重启命令改造
Node项目
,与Node编译部署方案
一样的使用条件,中使用
参考资料:
掘金小册:从0到1落地前端工程化