14
9

More than 1 year has passed since last update.

【2022Q2】pnpm Workspaceによるmonorepo構成のnpmパッケージ開発環境構築

Last updated at Posted at 2022-06-11

概要

手元の雑多なプライベートnpmパッケージ類をmonorepoに押し込んで効率的に管理しつつ、公開できるものは公開してしまおう、という試みにおける開発環境構築の記録。
pnpm WorkspaceによるmonorepoでTypeScriptからESM/CJS両対応またはESM専用のパッケージを生成し、Changesetsによるパッケージ別のバージョン管理と、これに連動した一括デプロイを行う、というもの。

ステップ毎に各設定ファイル等の一部を引用して記述しているため、全体像は完成形の下記ボイラープレートを参照のこと。

要件

  • 作業はWSL2のDebian上で行う
  • Node.jstj/n で管理しバージョンは16系を使用する
  • リポジトリは pnpm Workspaceを使用したmonorepo構成とする
  • 各パッケージのバージョンは個別管理とする
  • Gitプラットフォームは GitHub を使用する
  • 開発言語は TypeScript とする
  • Linterには ESLint を、Formatterには Prettier を使用し EditorConfig を併用する
  • ドキュメンテーションは TSDoc に従い、出力が必要な場合は TypeDoc を使用する
  • エディタには Visual Studio Code を使用し、必要に応じてコーディング用フォントと拡張機能を導入する
  • Simple Git Hookslint-staged でコミット時にLinter/Formatter/型チェックを自動で実行する
  • 英語版と日本語版のREADMEを作成し、 Shields.io で各種バッジを貼る
  • Changesets でバージョニングとCHANGELOGの生成を行う
  • tsup でESModule/CommonJS両対応のデュアルパッケージとしてビルドする
    • またはTypeScriptでESM専用モジュールとしてビルドする
  • pnpmでpackage.json上のバージョンが上がったパッケージをnpmに一括デプロイする
執筆時の詳細なバージョン情報
Name Version
Windows11 21H2
Debian 11.3
git 2.36
Node.js 16.15.1
pnpm 7.2.0
typescript 4.7.3
eslint 8.17.0
prettier 2.6.2
typedoc 0.22.17
simple-git-hooks 2.8.0
lint-staged 12.0.1
tsup 6.1.2

構築

  • 便宜上コードブロックのファイル名はプロジェクトルートをルートディレクトリと見なした絶対パスで記述する
  • WSL2の準備は省略
    • 概略:BIOSでCPUの仮想化機能を有効化 → WSLを有効化 → Microsoft Storeから Debian をインストール
  • Gitのインストールは省略
    • 概略:上記リンクの「ソースからのインストール」の通り

1. Node.jsのインストール

Node.jsのバージョン管理ツール tj/nn-install を使用してインストールし、Node16系の最新版をインストールする。

shell
# tj/nのインストール(n-install使用)
$ sudo apt-get update
$ sudo apt-get -y install curl
$ curl -L https://bit.ly/n-install | bash

# 16系の利用可能なバージョンを確認
$ n lsr --all | grep ^16
16.15.1
16.15.0
16.14.2
...

# 16系の最新バージョンをインストール
$ n i 16.15.1
$ node -v
16.15.1

2. pnpmのインストール

npmで pnpm をグローバルインストールする。

shell
$ npm i -g pnpm

3. リポジトリ作成

プロジェクトのディレクトリを作成し、gitリポジトリとして初期化して設定を行う。

shell
# リポジトリのディレクトリを作成
$ mkdir project-name
$ cd project-name

# git初期化
$ git init
$ git config core.filemode false
# その他必要に応じてユーザ名・メールアドレス・リモートリポジトリ等を設定
  • Windows環境で編集される可能性があるリポジトリは filemode = false にした方がよさそう
    • パーミッションが重要なリポジトリはWinでは触らないはず
    • 同様に ignorecase をどうするかも悩ましい(WinのFSは大文字小文字を区別しない)

3-1. .gitignore

.gitignore ファイルを作成して設定する。
GitHub公式の.gitignoreテンプレート から各OS用とNode.js用の内容を抽出して結合したものをベースとする。

/.gitignore
# tsup
dist

# TypeDoc
packages/*/docs

# VSCode
.vscode
*.code-workspace

# WSL
*Zone.Identifier

# 以下テンプレートの内容

4. ルートプロジェクト設定

ルートプロジェクトとはmonorepoにおける親となるリポジトリのこと。子はサブプロジェクト。
ルートプロジェクトの package.json とpnpmの設定ファイルを作成し編集する。

4-1. 初期化

shell (root project)
# package.jsonの雛形を生成
$ pnpm init

4-2. package.json

/package.json
{
  "name": "<project-name>",
  "version": "0.0.1", // 非公開なので重要ではないが、大きな変更があったら適宜手動でインクリメント予定
  "description": "<project-description>",
  "author": "<author-name>",
  "private": true, // ルートプロジェクトは公開しない
  "homepage": "https://github.com/<github-username>/<repository-name>",
  "repository": {
    "type": "git",
    "url": "https://github.com/<github-username>/<repository-name>.git"
  },
  "bugs": {
    "url": "https://github.com/<github-username>/<repository-name>/issues"
  },
  "scripts": {
    "preinstall": "npx -y only-allow pnpm" // pnpmを強制する
  },
  "engines": {
    "node": ">=16.8.0", // 後述
    "npm": "use pnpm", // pnpmを強制する
    "pnpm": ">=7",
    "yarn": "use pnpm" // pnpmを強制する
  }
}

4-3. サブプロジェクト検出パターン設定

pnpm-workspace.yaml を作成して設定する。

/pnpm-workspace.yaml
packages:
  - 'packages/*'
  • 公式ドキュメント
  • 今回はpackagesディレクトリ直下のディレクトリをサブプロジェクトと見なす

5. サブプロジェクト設定

サブプロジェクトの package.json を作成し編集する。

5-1. 初期化

shell (root project)
# ディレクトリ追加
$ mkdir packages
$ mkdir packages/package-name
$ cd packages/package-name
shell (sub project)
# 初期化
$ pnpm init

5-2. package.json

/packages/package-name/package.json
{
  "name": "<package-name>",
  "version": "0.0.0", // Changesetsが自動でインクリメントするため0.0.0にしておく
  "description": "<package-description>",
  "author": "<author-name>",
  "license": "<license>",
  "homepage": "https://github.com/<github-username>/<repository-name>/tree/main/packages/<package-name>#readme", // GitHub上のREADME.mdを使う場合
  "repository": {
    "type": "git",
    "url": "https://github.com/<github-username>/<repository-name>.git",
    "directory": "packages/<package-name>" // package.jsonのあるサブディレクトリを指定
  },
  "bugs": {
    "url": "https://github.com/<github-username>/<repository-name>/issues"
  },
  "keywords": [
    "hoge", // 後述
    "fuga"
  ],
  "files": [ // パッケージに含めるファイル
    "dist" // pnpm publishを再帰的に実行する際は `./dist` だと処理されない
  ]
}
  • package.json などは files フィールドで指定しなくても標準でパッケージに含まれる
  • 後述するがルートプロジェクトでpnpm Workspaceの機能 pnpm -r publish を使用して再帰的にデプロイする場合、 files フィールドのパス指定の先頭に ./ があると処理されない
    • 2022Q1に再帰的なpublishがfilesフィールドを参照しないバグが起票されて解決しており、その結果が現状であるため、現時点では仕様と思われる
    • 相対パスを ./ から始める流派の人は要注意
    • サブプロジェクト毎に npm publish (pnpmではなくnpmでのデプロイ)を行う場合は ./ が入っていても問題ない
  • keywords フィールドは npm のパッケージ情報Readmeタブ最下部の Keywords 欄に表示される
    • 検索対象なので過不足のないように
  • npmで公開しないものは private: true を指定しておく

6. TypeScript設定

TypeScriptコンパイラを導入し設定する。

shell (root project)
# インストール
$ pnpm add -wD typescript @tsconfig/node16-strictest-esm

6-1. tsconfig.json

  • TSConfig公式リファレンス
  • tsconfig.jsonTypeScriptコンパイラ の設定ファイル、即ち tsc コマンド実行時の設定を行うもの
    • 内容は大別すると入出力に関する設定とコーディング規約に関する設定に分かれている
  • 入出力に関する設定は当然ながらプロジェクトごとに異なるため、プロジェクトごとに tsconfig.json が必要になる
    • 互換コンパイラ(ESBuild等)も使用する
  • コーディング規約に関する設定はESLintのrulesに相当する
    • こちらはLinterやFormatterが利用する
  • tsconfig.json を参照するLinterに「npm-scriptsやテストで使用するスクリプト」や「 *rc.ts *.config.ts 系の設定ファイル」などもチェックさせたい場合、これらはコンパイルには無関係なファイルなので、コンパイル用の tsconfig.jsoninclude に含めてしまうのは違和感がある
    • 設定によっては「どこからも参照されていない孤立ファイルがある」として怒られることも
    • コンパイル用の tsconfig.json は過不足のないように設定し、Linter用にコンパイル用の設定を継承して調整したものを別途用意するのが妥当と思われる

ルートプロジェクト

@tsconfig/bases に収録されている @tsconfig/node16-strictest-esm を継承し、適宜オーバーライドする。

/tsconfig.json
{
  "extends": "@tsconfig/node16-strictest-esm/tsconfig.json",
  "compilerOptions": {
    "lib": ["esnext"], // enginesで指定したNode.jsが属するバージョンを選択

    // 以下お好みで
    "resolveJsonModule": true,
    "moduleResolution": "node", // resolveJsonModuleをtrueにする場合は継承していても書かないとエラーになる
    "declaration": true,
    "noEmitOnError": true,
    "allowSyntheticDefaultImports": true,
    "checkJs": false
  }
}

サブプロジェクト

ルートプロジェクトを継承し、入出力を設定する。

/packages/package-name/tsconfig.json
{
  "extends": "../../tsconfig.json", // ルートプロジェクトから継承
  "compilerOptions": {
    "outDir": "./dist" // コンパイル先はdistとする
  },
  "include": ["src/**/*"] // ソースはsrc配下に収める
}

6-2. 型チェック

サブプロジェクトのnpm-scriptsに型チェックの設定を追加する。

/packages/package-name/package.json
"type-check": "tsc --noEmit -p ."
  • tsc CLIオプション(公式)
  • コミット時の自動チェックに使用する
  • なお、サブプロジェクトで共通のビルド・テスト関連の依存関係はホイストを利用してルートプロジェクトの devDependencies で賄うこととする
    • typescript jest ts-jest tsup rimraf など
    • それ以外の型定義などは個々のサブプロジェクトの devDependencies に入れる

7. ドキュメンテーション設定

TypeDoc を導入し TSDoc 形式のドキュメンテーションをドキュメントとして出力できるようにする。

shell (root project)
# インストール
$ pnpm add -wD typedoc
  • TSDocはTypeScriptの開発元であるMicrosoft謹製のドキュメンテーション仕様
    • 概ねJSDocから型関係の記述を省略したもの
    • 執筆時のバージョンが 0.14.1 であることからわかるように、まだ正式版ではない
  • 今のところ @microsoft/tsdoc には出力機能がないため TypeDoc を使用する
/packages/package-name/package.json
"typedoc": "typedoc src/index.ts"
  • サブプロジェクトのnpm-scriptsにTypeDoc出力の設定を追加する
/.gitignore
packages/*/docs
  • TypeDocは標準設定では docs ディレクトリに出力するのでgitに無視させる

8. Linter/Formatter設定

ESLintPrettier および各種設定を導入し、文法チェックとフォーマットを設定する。

shell (root project)
# インストール
$ pnpm add -wD eslint eslint-define-config eslint-plugin-n \
  @typescript-eslint/eslint-plugin @typescript-eslint/parser \
  eslint-plugin-import eslint-import-resolver-typescript \
  eslint-plugin-tsdoc eslint-config-prettier prettier
  • eslint-define-config は複雑になりがちな .eslintrc.js をTSの型定義を利用して文法チェックする仕組み
  • eslint-plugin-n は更新が途絶えていたNode.js用プラグインの後継

8-1. ESLint

/eslintrc.cjs
// @ts-check
// ↑ eslint-define-config用
const { defineConfig } = require('eslint-define-config') // eslint-disable-line

module.exports = defineConfig({
  root: true,
  env: {
    es2021: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended', // TypeScript用の設定はこれで全て入る
    'plugin:import/recommended', // eslint-plugin-import
    'plugin:n/recommended', // eslint-plugin-n
    'prettier',
  ],
  plugins: ['eslint-plugin-tsdoc'],
  parserOptions: {
    ecmaVersion: 'latest',
  },
  settings: {
    'import/parsers': { // import用設定
      '@typescript-eslint/parser': ['.ts'],
    },
    'import/resolver': { // import用設定
      typescript: {
        alwaysTryTypes: true,
        project: 'packages/*/tsconfig.json',
      },
    },
  },
  rules: {
    // 必須設定
    // eslint-plugin-node
    'n/no-missing-import': 'off', // 拡張子を省略したimportがエラーになるため無効化
    'n/no-unsupported-features/es-syntax': 'off', // importを使うので無効化
    // eslint-plugin-import
    'import/order': ['error', { 'newlines-between': 'always' }], // エラーになるよう設定することで自動修正が効くようになる
    'import/no-named-as-default-member': 'off', // デュアルパッケージでビルドする場合、この設定に従うと一部のimportが動作しない
    // eslint-import-resolver-typescript
    'import/no-unresolved': 'error', // 解決できないimportをエラー扱いにする
    // eslint-plugin-tsdoc
    'tsdoc/syntax': 'warn', // TSDoc関連は全てwarning扱いにする

    // 以下お好みで
    '@typescript-eslint/no-non-null-assertion': 'off', // Mapが使いづらいため
    '@typescript-eslint/no-implicit-any-catch': [ // try..catchでerrorを扱うため
      'error',
      { allowExplicitAny: true },
    ],
    '@typescript-eslint/no-explicit-any': 'off', // 厳しすぎる
    '@typescript-eslint/no-empty-interface': 'off', // 厳しすぎる
  },
})
/.eslintignore
packages/*/dist
packages/*/docs
packages/*/coverage
packages/*/__tests__/src
packages/*/__tests__/dist
jest.config.cjs
!.*.js
!.*.cjs
!.*.mjs
!.*.ts
  • .eslintignoreに関する公式ドキュメント
  • 以下を無視する
    • 各種出力ファイル(まだ説明していないものは後述する)
    • 敢えて瑕疵のあるソースを含める可能性があるテスト用ファイル類(後述)
    • TSDocに怒られる jset.config.cjs (回避手段検討中)
  • dotファイル類は逆に標準ではチェックされないため「無視リストから外す」記述を行う必要がある
    • dotディレクトリについても同様
    • 公式ドキュメントに動作機序とサンプルが載っている
/package.json
"lint": "eslint --fix **/*.{ts,d.ts,js,cjs,mjs}"
  • ルートプロジェクトのnpm-scriptsに追加
  • .eslintignore が正しく設定できていれば対象拡張子の全ファイルを対象に実行すればよい

8-2. Prettier

/.prettierrc
// お好みで
{
  "singleQuote": true,
  "semi": false
}
/.prettierignore
packages/*/dist
packages/*/docs
packages/*/coverage
packages/*/__tests__/src
packages/*/__tests__/dist
*.md
  • 公式ドキュメント
  • 概ね .eslintignore と同様
  • Markdownのフォーマットはなんか変なので使用しない
    • VSCodeの markdownlint に任せる
      • markdownlint-climarkdownlint-cli2 を入れて自動化してもいいがひとまずスキップ
/package.json
"prettier": "prettier --write --ignore-unknown **/*"
  • ルートプロジェクトのnpm-scriptsに追加
  • .prettierignore が正しく設定できていれば全ファイルを対象に実行すればよい

8-3. EdiotorConfig

/.editorconfig
# お好みで
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
indent_size = 4
trim_trailing_whitespace = false

[*.json]
insert_final_newline = false

9. VSCode

  • WSLで開発するなら必須感がある
  • そろそろ files.excludeGitIgnore が利用できるようになりそう(何年越し?)

9-1. 拡張機能

9-2. フォント

  • お好みで
  • 個人的には PlemolJP を使用

10. precommitフック

Simple Git Hookslint-staged を導入し、コミット時に自動で文法チェック・フォーマット・型チェックが行われるように設定する。

shell (root project)
# インストール
$ pnpm add -wD simple-git-hooks lint-staged
/package.json
{
  // ...
  "scripts": {
    "prepare": "simple-git-hooks"
  },
  "simple-git-hooks": {
    "pre-commit": "pnpm exec lint-staged --concurrent false -c lint-staged.mjs"
  },
  // ...
}
  • 型チェックをステージされたパッケージに絞って実行するためlint-stagedの設定は外に出してJavaScriptで記述する
  • lint-stagedの設定ファイルの外部ファイル化は package.json を長くしたくない場合も有効
/lint-staged.mjs
export default {
  // Prettier
  '**/*': 'prettier --write --ignore-unknown',
  // ESLint
  '**/*.{ts,d.ts,js,cjs,mjs}': 'eslint --fix',
  // TypeScript
  'packages/*/src/**/*.ts': (filenames) => {
    const updatedPackages = new Set()
    const reGetPackageName = /packages\/(?<packageName>.+)\/src/
    for (const filename of filenames) {
      const found = filename.match(reGetPackageName)
      updatedPackages.add(found.groups.packageName)
    }
    return `pnpm --filter ${[...updatedPackages].join(' --filter ')} type-check`
  },
}
  • PrettierとESLintの設定はnpm-scriptsと同一
  • 各パッケージのsrcディレクトリ内のTSファイルがステージされていた場合、ステージされたTSファイルを含むパッケージのみ型チェックを実行する
    • pnpmの --filter オプションでパッケージを指定し、各パッケージの npm-scripts にある type-check を実行している
      • --filter オプションは複数指定して並列実行できる
shell (root project)
$ pnpm prepare
  • 忘れずにフックを有効化する

11. ビルド

11-1. デュアルパッケージ

tsup を導入してESModuleとCommonJS対応のデュアルパッケージでビルドし、サブプロジェクトの package.json をデュアルパッケージに対応させる。

shell (root project)
# インストール
$ pnpm add -wD tsup rimraf
  • tsup公式サイト
  • 依存関係のimportは自動で除外するが、うまく動かない場合は tsup-node コマンドを使用して欲しいとのこと
  • 競合としては unbuild がある
/packages/package-name/package.json
{
  // ...
  "main": "./dist/index.js",
  "module": "./dist/index.mjs", // どこで定義されているか不明
  "types": "./dist/index.d.ts", // TypeScriptによって定義されているフィールド
  "exports": { // Node.js 12 で追加された、パターンへの対応は14から
    ".": {
      "require": "./dist/index.js",
      "import": "./dist/index.mjs",
      "types": "./dist/index.d.ts"
    }
  },
  "scripts": {
    "clean": "rimraf ./dist", // 出力ディレクトリを削除
    "tsup": "tsup src/index.ts --dts --format esm,cjs", // 型定義を出力、ESModuleとCommonJSを出力
    "build": "pnpm clean && pnpm tsup" // 上二つを順次実行
  },
  // ...
}

11-2. ESM専用パッケージ

TypeScriptのESM対応により今後はESM専用のパッケージも増えていくと思われる。依存関係にESM専用パッケージを含むパッケージは自身もESM専用にならざるを得ない。
TSCでESM専用パッケージをビルドする場合は以下のような設定になると思われる。(2022-07-10時点)

/packages/package-name/package.json
{
  // ...
  "type": "module",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  },
  "scripts": {
    "clean": "rimraf ./dist", // 出力ディレクトリを削除
    "tsc": "tsc -p .", // tsconfig.jsonの設定に従ってコンパイル
    "build": "pnpm clean && pnpm tsc" // 上二つを順次実行
  },
  // ...
}
/packages/package-name/tsconfig.json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "module": "esnext",
    "removeComments": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

12. README

  • README.md はnpmパッケージとして公開した際にパッケージのホームとして表示されるため英語で記述する
  • 日本語のREADMEは README.ja.mdREADME.ja_JP.md としておき、冒頭でリンクを貼ることとする
  • 有名所のパッケージ等を参考に最初に規格を統一しておいた方が後々面倒がない
    • とはいえ凝ろうと思えばどこまでも凝ることができるため時間を溶かさない程度で

12-1. バッジ

  • Shields.io
    • 様々なサービスのエンドポイントからSVGのバッジを生成するサービス
      • npmパッケージであれば公開中のバージョンや設定しているライセンス、qualityやmaintenance等のレートなどが表示できる
      • 若干わかりづらいが、サイトを開いた際にフォーカスの当たっている水平線は検索用の入力欄であり、名称やサービスのURLから対応しているエンドポイントを検索できる
    • テキストとアイコン(次項参照)を組み合わせた自由記述での生成も可能
  • Simple Icons
    • Shields.ioで使用できるサービス・技術・ファイルタイプ・ブランド・企業などのアイコン
    • 全アイコンslugリスト

例としてパッケージとしてのnpmのバージョンとライセンスを表示する場合は以下のようになる。

markdown
![npm version](https://img.shields.io/npm/v/npm.svg)
![License](https://img.shields.io/npm/l/npm)

<!-- リンクを貼るなら更に囲む -->
[![npm version](https://img.shields.io/npm/v/npm.svg)](https://www.npmjs.com/package/npm)

npm version MIT

13. Changesets

Changesetsを導入し、対話型CLIで CHANGELOG.md の追記と package.json のバージョンのインクリメントを行う。

shell (root project)
# インストール
$ pnpm add -wD @changesets/cli

# 初期化
$ pnpm changeset init
  • Changesetは標準でpnpmのworkspaceに対応しておりインストールするだけで設定不要で使用できる
  • pnpmの公式ドキュメントにもChangesetsとの連携のページがある

13-1. アップデート対象パッケージの選択とサマリーの入力

shell (root project)
$ pnpm changeset
  • Changesetsによるバージョン管理はコミット等には紐付いておらず、完全に任意のタイミングで実行できる
  • changeset コマンドを実行すると対話式CLIで更新するパッケージの選択と CHANGELOG.md のサマリーの入力を行う
  • 基本的な流れは以下の通り(選択内容やその時点のバージョンによって変化する)
    1. 更新するパッケージの選択
    2. メジャーバージョンを上げるパッケージの選択
    3. マイナーバージョンを上げるパッケージの選択
    4. パッチバージョンを上げるパッケージの選択
    5. サマリーの入力
    6. 入力確認
  • changeset コマンドを最後まで進めるとルートプロジェクトの .changeset ディレクトリにランダムな名前のMarkdownファイルが生成される
    • このMarkdownには対象サブプロジェクトとバージョンアップの種別を示すメタデータ、および CHANGELOG.md に追記される内容(=入力したサマリー)が記録されている
    • 次節の操作でサブプロジェクトの CHANGELOG.md に適切に転記される
  • サマリーを複数入力する場合やパッケージ毎に異なるサマリーを入力する場合は pnpm changeset を複数回実行する
    • 変更が発生する度に pnpm changeset でサマリーを入力しておけば抜け漏れを防げる
    • 生成されたMarkdownを編集しても構わないが、トップレベルの箇条書きの項目を増やしたい場合は pnpm changeset を複数回実行するしかない
  • 次節で行う操作で書き換わった後の CHANGELOG.md を直接編集しても問題ないため、ケースバイケースで使い分けるとよい

13-2. CHANGELOG.mdの更新とバージョンのインクリメント

shell (root project)
$ pnpm changeset version
  • .changeset ディレクトリ内のMarkdownファイルで指定されたメタデータに従って対応するパッケージのpackage.jsonのバージョンをインクリメントする
  • .changeset ディレクトリ内のMarkdownファイルの内容を各パッケージの CHANGELOG.md に追記する
    • 完了すると .changeset ディレクトリ内のMarkdownは削除される

14. デプロイ

pnpmのpublishコマンドを再帰実行フラグ( -r )付きで使用し、バージョン情報を元に更新されたパッケージを全てnpmにデプロイする。

shell (root project)
# 念のため確認したければドライラン
$ pnpm -r publish --dry-run

# ワンタイムパスワードを指定して実行
$ pnpm -r publish --otp <one_time_password>
  • npmに公開中のバージョンと package.json のバージョンが比較され、更新されているもののみデプロイされる
  • Changesetsを適切に使用していればデプロイ対象のパッケージは package.json のバージョンが上がっているため自動的にデプロイ対象になる
  • gitのステージは綺麗な状態にしておく必要がある
    • テスト等の際は --no-git-checks で無効化できるが、普段は有効にして安全なデプロイフローを習慣化した方がよさそう
  • 当然ながらnpmにログインしている必要がある

15. 依存関係の更新

手動で行う場合は定番のCLIツールである npm-check-updates が有用。

shell (root project)
# ncuをサブディレクトリを含めて再帰的に実行する
$ ncu --deep

# ncuの結果をpackage.jsonに反映する
$ ncu -u --deep
  • グローバルインストールしてもいいし pnpm dlx 等でオンデマンドで実行してもよい
  • 対話モードやフィルタ機能、更には更新されたパッケージのアップデート後に自動でテストを実行するモードなどもあり、かなり高機能
  • 細かい条件がある場合は設定ファイル( .ncurc.{json,yml,js} )に書き出しておくこともできる

関連記事

本稿の13-2~14の手順をGitHub ActionsとChangesets Release Actionで自動化した。

ToDo

  • Jest, ts-jest, vitest等でテストを記述しCoverageを取得する → 記事にできるほどの内容にはならなかった
  • GitHub Actionsでテスト、ビルド、およびnpmjs.comへのデプロイを自動化する → 関連記事参照
    • Coverageデータを Codecov に展開する
  • Renovate をDockerでセルフホストし、GitHub Actionsで自動的にPRを発行する
14
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
9