RUA!

使用 Turborepo 和 rollup 构建 NPM 包

TABLE OF CONTENTS

对于 monorepo 我使用的是 turborepo,创建一个新的项目非常简单:

Turbo
Turbo is an incremental bundler and build system optimized for JavaScript and TypeScript, written in Rust.
https://turborepo.org/
npx create-turbo@latest

对于包管理器,这次尝鲜使用了 pnpm 它在安装包到 workspace 中相对于其他两个来说要更加的方便。

Fast, disk space efficient package manager | pnpm
Fast, disk space efficient package manager
https://pnpm.io/
pnpm add --filter rua-three react react-dom three stats.js -D

Turborepo

对于 turborepo 来说没有什么需要过多配置的,比较需要注意的就是它的环境变量需要手动在 turbo.json 配置文件中声明一次:

"globalEnv": [
  "NODE_ENV"
],

除此之外,在默认的 tsconfig 中, 其 targetes5 如果需要一些比较先进的语法,例如在类体中实例化另一个类,则就需要将 target 设置到 es6 及以上。

"compilerOptions": {
  "target": "es6",
},

rollup

相比较与 turborepo 来说,rollup 需要注意的地方就多一些。对于 rollup 的安装来说,本身所需要的依赖不是很多,主要是部分插件。

"@rollup/plugin-commonjs": "^22.0.2",
"@rollup/plugin-node-resolve": "^14.1.0",
"rollup": "^2.79.1",
"rollup-plugin-typescript2": "^0.34.0",

对于一个小包来说,我的目录结构也非常的简单,核心部分就在 rollup.config.jspackage.json

.
├── lib
│   ├── cjs
│   └── esm
├── package.json
├── README.md
├── rollup.config.js
├── src
│   ├── hooks
│   ├── index.ts
│   └── three
└── tsconfig.json

安装完了 rollup 之后,需要对其简单的进行一下配置。对于 input 和 output 是基本操作,没有什么值得注意的。而 external 字段决定了我们依赖是否是外部依赖,从而直接决定了 rollup 会不会将第三方的依赖打包到一起。

import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from 'rollup-plugin-typescript2';

import pkg from './package.json';

export default {
  input: 'src/index.ts',
  output: [
    {
      file: pkg.main,
      format: 'cjs',
      sourcemap: true,
    },
    {
      file: pkg.module,
      format: 'es',
      sourcemap: true,
    },
  ],
  external: [
    ...Object.keys(pkg.peerDependencies || {}),
    'three/examples/jsm/controls/OrbitControls',
  ],
  plugins: [
    nodeResolve(),
    commonjs(),
    typescript({
      typescript: require('typescript'),
    }),
  ],
};

通常来说,我们将所依赖的第三方依赖明确的生声明在 peerDependencies 中,在根据其 key 设置到 external 中,这样我们的 peerDependencies 就不会被一起打包了。

"peerDependencies": {
  "react": "^18.2.0",
  "react-dom": "^18.2.0",
  "stats.js": "^0.17.0",
  "three": "^0.144.0"
},

但在我的例子中,光添加了 three 还不够。如果还引入了 three 这个包下的其他文件夹内的文件,rollup 并没有非常智能的识别到 three/examples/jsm/controls/OrbitControls 也隶属于 three

从而将 OrbitControls 也打包到一起了,所以在 external 中还需要手动添加。

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

package

package.json 中除了 peerDependencies 比较重要外,入口文件和类型文件的位置声明也决定了我们的包能否被正常使用。

"main": "./lib/cjs/index.js",
"module": "./lib/esm/index.js",
"types": "./lib/esm/index.d.ts",

files 字段则决定了当我们使用 npm publish 时所上传的文件:

"files": [
  "/lib"
],

NPM

在做了适当的配置后,公开一个包到公共源非常简单,只需要两个命令,分别是登录和上传。

npm adduser
npm publish

需要注意的就是不能在镜像源上登陆,当然也不能上传。