UNPKG

utquidem

Version:

The meta-framework suite designed from scratch for frontend-focused modern web development.

151 lines (107 loc) 5.3 kB
--- sidebar_position: 7 --- # 模块的入口文件配置 对于可复用模块来说,`package.json` 是一个很重要的文件,其中包含了很多信息,例如项目的名称、依赖的模块。 本章将要介绍 `package.json` 文件中 "exports" 字段的使用以及 Modern.js 对于它做了哪些支持。 ## package.json 中的 `exports` 是什么? 在一个包的 `package.json` 文件中,"main" 字段可以用于定义一个包的入口文件。这个字段在 Node.js 所有版本中都支持,并且在其他工具中(例如 webpack)中也默认支持。 虽然它已经被普遍支持,但是它提供的能力其实很有限:它仅仅只能定义一个主要的入口文件。 而 "exports" 字段提供了 "main" 的替代方案,它不仅可以定义主要的入口文件,还可以自定义入口。在自定义入口的同时还起到了封装入口的作用:使用者不可以访问未在 "exports" 中定义的入口路径以外的任何其他路径。 ### 举个例子 如果有一个 **foo** 包,其中包含了 `./index.js`、`./lib.js`、`./feature.js` 三个文件,如果它的 `package.json` 定义如下: ```json { "name": "foo", "exports": { ".": "./index.js", "./lib": "./lib.js" } } ``` 在支持 "exports" 的环境里,你可以在代码中这样导入模块 **foo** 的文件: ``` js const foo = require('foo'); const fooLib = require('foo/lib'); ``` 但是你无法这样使用: ``` js const fooFeat = require('foo/feature'); ``` 因为在 `package.json` 中未定义 `./feature` 入口路径。 ### 关于"exports""main"之间的优先级 如果同时定义了 "exports""main""exports" 字段优先于 "main"。因此如果当 "exports" 字段存在的时候,"main" 字段的配置会被覆盖掉。 "exports" 字段不是特定作用于 ES Module 还是 CommonJS,因此不能使用 "main" 字段来作为使用 CommonJS 的回退手段。但它可以作为不支持 "exports "字段的旧版本的 Node.js 的回退手段。 因此对于上面的例子中我们就可以这样修改: **package.json** ``` { "name": "foo", "main": "./index.js", "exports": { ".": "./index.js", "./lib": "./lib.js" } } ``` ### 条件导出 "exports" 字段提供了条件导出的功能。通过条件导出,可以定义每个环境对应不同的模块包的入口文件,这也包括模块包被使用的时候是通过 `require` 的方式还是通过 `import` 的方式。 例如针对上面的例子进行扩展,假设该模块包提供了 ES Module 实现的文件 `wrapper.mjs` ,那么 `package.json` 会有如下的变化: ``` json { "name": "foo", "main": "./index.cjs", "exports": { "import": "./wrapper.mjs", "require": "./index.cjs" } } ``` 此时如果通过 `require('foo')` 这样的方式使用该模块,则实际上导入的是 `foo/index.cjs` 文件。 而当通过 `import foo from 'foo';` 这样使用的时候,则实际导入的是 `foo/wrapper.mjs` 文件。 :::info 补充信息 关于 `.cjs` 与 `.mjs` * `.mjs` 为后缀的文件其代码会被识别为使用了 ES Module 模块系统。 * `.cjs` 为后缀的文件其代码会被识别为使用了 CommonJS 模块系统。 ::: 除了像上面使用直接映射方式之外,还可以使用嵌套条件的方式来定义 "exports",例如: ``` json { "main": "./main.js", "exports": { "node": { "import": "./feature-node.mjs", "require": "./feature-node.cjs" }, "default": "./feature.mjs", } } ``` > "node" 用于匹配任何 Node.js 环境,可以是 CommonJS 或者是 ES Module 文件。 > "default" 用于在不满足上面任何条件情况下的回退手段。 关于更多关于 "exports" 的使用,可以阅读 [Node.js Documentation About Packages](https://nodejs.org/api/packages.html) ## 在 Modern.js 中提供的支持 对于不同的可复用模块来说,可能会有不同的(语法以及模块化)构建产物需求 Modern.js 针对该需求提供了不同形式的构建产物以满足各种场景。 在 [构建可复用模块](/docs/guides/features/modules/build) 章节中提到,默认情况下,在 JS 构建产物目录(`dist/js` )下会存在三个目录: - `dist/js/modern` - `dist/js/node` - `dist/js/treeshaking` 这些目录从上到下分别对应了:`ES6 + ES Module`、`ES6 + CommonJS`、`ES5 + ES Module` 这三种构建产物。 因此如果可复用模块是用于在 Node.js 中使用,那么可以在 `package.json` 中按照如下方式进行配置: ``` json { "name": "node-lib", "main": "./dist/js/node/index.js", "exports": { "node": { "require": "dist/js/node/index.js", "import": "dist/js/modern/index.js" }, "default": "dist/js/treeshaking/index.js" } } ``` :::info 补充信息 对于其他环境,例如 webpack。可能存在不完全支持 "exports"的情况,因此对于在非 Node.js 环境运行的可复用模块要谨慎使用。 ::: 除了默认的三种产物以外,Modern.js 还提供了多个预设配置供不同场景去选择使用。具体如何使用,可以查看 [output.packageMode](/docs/apis/config/output/package-mode) 以及 [output.packageFields](/docs/apis/config/output/pacakge-fields)。