---
title: 使用 Turborepo 和 rollup 构建 NPM 包
date: '2022-10-10'
tags: [JavaScript, NPM]
---

对于 monorepo 我使用的是 [turborepo](https://turborepo.org/)，创建一个新的项目非常简单：

```tsx
npx create-turbo@latest
```

对于包管理器，这次尝鲜使用了 [pnpm](https://pnpm.io/) 它在安装包到 workspace 中相对于其他两个来说要更加的方便。

```tsx
pnpm add --filter rua-three react react-dom three stats.js -D
```

## Turborepo

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

```tsx
"globalEnv": [
  "NODE_ENV"
],
```

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

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

## rollup

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

```tsx
"@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.js` 和 `package.json` 。

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

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

```tsx
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` 就不会被一起打包了。

```tsx
"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 中还需要手动添加。

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

## package

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

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

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

```tsx
"files": [
  "/lib"
],
```

## NPM

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

```tsx
npm adduser
npm publish
```

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