中文版在英文版之后。

NPM Publish Reference

Talking over NPM Publish, it is unavoidable to go through the long evolution history of CommonJS and AMD into UMD and finally ES Module. However, we choose to leave it to further reading in References.

In short, we are supposed to publish ES Module stated in module field, for those projects able to recognize ES Module; for other projects unable to do so, we are supposed to publish CommonJS stated in main; if we have browser support requirements, we are supposed to publish UMD instead of CommonJS or side by side.

Published directories

Here we provide a list of well-known javascript/typescript projects on Github, let’s take a look how they publish npm packages:

  1. redux:
    • adopts Rollup;
    • inside repository, places source code under src with nothing else published;
    • inside npm, publishes:
      • src;
      • lib (uncompressed CommonJS, pointed by main);
      • es (uncompressed and compressed ES Module, pointed by module);
      • dist (uncompressed and compressed UMD, pointed by unpkg);
  2. react-use:
    • adopts tsc;
    • inside repository, places source code under src with nothing else published;
    • inside npm, publishes:
      • lib (uncompressed CommonJS, pointed by main);
      • esm (uncompressed ES Module, pointed by module);
  3. vue:
    • adopts Rollup;
    • inside repository, places source code under src, along with dist published;
    • inside npm, publishes:
      • src;
      • dist (containing uncompressed and compressed CommonJS, uncompressed and compressed ES Module and uncompressed and compressed UMD), with main pointing at CommonJS, module pointing at ES Module and unpkg and jsdelivr pointing at UMD;
  4. react:
    • adopts Rollup;
    • inside repository, places sources code under src of MonoRepo, with nothing else published;
    • inside npm, publishes:
      • cjs (uncompressed and compressed CommonJS, pointed by main);
      • umd (uncompressed and compressed UMD);
  5. angular:
    • adopts internal tools;
    • inside repository, places source code under src of MonoRepo, with nothing else published;
    • inside npm, publishes:
      • bundles (uncompressed and compressed UMD, pointed by main);
      • various versions of ES Module (esm vs. fesm, ES5 vs. ES2015, module pointing at fesm5);
  6. react-router:
    • adopts Rollup;
    • inside repository, places source code under modules of MonoRepo, with nothing else published;
    • inside npm, publishes:
      • cjs (uncompressed and compressed CommonJS, pointed by main);
      • esm (uncompressed ES Module, pointed by module);
      • umd (uncompressed and compressed UMD);
  7. axios:
    • adopts Webpack;
    • inside repository, places source code under lib, along with dist published;
    • inside npm, publishes:
      • lib;
      • dist (uncompressed and compressed UMD, pointed by main);
  8. material-ui:
    • adopts Rollup for UMD and Babel for CommonJS and ES Module;
    • inside repository, places source code under src of MonoRepo, with nothing else published;
    • inside npm, publishes:
      • root directory (uncompressed CommonJS, pointed by main);
      • es (uncompressed ES Module);
      • esm (uncompressed ES Module of ES5, pointed by module);
      • umd (uncompressed and compressed UMD);
  9. antd:
    • adopts Webpack;
    • inside repository, places source code under components, with nothing else published;
    • inside npm, publishes:
      • lib (uncompressed CommonJS, pointed by main);
      • es (uncompressed ES Module, pointed by module);
      • dist (uncompressed and compressed UMD, pointed by unpkg);
  10. element-ui:
    • adopts Webpack;
    • inside repository, places source code under src and packages, with nothing else published;
    • inside npm, publishes:
      • lib (single-file and multiple-file CommonJS, compressed UMD, main pointing at CommonJS).

unpkg links of above mentioned projects can be found in References and package.json has field repository for repository info.

Recommendation

  1. Adopt Rollup, for fast compilation, smaller bundle size and clean and straightforward configuration and workflow;
  2. Place source code under src or src of MonoRepo;
  3. Publish UMDCommonJSES Module in separate directories, or in directories with common conventions (e.g. lib for CommonJS and dist for UMD);
  4. Publish both uncompressed and compressed UMD (for development and production purpose);
  5. Publish both uncompressed and compressed ES Module since popular browsers are powerful and smark enough;
  6. Point main at CommonJS or UMD and module at ES Module in package.json.

BTW, typescript projects will also publish .d.ts files, which can benefit target users as well as IDEs a lot. Alternatively, you can write your own type definition files.

NPM 发布参考

说到 NPM Publish,免不了去介绍 CommonJSAMD 然后到 UMD 再到 ES Module 的历史,这边把详细介绍放在参考文献里。

简而言之我们需要,发布以 module 为入口的 ES Module 版本,供能识别 ES Module 的项目使用;发布以 main 为入口的 UMD 版本,供浏览器和不能识别 ES Module 的项目使用,如果不需要浏览器支持则可以只发布 CommonJS 版本。

发布目录

这边先罗列一下大家耳熟能详的一些项目的发布方式:

  1. redux
    • 使用 Rollup
    • 仓库里,源代码在 src,无其他发布内容;
    • npm 里,发布:
      • src
      • lib(非压缩的 CommonJSmain);
      • es(非压缩和压缩的 ES Modulemodule);
      • dist(非压缩和压缩的 UMDunpkg);
  2. react-use
    • 使用 tsc;
    • 仓库里,源代码在 src,无其他发布内容;
    • npm 里,发布:
      • lib(非压缩的 CommonJSmain);
      • esm(非压缩的 ES Modulemodule);
  3. vue
    • 使用 Rollup
    • 仓库里,源代码在 src,同时发布 dist
    • npm 里,发布:
      • src
      • dist(非压缩和压缩的 CommonJS、非压缩和压缩的 ES Module、非压缩和压缩的 UMD),main 指向 CommonJSmodule 指向 ES Moduleunpkgjsdelivr 指向 UMD
  4. react
    • 使用 Rollup
    • 仓库里,源代码在 MonoRepo 的 src,无其他发布内容;
    • npm 里,发布:
      • cjs(非压缩和压缩的 CommonJSmain);
      • umd(非压缩和压缩的 UMD);
  5. angular
    • 使用内部工具;
    • 仓库里,源代码在 MonoRepo 的 src,无其他发布内容;
    • npm 里,发布:
      • bundles(非压缩和压缩的 UMDmain);
      • 多种 ES ModuleesmfesmES5ES2015module 指向 fesm5);
  6. react-router
    • 使用 Rollup
    • 仓库里,源代码在 MonoRepo 的 modules,无其他发布内容;
    • npm 里,发布:
      • cjs(非压缩和压缩的 CommonJSmain);
      • esm(非压缩的 ES Modulemodule);
      • umd(非压缩和压缩的 UMD);
  7. axios
    • 使用 Webpack
    • 仓库里,源代码在 lib,同时发布 dist
    • npm 里,发布:
      • lib
      • dist(非压缩和压缩的 UMDmain);
  8. material-ui
    • 使用 Rollup 生成 UMDBabel 生成 CommonJSES Module
    • 仓库里,源代码在 MonoRepo 的 src,无其他发布内容;
    • npm 里,发布:
      • 扁平目录(非压缩的 CommonJSmain);
      • es(非压缩的 ES Module);
      • esm(非压缩的 ES5ES Modulemodule);
      • umd(非压缩和压缩的 UMD);
  9. antd
    • 使用 Webpack
    • 仓库里,源代码在 components,无其他发布内容;
    • npm 里,发布:
      • lib(非压缩的 CommonJSmain);
      • es(非压缩的 ES Modulemodule);
      • dist(非压缩和压缩的 UMDunpkg);
  10. element-ui
    • 使用 Webpack
    • 仓库里,源代码在 srcpackages,无其他发布内容;
    • npm 里,发布:
      • lib(整合和散装的非压缩的 CommonJS、压缩的 UMD),main 指向 CommonJS

以上项目都能在参考文献里找到 unpkg 的链接,然后在 package.json 里找到仓库。

推荐方案

  1. 使用 Rollup,使得你的编译打包更快、体积更小(可以阅读参考文献),编译配置及流程清晰(一些项目整个流程非常繁冗复杂);
  2. 源代码放在 src 或者 MonoRepo 的 src
  3. 单独为 UMDCommonJSES Module 建立发布目录,或者使用有习惯用途的目录命名(CommonJS 放在 libUMD 放在 dist);
  4. UMD 提供非压缩和压缩两个版本(供开发和生产使用);
  5. ES Module 最好也提供压缩版本,供浏览器使用;
  6. package.jsonmain 指向 CommonJSUMDmodule 指向 ES Module

另外说一下,typescript 的项目会发布 .d.ts 的文件,可以给 IDE 以及开发者提供便利。不过也可以自行编写类型定义文件。

References:

  1. NPM official documentation: packages-and-modules, npm-package
  2. JavaScript module system, CommonJS, Asynchronous Module Definition, IIFE
  3. Popular repositories: redux, react-use, vue, react, angular, react-router, axios, material-ui, antd, element-ui
  4. Angular Flattening of ES Modules
  5. The cost of small modules (Rollup recommendation)