当前位置:网站首页>如何正确地配置入口文件?
如何正确地配置入口文件?
2022-08-02 18:39:00 【大淘宝技术】

第三方库作者就需要编写相应的入口文件,来达到“动态”引入的目的,同时也方便于打包工具对于无用代码的剔除,减少代码体积,本篇文章主要聚焦于前端工程如何正确地配置入口文件。
CommonJS(cjs) 和 ECMAScript modules (esm)。注:本篇文章以node规范为准,对于打包工具额外支持的配置方式会进行额外标注
本文的涉及的示例代码可以通过 https://github.com/HomyeeKing/test-entry 进行查看、测试
package.json的 main字段是最常见的指定入口文件的形式
{"name": "@homy/test-entry","version": "1.0.0","description": "","main": "index.js"}
@homy/test-entry这个包的时候,可以确定@homy/test-entry 这个npm包的入口文件指向的是 index.jsconst pkg = require('@homy/test-entry')但是index.js究竟是cjs or esm?
一种方式是我们可以通过后缀名来显示地标注出当前文件是cjs还是esm格式的:
cjs --->
.cjsesm --->
.mjs
那么不同模块格式的文件如何相互引用呢?解释规则大致如下
import了CJS格式的文件,module.exports会等同于export default, 具名导入会根据静态分析来兼容,但是一般推荐在ESM中使用defaultExport格式来引入CJS文件
在CJS中,如果想要引入ESM文件,因为ESM模块异步执行的机制,必须使用Dynamic Import即
import()来引用
// index.cjsconst pkg = require('./index.mjs') // Errorconst pkg = await import('./index.mjs') //// index.mjsimport { someVar } from './index.cjs' // ️ it dependens 推荐下边方式引入import pkg from './index.cjs' //
另一种方式是通过package.json的 type字段来标识
.js文件,{"name": "@homy/test-entry","version": "1.0.0","description": "","type": "commonjs", // or "module", 默认是 commonjs"main": "index.js"}
如果手动设置type: module, 则将index.js当做esmodule处理,否则视为CommonJS
type: module ,只有Node.js >= 14 且使用import才能使用,不支持require引入
注:关于.js的详细解析策略推荐阅读 https://nodejs.org/api/modules.html#enabling
通过type和main字段,我们可以指定入口文件以及入口文件是什么类型,但是指定的只是一个入口文件,仍然不能够满足我们“动态”引入的需求,所以node又引入exports这个新的字段作为main更强大的替代品。
相比较于main字段,exports可以指定多个入口文件,且优先级高于main
{"name": "@homy/test-entry","main": "index.js","exports":{"import":"./index.mjs","require":"./index.cjs","default": "./index.mjs" // 兜底使用},}
const pkg = require('@homy/test-entry/test.js');// 报错!Package subpath './test.js' is not defined by "exports"
submodule, 我们可以这样编写"exports": {"." : "./index.mjs","./mobile": "./mobile.mjs","./pc": "./pc.mjs"},// or 更详细的配置"exports": {".":{"import":"./index.mjs","require":"./index.cjs","default": "./index.mjs"},"./mobile": {"import":"./mobile.mjs","require":"./mobile.cjs","default": "./mobile.mjs"}},
然后通过如下方式可以访问到子模块文件
import pkg from 'pkg/mobile'imports 字段,主要用于控制import的解析路径,类似于Import Maps, 不过在node中指定的入口需要以#开头,感兴趣的可以阅读subpath-importsmain exports字段,被主流打包工具广泛支持的还有一个module字段大部分时候 我们也能在第三方库中看到module这个字段,用来指定esm的入口,但是这个提案没有被node采纳(使用exports)但是大多数打包工具比如webpack、rollup以及esbuild等支持了这一特性,方便进行tree shaking等优化策略

另外,TypeScript已经成为前端的主流开发方式,同时TypeScript也有自己的一套入口解析方式,只不过解析的是类型的入口文件,有效辅助开发者进行类型检查和代码提示,来提高我们编码的效率和准确性,下面我们继续了解下TypeScript是怎么解析类型文件的。
main字段,然后找对应文件是否存在类型声明文件,比如main指向的是lib/index.js, TypeScript就会查找有没有lib/index.d.ts文件。另外一种方式,开发者可以在package.json中通过
types字段来指定类型文件,exports中同理。{"name": "my-package","type": "module","exports": {".": {// Entry-point for TypeScript resolution - must occur first!"types": "./types/index.d.ts",// Entry-point for `import "my-package"` in ESM"import": "./esm/index.js",// Entry-point for `require("my-package") in CJS"require": "./commonjs/index.cjs",},},// CJS fall-back for older versions of Node.js"main": "./commonjs/index.cjs",// Fall-back for older versions of TypeScript"types": "./types/index.d.ts"}
▐ TypeScript模块解析策略
moduleResolution字段,支持classic(默认)和node两种解析策略,主要针对相对路径引入和非相对路径引入两种方式,我们可以通过示例来理解下▐ classic
查找以.ts 或.d.ts结尾的文件
relative import
// /root/src/folder/A.tsimport { b } from "./moduleB"// process:/root/src/folder/moduleB.ts/root/src/folder/moduleB.d.ts
相对路径会找当前目录下的.ts 或.d.ts的文件
no-relative import
// /root/src/folder/A.tsimport { b } from "moduleB"// process:/root/src/folder/moduleB.ts/root/src/folder/moduleB.d.ts/root/src/moduleB.ts/root/src/moduleB.d.ts/root/moduleB.ts/root/moduleB.d.ts/moduleB.ts
则会向上查找,直到找到moduleB 相关的.ts或.d.ts文件
▐ node
以类似于node的解析策略来查找,但是相应的查找的范围是以.ts .tsx .d.ts为后缀的文件,而且会读取package.json中对应的types(或typings)字段
relative
/root/src/moduleAconst pkg = require('./moduleB')// process:/root/src/moduleB.js/root/src/package.json (查找/root/src下有无package.json 如果指定了main字段 则指向main字段对应的文件)/root/src/moduleB/index.js
.js 当前package.json中main字段指向的文件以及是否存在对应的index.js文件。.ts .tsx .d.ts,而且ts这时候会读取types字段 而非main/root/src/moduleB.ts/root/src/moduleB.tsx/root/src/moduleB.d.ts/root/src/moduleB/package.json (if it specifies a types property)/root/src/moduleB/index.ts/root/src/moduleB/index.tsx/root/src/moduleB/index.d.ts
no-relative
node_modules下有没有对应文件/root/src/moduleAconst pkg = require('moduleB')// process:/root/src/node_modules/moduleB.js/root/src/node_modules/package.json/root/src/node_modules/moduleB/index.js/root/node_modules/moduleB.js/root/node_modules/moduleB/package.json (if it specifies a "main" property)/root/node_modules/moduleB/index.js/node_modules/moduleB.js/node_modules/moduleB/package.json (if it specifies a "main" property)/node_modules/moduleB/index.js
@types下类型的查找/root/src/node_modules/moduleB.ts/root/src/node_modules/moduleB.tsx/root/src/node_modules/moduleB.d.ts/root/src/node_modules/moduleB/package.json (if it specifies a types property)/root/src/node_modules/@types/moduleB.d.ts <----- check out @types/root/src/node_modules/moduleB/index.ts/root/src/node_modules/moduleB/index.tsx/root/src/node_modules/moduleB/index.d.ts....
node中可以通过
main和type: module | commonjs来指定入口文件及其模块类型,exports则是更强大的替代品,拥有更灵活的配置方式主流打包工具如webpack rollup esbuild 则在此基础上增加了对top-level
module的支持TypeScript 则会先查看package.json中有没有
types字段,否则查看main字段指定的文件有没有对应的类型声明文件
https://webpack.js.org/guides/package-exports/
https://nodejs.org/api/packages.html#packages_package_entry_points
https://esbuild.github.io/api/#main-fields
https://www.typescriptlang.org/docs/handbook/module-resolution.html#relative-vs-non-relative-module-imports
https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#version-selection-with-typesversions
https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions

作者|王宏业(莽原)
编辑|橙子君

本文分享自微信公众号 - 大淘宝技术(AlibabaMTT)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
边栏推荐
- cache2go-源码阅读
- Why young people are snapping up domestic iPhone, because it is much cheaper and more populist
- 指针常量和常量指针概述
- Functional test points for time, here is a comprehensive summary for you
- Monitor is easy to Mars debut: distributed operations help TOP3000 across management gap
- 读书笔记之《你想过怎样的一生?》
- LSB利器-zsteg
- Enterprise cloud cost control, are you really doing it right?
- NIO基础之三大组件
- LeetCode 2349. 设计数字容器系统(SortedSet)
猜你喜欢

共享平台如何提高财务的分账记账效率?

中国科学院院属研究单位

LeetCode 2349. 设计数字容器系统(SortedSet)

From the technical panorama to the actual scene, analyze the evolutionary breakthrough of "narrowband high-definition"

I have 8 years of experience in the Ali test, and I was able to survive by relying on this understanding.

Sentienl【动态数据源架构设计理念与改造实践】

Mppt photovoltaic maximum power point tracking control matlab simulation

LSB利器-zsteg

有什么好用的IT资产管理软件

麦聪DaaS平台 3.7.0 Release 正式发布:全面支持国际化
随机推荐
洛谷P5094 MooFest G 加强版
互联网寒冬,挚友7面阿里,终获Offer
WPF使用Prism登录
Five keys to a successful Industrial IoT deployment
Detailed explanation of AtomicInteger
LeetCode 2333. 最小差值平方和(贪心)
【C语言刷题】双指针原地修改数组(力扣原题分析)
Mobile Banking Experience Test: How to Get the Real User Experience
LeetCode 2353. 设计食物评分系统(sortedcontainers)
NIO's Selector execution process
如何确保智能工厂的安全?
洛谷P4316 绿豆蛙的归宿
浅谈一下pyd文件的逆向
有哪些好用的实时网络流量监控软件
看【C语言】实现简易计算器教程,让小伙伴们为你竖起大拇指
注释
LeetCode 2343. 裁剪数字后查询第 K 小的数字
就刚刚,鸿蒙3.0发布了,华为还一口气发布了十一款产品
selenium安装和环境配置Firefox
流量分析三—远程登陆
