引
一个可能并不是有很多人会去做的场景,但是他对于开源贡献者以及协同贡献者来说确实是比较重要的问题。
前言
大部分的人都开发过 monorepo 吧!如果说你参与过一些比较大型的开源项目,并且正好是一个 lib 开发者的话,你有福了!骄傲脸
当国外开发者还在手写 publishConfig 的时候,我带你来跑步进入现代化 cli。
那么问题是什么呢?
很常见的由于大家都是吴彦祖,所以在参与开源贡献的时候我们经常可以看到这样。
或者这样
有些人可能奇怪了,这又怎么了吗?
如果你有去运行项目你会发现:诶呀,跑不起来!
等等,我知道你很急,但是你先别急。
你可能想说,你这人会不会开发啊,会不会看 contribute guide 啊!你 build 啊!这么大个 dist 在这你看不到吗?你肯定要构建才能有啊。
好,那么问题来了,我为什么要构建?typescript 是不认识 exports 吗?bundler 是不认识 exports 吗?我直接在这写 ts 文件不行吗?
很好,这个时候可能也有人急了,但是应该大部分人还是懵的。为什么都支持,这些大佬还是这样在项目里面写呢?那是因为之前的 exports 与 imports 支持并没有现在这么好,但是现在,时代变了大人!
我们 Node.js 在 v12 支持了 exports,大多数的 bundler 也在最近的版本就已经处理好了这些问题。同时最重要也是最最重要的 ts 也在很早支持了 nodenext 的解析策略,并且在 v5 提供了 bundler 的 moduleResolution 选项。publishConfig 也是一个很早就有的东西(我为什么说这个呢?真奇怪)。
这些都是我们现代化 monorepo 项目的不可或缺的特性!那么!现在开始。
JK 启动
shell
pnpm add -D jiek
现在,忘掉 exports.types
、exports.import
、exports.default
、exports.require
。享受纯粹的 package.json 的编写,把 exports 想象为你需要构建的入口(entry points)。
json
{
"exports": {
".": "index.ts"
}
}
是不是比起这一坨要省了很多事呢?
恭喜,你已到达彼岸,现在只需要解决一个最重要也是最致命的问题。
可能有人会说:exports 我也不是不懂,这玩意不能用啊?你让我发给用户的用 .ts 文件?他再编译一遍到 .js ?你自己有问题不要带着我也有问题好吧?难道你有啥法子可以覆盖我要发布的 pacakge.json ?
不错,这里就不得不提到上文中的 publish config 了。顾名思义,发布 配置。那自然是在发布的时候会用来覆盖外面的 package.json 的,所以我们只需要这么写。
json
{
"exports": {
".": "index.ts"
},
"publishConfig": {
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.esm.js",
"require": "./dist/index.umd.js",
"inner-src": "./src/index.ts"
},
}
}
好好好,你小子,前面说那么一大圈。合着这玩意还是要写啊?(实际上已经解决了开发阶段不需要 build 的问题了)
那么为什么不更近一步呢?走进构建工具,规定输出格式,制定产物命名规范,自适应产物生成格式,调整输出内容,同时得到我们的 exports 呢?
嗯,链路很长。不过,我做了。
shell
jk pub -f pnpm_工作空间过滤规则 -p
{
"name": "包名",
"exports": {
".": "./src/index.ts",
"./types": "./src/types.ts",
"./utils": "./src/utils/index.ts",
"./utils/valtio": "./src/utils/valtio/index.ts",
"./plugins/*": ["./src/plugins/*/index.ts", "./src/plugins/*.ts"]
},
"publishConfig": {
"exports": {
"./package.json": "./package.json",
".": { ... },
"./types": { ... },
"./utils": { ... },
"./utils/valtio": { ... },
"./plugins/bracket-matcher": { ... },
"./plugins/expression-quick-completions": { ... },
"./plugins/symmetry-operator": { ... },
"./plugins/code-styler": { ... },
"./plugins/provide-completions": { ... }
},
"types": "./dist/index.d.ts",
"main": "./dist/index.umd.js",
"module": "./dist/index.esm.js",
"browser": "./dist/index.umd.min.js",
"typesVersions": {
"<5.0": {
"*": [
"*",
"./dist/*",
"./dist/*/index.esm.d.ts"
]
}
}
}
}
-p
参数为预览模式,不会真实调用 pnpm publish 指令。你可以在这里检查工具生成是否合理。
如果你对我的构建工具感兴趣,可以试试 jk build -f pnpm_过滤规则
,会根据你的入口(exports)直接构建产物,无配置,如果你只有一个入口,甚至可以不写 index 入口,不过别的空间内包,没办法找到你的入口,比较适合那种比较简单的单包以及最终产物单一并不会被内部引用的包。
可能不一定能符合你的需求,展示是我个人的构建规则,但是是通用且合理的,如果有定制化需求,合理场景我可以花费一定的时间来进行迭代。
散会
感谢 Jack-Works、magic-akari 在我开发过程中提出的建设性建议与支持,如果对你也有用,可以和我一样 sponsor 他们,你的鼓励是他们摆脱开源 ed 的动力。我就不用了,我的还没通过😭。
最后
文章采用类似对话的方式进行编写,希望不要踩到大家的雷,希望雷也不要雷到大家。以上,致谢。