package.json中browser/module/main加载顺序
Author:zhoulujun Date:
内容来源:https://github.com/SunshowerC/blog/issues/8
browser VS module VS main
前端开发中使用到 npm 包那可算是家常便饭,而使用到 npm 包总免不了接触到 package.json 包配置文件。
那么这里就有一个问题,当我们在不同环境下 import 一个 npm 包时,到底加载的是 npm 包的哪个文件?
老司机们很快地给出答案:main 字段中指定的文件。
然而我们清楚 npm 包其实又分为:只允许在客户端使用的,只允许造服务端使用的,浏览器/服务端都可以使用。
如果我们需要开发一个 npm 包同时兼容支持 web端 和 server 端,需要在不同环境下加载npm包不同的入口文件,显然一个 main 字段已经不能够满足我们的需求,这就衍生出来了 module 与 browser 字段。
本文就来说下 这几个字段的使用场景,以及同时存在这几个字段时,他们之间的优先级。
文件优先级
在说 package.json 之前,先说下文件优先级
由于我们使用的模块规范有 ESM 和 commonJS 两种,为了能在 node 环境下原生执行 ESM 规范的脚本文件,.mjs 文件就应运而生。
当存在 index.mjs 和 index.js 这种同名不同后缀的文件时,import './index' 或者 require('./index') 是会优先加载 index.mjs 文件的。
也就是说,优先级 mjs > js
browser,module 和 main 字段
字段定义
main: 定义了npm包的入口文件,browser 环境和 node 环境均可使用module: 定义npm包的 ESM 规范的入口文件,browser 环境和 node 环境均可使用·
browser: 定义npm包在 browser 环境下的入口文件
使用场景与优先级
首先,我们假定 npm 包 test 有以下目录结构
----- lib |-- index.browser.js |-- index.browser.mjs |-- index.js |-- index.mjs
其中 *.js 文件是使用 commonJS 规范的语法(require('xxx')),*.mjs 是用 ESM 规范的语法(import 'xxx')
其 package.json 文件:
"main": "lib/index.js", // main
"module": "lib/index.mjs", // module
// browser 可定义成和 main/module 字段一一对应的映射对象,也可以直接定义为字符串
"browser": {
"./lib/index.js": "./lib/index.browser.js", // browser+cjs
"./lib/index.mjs": "./lib/index.browser.mjs" // browser+mjs
},
// "browser": "./lib/index.browser.js" // browser根据上述配置,那么其实我们的 package.json 指定的入口可以有
mainmodulebrowserbrowser+cjsbrowser+mjs
这 5 种情况。
下面说下具体使用场景。
webpack + web + ESM
这是我们最常见的使用场景,通过 webpack 打包构建我们的 web 应用,模块语法使用 ESM
当我们加载
import test from 'test'
实际上的加载优先级是 browser = browser+mjs > module > browser+cjs > main
也就是说 webpack 会根据这个顺序去寻找字段指定的文件,直到找到为止。
然而实际上的情况可能比这个更加复杂,具体可以参考流程图

webpack + web + commonJS
const test = require('test')事实上,构建 web 应用时,使用 ESM 或者 commonJS 模块规范对于加载优先级并没有任何影响
优先级依然是 browser = browser+mjs > module > browser+cjs > main
webpack + node + ESM/commonJS
我们清楚,使用 webpack 构建项目的时候,有一个 target 选项,默认为 web,即进行 web 应用构建。
当我们需要进行一些 同构项目,或者其他 node 项目的构建的时候,我们需要将 webpack.config.js 的 target 选项设置为 node 进行构建。
import test from 'test'
// 或者 const test = require('test')优先级是: module > main
node + commonJS
通过 node test.js 直接执行脚本
const test = require('test')只有 main 字段有效。
node + ESM
通过 --experimental-modules 可以让 node 执行 ESM 规范的脚本(必须是 mjs 文件后缀) `node --experimental-modules test.mjs
import test from 'test'
只有 main 字段有效。
总结
如果
npm包导出的是 ESM 规范的包,使用 module如果
npm包只在 web 端使用,并且严禁在 server 端使用,使用 browser。如果
npm包只在 server 端使用,使用 main如果
npm包在 web 端和 server 端都允许使用,使用 browser 和 main其他更加复杂的情况,如
npm包需要提供 commonJS 与 ESM 等多个规范的代码文件,请参考上述使用场景或流程图
转载本站文章《package.json中browser/module/main加载顺序》,
请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/nodejs/8763.html