Nx + shipjs で npm package を複数管理する

Nx では oss 向けの workspace を作成できるが、ドキュメントが分かりづらかったので自分なりにまとめる。本記事の内容はこのプロジェクトを作成するときに分かったことをまとめたもの。
GitHub - tyankatsu0105/css-houdini: CSS Houdini
現在の Nx は 11.0.20。

なお、

  • sample-org という organization の scoped package な node ライブラリを管理する
  • npm package は全て同じバージョニング

を前提とする。

workspace の作成

npx create-nx-workspace@latestで workspace を作成する。

? Workspace name (e.g., org name)     sample-org
? What to create in the new workspace oss               [an empty workspace with a layout that works best for open-source projects]
? Use Nx Cloud? (It's free and doesn't require registration.) No

これでpackagesが root にある workspace が作成される。各パッケージはここに配置されていく。

nx.json のworkspaceLayoutlibsDirしか使わないので、それ以外は消していい

続けて、@nrwl/nodeを入れて node library を generate できるようにする。

npm i -D @nrwl/node --save-exact

そして generate する。

npx nx g @nrwl/node:library sample-package1 --publishable --importPath="@sample-org/sample-package1"

publishable オプションで npm publish する前提の library を generate できる。 このとき、importPath をつけることが必須になるので、@<orgName>/<packageName>とする。

これでpackages/sample-package1/package.jsonの name に importPath で指定した library が作成される。

shipjs を導入する

shipjs は

  • CHANGELOG.md の生成
  • package.json の version のカウントアップ
  • release タグの生成
  • release PR の自動生成
  • build と npm publish の実行

などができる、npm publish に関するあれこれをサポートしてくれるパッケージ
Introduction | Ship.js

shipjs は monorepo のサポートもしているので、Nx の workspace も大丈夫。しかし、パッケージごとのバージョニングはサポートされておらず、全て統一バージョンになってしまうので注意。

npx shipjs setup

質問に答えていくと設定が完了するので、.env をローカルに作成して、shipjs prepareが実行できるようにする。

.env
GITHUB_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx

shipjs の config ファイルを作る必要があるので、root に置く。

ship.config.js
const getPackagePath = (dir) => {
  const splittedDir = dir.split('/');
  const packagePath = [
    splittedDir[splittedDir.length - 2],
    splittedDir[splittedDir.length - 1],
  ].join('/');
  return { packagePath };
};

const getDistPackagePath = (packagePath) => {
  const distPackagePath = `../../dist/${packagePath}`;

  return { distPackagePath };
};

module.exports = {
  monorepo: {
    mainVersionFile: 'package.json',
    packagesToBump: ['packages/*'],
    packagesToPublish: ['packages/*'],
    updateDependencies: false,
  },
  buildCommand: () => 'nx run-many --target=build --all --maxParallel=3',
  publishCommand: ({ defaultCommand, tag, dir }) => {
    const { packagePath } = getPackagePath(dir);
    const { distPackagePath } = getDistPackagePath(packagePath);

    return `cd ${distPackagePath} && ${defaultCommand} --access public --tag ${tag}`
  }
};

これで、準備が完了。

publish する

諸々ライブラリの作成が進んでリリースするタイミングがきたら、

npm run release

shipjs prepareを実行する。

質問に答えると PR が作成されるので、諸々確認して merge する。
PR はこんなかんじ。
chore: release v0.2.0 by tyankatsu0105 · Pull Request #24 · tyankatsu0105/css-houdini · GitHub

これで packages 配下全てを build して、publish する。

Tips

srcRootForCompilationRoot で build するときの directory を変更する

workspace.jsontarget.build.options.srcRootForCompilationRootを指定すると、そこの中身をビルドして root に配置してくれる。package.jsonmainsrc/index.jsからindex.jsにしたいみたいなときに便利。
workspace.jsontarget.build.options.mainも変更しておくのを忘れずに。