Open6

lerna + yarn

空の状態から

terminal
touch .gitignore # 適当に作成する
yarn init

package.jsonをworkspace用に改造(licenseは消しても消さなくても)

package.json
--- a/package.json
+++ b/package.json
@@ -1,8 +1,9 @@
 {
   "name": "<project-name>",
-  "version": "1.0.0",
-  "main": "index.js",
   "repository": "<git repository>",
   "author": "YutaUra <yuuta3594@outlook.jp>",
-  "license": "MIT"
+  "private": true,
+  "workspaces": [
+    "packages/*"
+  ]
 }

lernaの設定

terminal
# lerna をインストールしていない場合は
# yarn global add lerna
lerna init

# パッケージのバージョンを個々に管理したい場合は
# lerna init -i

するとlerna.jsonができるので以下のように変更

lerna.json
--- lerna.json
+++ lerna.json
@@ -1,6 +1,6 @@
 {
-  "packages": [
-    "packages/*"
-  ],
+  "packages": ["packages/*"],
+  "npmClient": "yarn",
+  "useWorkspaces": true,
   "version": "0.0.0"
 }

node のバージョン固定させときましょう。(M1 Mac使ってるので結構新しいけど、バージョンはなんでも良い)

terminal
nodenv local 16.0.0

huskyを入れる。(なんかhuskyってここ最近で結構変わってるんで、公式のドキュメント見た方がいいかも)

terminal
npx husky-init && yarn

prettier, eslint, lint-staged, typescript, typesyncをrootに入れる。(workspaceのrootに入れる場合のWフラグと、devDependencyに入れる用のDフラグを忘れずに)

terminal
yarn add -WD prettier eslint lint-staged typescript typesync

typesync使ってる人いますか?結構いいですよね〜

こんな感じに変更させれてるはずです。

package.json
--- a/package.json
+++ b/package.json
@@ -6,7 +6,19 @@
   "workspaces": [
     "packages/*"
   ],
+  "scripts": {
+    "prepare": "husky install",
+    "postinstall": "typesync"
+  },
   "devDependencies": {
-    "lerna": "^4.0.0"
+    "@types/eslint": "^7.2.10",
+    "@types/prettier": "^2.2.3",
+    "eslint": "^7.26.0",
+    "husky": "^6.0.0",
+    "lerna": "^4.0.0",
+    "lint-staged": "^11.0.0",
+    "prettier": "^2.3.0",
+    "typescript": "^4.2.4",
+    "typesync": "^0.8.0"
   }
 }

CI周りの設定していく

terminal
touch .prettierrc

僕の好きな設定

.prettierrc
{
  "semi": false,
  "singleQuote": true,
  "trailingComma": "all"
}

tsconfig

terminal
touch tsconfig.strict.json

全てのモノレポで厳密な型チェックをしたいので、共通の設定をくくり出します

tsconfig.strict.json
{
  "compilerOptions": {
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true
  }
}

eslintは各モノレポで設定でいいかな〜今後変えるかもです

npm-run-all入れます

terminal
yarn add -WD npm-run-all

そして、こんな感じでpackage.jsonを修正

package.json
--- a/package.json
+++ b/package.json
@@ -8,7 +8,16 @@
   "scripts": {
     "prepare": "husky install",
     "postinstall": "typesync",
+    "pre-commit": "lint-staged && run-p pre-commit:*",
+    "pre-commit:format-check": "lerna run format-check --parallel",
+    "pre-commit:lint-check": "lerna run lint-check --parallel",
+    "pre-commit:type-check": "lerna run type-check --parallel"
+  },
+  "lint-staged": {
+    "packages/*/src/**/*.{ts,tsx}": [
+      "prettier -w"
+    ]
   },
   "devDependencies": {
     "@types/eslint": "^7.2.10",
@@ -17,6 +26,7 @@
     "husky": "^6.0.0",
     "lerna": "^4.0.0",
     "lint-staged": "^11.0.0",
+    "npm-run-all": "^4.1.5",
     "prettier": "^2.3.0",
     "typescript": "^4.2.4",
     "typesync": "^0.8.0"

そして、huskyに設定をします

.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn pre-commit

この状態でコミットとかするとちゃんとpre-commitが動いてるのがわかります。

いよいよライブラリを作成していく
lernaを使って対話的に作成することができます。

terminal
lerna create @<org-name>/<package-name>

どうせ変更するので全部YESって答えていいと思います
そして、package.jsonをこんな感じに変更します。

packages/<packages-name>/package.json
{
  "name": "@<org-name>/<package-name>",
  "version": "0.0.0",
  "author": "YutaUra <yuuta3594@outlook.jp>",
  "main": "dist/index.js",
  "types": "dist/index.es.d.ts",
  "module": "dist/index.es.js",
  "directories": {
    "lib": "src",
    "test": "__tests__"
  },
  "files": [
    "package.json",
    "README.md",
    "dist"
  ],
  "scripts": {
    "format-check": "prettier -c 'src/**/*.{ts}'",
    "lint-check": "eslint",
    "type-check": "tsc --noEmit"
  }
}

packages/<package-name>/libを削除して、packages/<package-name>/src/index.tsを作成

tsconfig.jsonを作成します。rootに作成したtsconfig.strict.jsonを継承する形で好きなように作ってください。rollupとかでビルドしていくのでお好みでpathのエイリアスとか設定しちゃってください。
この辺の設定とかはtsconfig.lib.jsonみたいな形で括り出してもいいと思います。(てか多分そうするかも)

packages/<package-name>/tsconfig.json
{
  "extends": "../../tsconfig.strict.json",
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "declaration": true,
    "emitDeclarationOnly": true,
    "isolatedModules": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "baseUrl": "./",
    "declarationDir": "dist",
    "paths": {
      "~/*": ["src/*"]
    }
  },
  "include": ["src/**/*.ts"]
}

とりあえず、index.tsを適当に作成します。

packages/<package-name>/src/index.ts
export const greet = (name: string): void => {
  console.log(`Hello, ${name}!`)
}

ビルドに必要なものをインストールします

terminal
yarn add -WD @babel/core @babel/preset-env @rollup/plugin-babel @rollup/plugin-typescript rollup rimraf
ログインするとコメントできます