首页 > 解决方案 > 如何使用通用实用程序构建 NPM 包

问题描述

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

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

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

如果不应该,应该"main"指向什么,应该如何导出和导入东西?例如,我希望能够import foobar from '@org/common/category/foobar,但是 npm 创建包的方式,似乎打包的路径通常最终会包含distorlib或类似的东西,我真的不想要。

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

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

标签: typescriptnpmstructuretsdx

解决方案


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

发布现代 es 模块

对于现代库(节点和浏览器),您应该在 typescript 中编写源代码,并提供 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"
},

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

"baseUrl": ".",
"rootDir": "source",
"outDir": "dist",
"target": "esnext",
"lib": ["esnext", "dom"],
"module": "esnext",
"experimentalDecorators": true,
"sourceMap": true,
"declaration": true,

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

遗留的 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"fields 是可选的——跳过它

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

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

像上面这样的显式导入比重新导出可能未使用的模块的大树的索引要好,最好只导入你需要的东西来避免需要摇树

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

你只想设置你的 package.json"files"数组来告诉 npm 发布"dist"充满 es-modules 的目录 - 并发布"source",以便消费者在调试库中的任何内容时获得良好的 sourcemap 体验

鼓励用户直接导入模块消除了树抖动问题——因为你没有使用索引文件来聚合可能不需要的模块,你不必把它们摇出来——无论如何,处理包使用胖索引模块

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

是的,这在美学上也困扰着我,但我克服了

dist现在我喜欢它,包很简单,从根开始,和之间有区别source(比如访问源映射以进行调试等),所以区别是公平的游戏

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

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

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

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

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


推荐阅读