如何使用通用工具构建 NPM 包

Svi*_*ish 3 structure npm typescript tsdx

我需要为我们公司各种前端项目使用的一些常用功能制作一个 NPM 包,但非常不确定如何正确执行。我们正在使用 Typescript,tsdx似乎处理了几件我不确定如何正确执行的事情,但它没有说明如何构建“实用程序”类型的包。

我不明白的是,我应该"main"package.json点的时候有没有一个合乎逻辑的单一出口/类/函数是有道理的包?

它应该只导出整个包中的每个“公共”函数吗?如果是这样,这将如何影响摇树(我目前不太了解)以及诸如此类的事情?

如果不应该,应该"main"指向什么,应该如何导出和导入东西?我会为像例如要能够import foobar from '@org/common/category/foobar,但是包是由故宫创建方式,似乎打包路径往往会落得包括distlib或类似的东西,我真的不想。

应该如何构建一个“多功能 NPM 包”来获得干净的导入和有效的 tree-shaking 和其他好东西?

有没有人在 GitHub 或其他可用的地方有任何好的、干净、简单的库示例?我曾尝试查看像 lodash 这样的项目,但它们通常不是用 Typescript 编写的,而且似乎通常具有相当复杂的设置,包括单存储库、工作区、自定义构建脚本等......

Cha*_*kal 5

应该如何构建一个“多功能 NPM 包”来获得干净的导入和有效的 tree-shaking 和其他好东西?

发布现代 es 模块

对于现代库(节点和浏览器),您应该在打字稿中创作源代码,并提供 es-module 分发

这个策略遵循的理念是新的库应该是现代的、精益的和简约的——你的库应该只是一个公开可用的 es 模块目录

你的 package.json 应该包括

"type": "module",
"main": "dist/main.js",
"module": "dist/main.js",
"files": [
  "dist",
  "source"
],
"scripts": {
  "prepare": "tsc",
  "watch": "tsc -w",
},
"devDependencies": {
  "typescript": "typescript": "^3.8.3"
},
Run Code Online (Sandbox Code Playgroud)

也许你的 tsconfig.json 有这样的条目

"baseUrl": ".",
"rootDir": "source",
"outDir": "dist",
"target": "esnext",
"lib": ["esnext", "dom"],
"module": "esnext",
"experimentalDecorators": true,
"sourceMap": true,
"declaration": true,
Run Code Online (Sandbox Code Playgroud)

所有优化问题——即:捆绑、缩小、摇树、转译、填充等——所有这些问题都已经由消费者应用程序处理(如果库提供这些问题,那就是多余的膨胀)

遗留的 common-js 应用程序可以轻松地使用 esm 适配器来使用 es 模块分发

如果你绝对必须(请另外考虑),你可以让你的双 esm+cjs 混合包:只需运行一个并行构建步骤tsc -- --module=commonjs --outDir dist-cjs,然后设置 package.json "main": "dist-cjs/main.js",,你就可以同时支持 commonjs 和 esm

具体答案

我需要为我们公司各种前端项目使用的一些常用功能制作一个 NPM 包,但非常不确定如何正确执行。我们正在使用 Typescript,并且 tsdx 似乎处理了几件我不确定如何正确执行的事情,但它没有说明如何构建“实用程序”类型的包。

这就是我推荐 esm 策略的原因:它适用于同构代码,也就是说,该库可以在前端项目和后端节点项目上无缝工作

我不明白的是,当包中没有一个合乎逻辑的单一导出/类/函数时,package.json 中的“main”应该指向什么?

package.json"main""module"字段是可选的——跳过它

我认为这是一个最佳实践:不要将单个入口点指定为您的“主要”——相反,您应该鼓励消费者明确选择他们想要的模块

import {makeLogger} from "authoritarian/dist/toolbox/logger/make-logger.js"

像上面这样的显式导入比重新导出可能未使用的模块的大树的索引更好,最好通过仅导入您需要的内容来避免根本不需要摇树

它应该只导出整个包中的每个“公共”函数吗?如果是这样,这将如何影响摇树(我目前不太了解)以及诸如此类的事情?

你只是想设置你的 package.json"files"数组来告诉 npm 发布"dist"充满 es-modules的目录——并且还发布"source"这样消费者在调试库中的任何东西时都会有一个很好的 sourcemap 体验

鼓励用户直接导入模块消除了摇树问题——因为您没有使用索引文件来聚合可能不需要的模块,因此您不必将它们抖掉——无论如何,这是消费者关心的问题,处理包使用脂肪指数模块

[...] 似乎打包的路径最终会包含 dist 或 lib 或类似的东西,我真的不想要。

是的,这曾经也困扰着我,但我克服了它

现在我喜欢它,包装很简单,从根,并有之间的差异dist,并source(如访问sourcemaps用于调试等),这样的区分是公平的游戏

应该如何构建一个“多功能 NPM 包”来获得干净的导入和有效的 tree-shaking 和其他好东西?

我认为这个答案的策略将提供你正在寻找的

有没有人在 GitHub 或其他可用的地方有任何好的、干净、简单的库示例?我曾尝试查看像 lodash 这样的项目,但它们通常不是用 Typescript 编写的,而且似乎通常具有相当复杂的设置,包括单存储库、工作区、自定义构建脚本等......

我还没有制作流行的包(还没有,muahaha!)但是我的图书馆权威走在路上..我最近制作了很多图书馆,我所宣扬的上述原则是我认为我学到的: renraku是我的同构 json-rpc 库,metalshop是我的 web 组件库,shopper是我的 shopify 购物车 ui

其他不是我制作的非常好的lit-element库包括.. 大多数库都不是新的,并且在 commonjs 世界中半途而废