新增的模块加载流程
require("X") //当在 Y 文件中加载 X 模块时
-
如果 X 是核心模块,载入
-
如果 X 是以 "/" 开头的绝对路径,需要添加系统根路径
-
如果 X 是以 "/" , "./" , "../" 开头的路径
a. 尝试作为一个文件载入
b.尝试作为一个目录载入
c.出错 "not found"
-
尝试加载自身引用(LOAD_SELF_REFERENCE)
-
尝试加载 node_modules 三方控件引用
其中第四步为 node v12 新增的流程,需要使用 --experimental-modules 开启此步流程, 在node v13 中不需要 --experimental-modules 。
使用 exports 声明
node 在 v12 允许在 package.json 中使用 exports ,显示声明要导入的文件路径以及如何去解析它们,这扩展了使用 main 字段已经拥有的控件包。
文件声明
{
"exports": {
"./feature": "./lib/feature.js",
}
}
目录声明
{
"exports": {
"./feature/": "./lib/feature/",
}
}
默认声明
使用 "." 可以声明默认的输出模块,对于支持 exports 的node版本中,exports 的优先级是高于 main
{
"exports": {
".": "./main.js"
}
}
//也可以简写
{
"exports": "./main.js"
}
//等同于用
{
"main": "./main.js",
}
有条件的导出
exports可以根据不同环境导出不同的文件,node 支持4种条件匹配:
default: 默认的匹配选项,任意条件都能匹配的选项。import: 使用 esmodule 加载模块的选项。require: 使用 CommonJS 加载模块的选项。node: 使用任意node环境加载文件的选项。
它们四个的优先级取决于在 exports 中的声明顺序,越早声明优先级越高。
{
"exports": {
"./feature": {
"import": "./feature-default.js",
"browser": "./feature-browser.js"
}
}
}
错误忽略
当使用数组时,不合法的路径将被忽略,比如不以 "./" 开头的路径或者不是以 "/"结尾的目录。
但是这并不是一种错误的回退写法,前一个值是路径但是却没有这个文件时,node还是会抛出错误,并不会加载后面的路径
{
"exports": {
"./submodule": ["not:valid", "./submodule.js"]
}
}
加载自身引用步骤
require("X") //当在 Y 文件中加载 X 模块时
当 X 不是核心模块并且不是以 "/" , "./" , "../" 开头的路径时,会尝试加载自身引用。
-
将 X 分解分 name/subpath 两部分,以第一个"/"分割。
-
如果name和最近的package.json中name相同,且有声明
exports -
exports中有以subpath开头的声明a.如果是文件声明,尝试作为一个文件载入
b.如果是目录声明,将x前缀转换成声明的目录,继续载入
PACKAGE_EXPORTS_TARGET_RESOLVE( pathToFileURL(DIR/name), exports[key], subpath.slice(key.length), ["node", "require"] )
加载 node_modules 三方控件引用
加载三方控件时,也会去解析package.json 中 exports 声明