Closed101

create-babylon-app v1.0に向けたアプデ作業

にー兄さんにー兄さん

実はちょいちょい使われている?(検索でヒットする?)かもしれないので、
このさいちゃんとメンテしていきたいなぁという気持ちがあったのである

というのと、自分も使うんだけど正直まだ使い勝手は良いわけではないので
自分で使うようにちゃんとやっていきたい

にー兄さんにー兄さん

まぁあとフォーラムの中で
「これを公式docsに載せよう!」「いや、このツールはまだ便利じゃないから」
という会話があったりしたので
あ~これはちょっと悔しいな……って気持ちになった

にー兄さんにー兄さん

OSS作って公開して、需要があるのにリリースしてハイおしまい!はちょっとね......。
胸張っておススメできるくらいにこだわって作りたいよなぁ

にー兄さんにー兄さん

やりたいこと

  • テンプレートの拡充と将来的なテンプレ追加に対応できる選択アルゴリズム
  • CLIの動作をモダン化
    • cittyへの移行
    • inquireのために対応してるcjsでの実行をvite-nodeにする
  • CI/CD, Test
  • 公式ドキュメントWebサイト
にー兄さんにー兄さん

v1.0ではモダン化は対応したいけど
Babylon.js 7対応とか、便利なテンプレート追加とか、CICD対応とかは0.2で出しちゃってもいいかも

にー兄さんにー兄さん

nuxiを見ていたら、どうやらunjs/gigetというものを使ってテンプレートをダウンロードしているらしい
ほぇ~~すげぇ使ってみたい

あと、ビルドはunjs/unbuild、tsの実行にはunjs/jitiが使えるらしい

なんかunjsが強すぎる

にー兄さんにー兄さん

とりあえずnuxt/cliの中身を解析してみることにした
ファイル構成自体はすごいシンプルな感じなので読めそう

にー兄さんにー兄さん

nuxi、というか割とそういう系のCLIは
コアな機能をimportして使うことができるようになっている
ん-、nuxiを使ったCLIを作ろうと思った時に便利なのかなぁ

にー兄さんにー兄さん

なのでpackage.jsonではこんな感じの表記になっている

{
  ...
  "type": "module",
  "exports": {
    ".": "./dist/index.mjs",
    "./cli": "./bin/nuxi.mjs"
  },
  "types": "./dist/index.d.ts",
  "bin": {
    "nuxi": "./bin/nuxi.mjs",
    ...
  },
  "files": [
    "bin",
    "dist"
  ],
  ...
}
にー兄さんにー兄さん

まぁ今回は通常のスクリプトで使う用のimportは考えなくていいかなぁ、たぶん使わんだろうし

現状のcreate-babylon-appでは/index.cjs/dist/index.jsをrequireして使ってるけども
nuxiでは、/bin/nuxi.mjs/dist/index.mjsのrunMainを呼び出しているようだな

にー兄さんにー兄さん

build.config.tsはunbuildのコンフィグなのかなぁ
packagejsonのbuildコマンドにはunbuildとしか書かれていないので、
おそらくデフォでunbuildは./dist/index.mjsを生成する感じかなぁと思った

にー兄さんにー兄さん

それで、/bin/nuxi.mjsはもともと設置しているので、それをCLIでは呼び出すようにしていると

にー兄さんにー兄さん

nuxiのコードリーディングを進めている

どうやら、cittyは普通にコマンドライン引数とかコマンドをいい感じにしてくれるやーつらしい
defineCommandというやつでコマンドを定義できるんだけど、そこにサブコマンドとかargsを定義できる

nuxiの場合は以下のような構造

└─ nuxi <-------------------- main command
    ├─ init <---------------- sub command
    │    └─ args
    │        ├─ --dir
    │        ├─ --template
    │        └─ ...
    ├─ dev <----------------- sub command
    │    └─ args
    │        └─ ...
    ├─ info <---------------- sub command
    └─ ...

subであれmainであれ、これらはcommandというオブジェクトで、
commnadはネスト出来る仕組みらしい

にー兄さんにー兄さん

commandで実行する処理はrunメソッドで定義でき、
多分だけど、ctx.dataで親コマンドのデータを受け取れそう

にー兄さんにー兄さん

対話型インターフェースはconsola.promptがやってくれそう
実質inquireの代替かな?

にー兄さんにー兄さん

何となくわかってきたので、テスト用のCLIを一回作ってみようと思う

にー兄さんにー兄さん

testbedプロジェクトで作業中

unbuildを導入してtsをビルドし、それをCLIとして実行するまでのテスト環境を整備

src/main.ts
const helloLog = () => {
  console.log("Hello");
};

export const runMain = helloLog;
src/index.ts
export * from "./main"
bin/cli.mjs
import { runMain } from "../dist/index.mjs";

runMain();
package.json
{
  "name": "unjs-stack-cli-testbed",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.ts",
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "unbuild",
    "start": "node ./bin/cli.mjs"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "unbuild": "^2.0.0"
  }
}
pnpm build && pnpm start

これでHelloが出力される

にー兄さんにー兄さん

Biomeを導入してみたら、マジで手軽すぎてビビった
https://biomejs.dev/ja/

にー兄さんにー兄さん

ホントに、公式サイトに書いてあるようなことしかしてないけど
一瞬でlintとformatができるようになった

にー兄さんにー兄さん

テキトーにこんな感じでスクリプトを登録したら動く

    "lint": "biome lint ./src",
    "format": "biome format --write ./src",
    "check": "biome check ./src",
    "check:write": "biome check --write ./src"
にー兄さんにー兄さん

cittyもconsolaも試した
ついでにjitiによるtsの実行もできるようになった、最高だな

にー兄さんにー兄さん

gigetのexample
githubの特定のディレクトリからもいけるんや!これはいいな

# Clone /test directory from main branch
npx giget@latest gh:unjs/template/test
にー兄さんにー兄さん

giget、めっちゃよいな・・・

    const templateName = await consola.prompt("Which template do you use?", {
      type: "select",
      options: ["vite-ts", "vite-js"],
    });

    const doInstall = await consola.prompt("Install dependencies?", {
      type: "confirm",
    });

    const { dir, source } = await downloadTemplate(
      `gh:drumath2237/create-babylon-app/templates/${templateName}`,
      { install: doInstall, dir: `test-temp/${name}` }
    );
    console.log(dir, source);
にー兄さんにー兄さん

GitHub Actionsのジョブの分け方の作法があまり分かっていなくて、ちょっと手が止まってる感じがする

にー兄さんにー兄さん

今やりたいことって、たぶん単一のyamlファイルで実現できると思うし
多分それがいいような気はしている
というのも、リリース時にはやっぱりPRのジョブでしているようなビルドステップが必要なので
DRY的に重複したジョブの記述したくないなぁという

にー兄さんにー兄さん

構造としては

  • PRコミットPush時
    • 各種セットアップ
    • 静的テスト
    • ビルド
  • mainrelease/*ブランチマージ時
    • PRコミット時のジョブを待機
    • npm publish

ジョブやステップの記述はできるけど
イベントが駆動する条件設定の方法がわからないな

にー兄さんにー兄さん

いったん、こんな感じにyamlを書いてみた

name: Build and Publish
on:
  pull_request:

jobs:
  build_and_test:
    runs-on: ubuntu-22.04
    strategy:
      matrix:
        node-version: [20]
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: 9
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "pnpm"
          registry-url: https://registry.npmjs.org
      - name: Install dependencies
        run: pnpm install
      - name: Static test
        run: pnpm run check:ci
      - name: Build
        run: pnpm run build

  release:
    runs-on: ubuntu-22.04
    needs: build_and_test
    # releaseブランチからmainにPRがマージされたら
    if: |
      github.event.pull_request.merged == true
      && github.base_ref == 'main'
      && startsWith(github.head_ref, 'release/')
    steps:
      - name: Publish
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
にー兄さんにー兄さん

GitHub でBranch Protection Rulesを設定
今のリリース戦略であればmainに直Pushしなくてすむので、直Pushを抑制する

にー兄さんにー兄さん

そしてlerna-liteのallowBranchを設定したところ
mainブランチでlerna versionコマンドが使えなくなってよかった

lerna.json
{
  "$schema": "node_modules/@lerna-lite/cli/schemas/lerna-schema.json",
  "version": "0.1.5",
  "npmClient": "pnpm",
  "packages": ["./"],
  "command": {
    "version": {
      "allowBranch": ["release/*"]
    }
  }
}

にー兄さんにー兄さん

あら、lerna versionは作動したけど
そのあとのnpm publishのジョブが起動しなかった

これはおそらく、releaseジョブがbuildジョブに依存しているけど
buildジョブはpull_reqしか指定していないから
マージ時に動作しなかったんだな

にー兄さんにー兄さん

ピエ・・・releaseフローは起動したのに失敗してる・・・なんで・・・

Run npm publish
  npm publish
  shell: /usr/bin/bash -e {0}
  env:
    NODE_AUTH_TOKEN: ***
npm error code ENOENT
npm error syscall open
npm error path /home/runner/work/create-babylon-app/create-babylon-app/package.json
npm error errno -2
npm error enoent Could not read package.json: Error: ENOENT: no such file or directory, open '/home/runner/work/create-babylon-app/create-babylon-app/package.json'
npm error enoent This is related to npm not being able to find a file.
npm error enoent

npm error A complete log of this run can be found in: /home/runner/.npm/_logs/2024-07-04T15_42_02_824Z-debug-0.log
Error: Process completed with exit code 254.

何だこのパス /home/runner/work/create-babylon-app/create-babylon-app/package.json

にー兄さんにー兄さん

上記はおそらく、checkoutするようにしたら大丈夫になった!

けど別のエラー。これが全くわからない

npm notice
npm notice 📦  create-babylon-app@0.2.0
npm notice Tarball Contents
npm notice 11.4kB LICENSE.md
npm notice 780B README.md
npm notice 48B index.cjs
npm notice 1.4kB package.json
npm notice 29B templates/test/index.js
npm notice 64B templates/test/package.json
npm notice 348B templates/vite-js/index.html
npm notice 1.5kB templates/vite-js/main.js
npm notice 264B templates/vite-js/package.json
npm notice 161B templates/vite-js/style.css
npm notice 371B templates/vite-ts/index.html
npm notice 299B templates/vite-ts/package.json
npm notice 1.4kB templates/vite-ts/src/createScene.ts
npm notice 517B templates/vite-ts/src/main.ts
npm notice 161B templates/vite-ts/src/style.css
npm notice 38B templates/vite-ts/src/vite-env.d.ts
npm notice 446B templates/vite-ts/tsconfig.json
npm notice Tarball Details
npm notice name: create-babylon-app
npm notice version: 0.2.0
npm notice filename: create-babylon-app-0.2.0.tgz
npm notice package size: 7.0 kB
npm notice unpacked size: 19.2 kB
npm notice shasum: 80b73168539a58e258d913b6c0326370f8046748
npm notice integrity: sha512-+h8ZyUGGBsDuj[...]jrFEif20nAXog==
npm notice total files: 17
npm notice
npm error code ENEEDAUTH
npm error need auth This command requires you to be logged in to https://registry.npmjs.org/
npm error need auth You need to authorize this machine using `npm adduser`

npm error A complete log of this run can be found in: /home/runner/.npm/_logs/2024-07-04T16_24_55_275Z-debug-0.log

GitHubの設定でRepository SecretsにNPM_TOKENを設定しているし、
それをymlでNODE_AUTH_TOKENに環境変数として設定しているのに、なぜだ?

にー兄さんにー兄さん

一回GitHUb Actionsでnpm publishする方法を勉強しなおすか
しかし、ここはまえと変更していないはずなんだけどなぁ

TOKENも、classicだけどAutomationで作り直したんだが

にー兄さんにー兄さん

おっ、どうやらそうだったらしい

そして、余計なことした(興味本位でつけたProvenance)ことにより、エラーで失敗
これはどこかの記事で見たな、なんかpermissionを与えなくちゃいけないらしい

2024-07-04T16:51:31.4722126Z npm error code EUSAGE
2024-07-04T16:51:31.4733888Z npm error Provenance generation in GitHub Actions requires "write" access to the "id-token" permission
にー兄さんにー兄さん

やった~~~リリースフロー動いた!!

いやはや、ここまでGitHub Actionsで苦戦することになるとは……
やっぱりちゃんと基礎を勉強しないとだめだな
割と雰囲気でいじっちゃってるから

にー兄さんにー兄さん

まずい、リリースしたは良いものの、これ実行するとエラーになる

Error: Cannot find module './dist/index.js'
Require stack:
- C:\Users\2237k\AppData\Local\pnpm-cache\dlx\umiaujrtdk34onymzibtmx4bui\1907ed94d3c-36d8\node_modules\.pnpm\create-babylon-app@0.1.6\node_modules\create-babylon-app\index.cjs
    at Module._resolveFilename (node:internal/modules/cjs/loader:1048:15)
    at Module._load (node:internal/modules/cjs/loader:901:27)
    at Module.require (node:internal/modules/cjs/loader:1115:19)
    at require (node:internal/modules/helpers:130:18)
    at Object.<anonymous> (C:\Users\2237k\AppData\Local\pnpm-cache\dlx\umiaujrtdk34onymzibtmx4bui\1907ed94d3c-36d8\node_modules\.pnpm\create-babylon-app@0.1.6\node_modules\create-babylon-app\index.cjs:2:1)
    at Module._compile (node:internal/modules/cjs/loader:1241:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Module._load (node:internal/modules/cjs/loader:938:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    'C:\\Users\\2237k\\AppData\\Local\\pnpm-cache\\dlx\\umiaujrtdk34onymzibtmx4bui\\1907ed94d3c-36d8\\node_modules\\.pnpm\\create-babylon-app@0.1.6\\node_modules\\create-babylon-app\\index.cjs'
  ]
}
にー兄さんにー兄さん

今見たら、確かにnpmのcodesにはdistが含まれておらず
これはリリースフローでビルドが行われないからな気がした
うわ~やっちまった、明日対応だな

にー兄さんにー兄さん

これはたぶん、今日散々苦労したneedsを使わずに
buildとreleaseでワークフローを分けることになりそうだな・・・

にー兄さんにー兄さん

ジョブ間でファイルの引継ぎはされないので、そう勘違いしたことがミスにつながったっぽい

にー兄さんにー兄さん

結局のところ、いい感じにワークフロー自体を分離することで解決しました
やはりリリース時にdistが生成されていなかったのが問題だったようで、普通に解決した

にー兄さんにー兄さん

0.1.7以降初の開発作業 ゆるほめLTでの発表があったので、それの資料準備などをやっていた

直近は、いったんビルド基盤をtsc->unbuildに移行して
.mjsを実行する形を目指すよ

にー兄さんにー兄さん

unbuild、なぜか依存関係に廃止されたぱっけーじなのかな、があるらしく
ちょっと気になりますね

にー兄さんにー兄さん

mjsは出力されたけど、実行はできなかったな

にー兄さんにー兄さん
import { copy, readJSON, writeJson } from 'fs-extra';
               ^^^^^^^^
SyntaxError: Named export 'readJSON' not found. The requested module 'fs-extra' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'fs-extra';
const { copy, readJSON, writeJson } = pkg;
にー兄さんにー兄さん

esm版をインポートしてみたら、今度は別のエラーが出た

にー兄さんにー兄さん

あ~たしかに、fs-extraでは./esm.mjsではなく./esmでexportしているので
其れで動かなかったらしいな

にー兄さんにー兄さん

一応unbuildでも動くようにしたけど、最終的にfs-extraとか排除したいので
大部分はあまり意味はなかったかもしれない

とはいえ、unbuildに移行してmjsで動くようになったのは何となく嬉しい

にー兄さんにー兄さん

citty, jiti, consolaへの移行作業を進めていく

jitiへの移行はたぶん秒で終わるので対応しちゃいたいな
cittyとconsolaの順番は悩ましいな

しかしcittyのほうが変えるものが多いので、最初にconsolaのほうがいいかも

にー兄さんにー兄さん

cittyに移行する際に、最初に簡単な対応をまずやってしまって
そのあとにちゃんと設計されたやり方をしたい

すなわち、最終的に得たい入力からコマンドライン引数を定義したり
テンプレート選択のロジックをスマートにしたい

にー兄さんにー兄さん

基本的な置き換えはすぐできたな
あまり迷わずすぐ着手すべきだった

ということでcottyやconsolaなどが加わったバージョンがmainにマージされた

にー兄さんにー兄さん

次は便利テンプレートの追加をやっていきたい
考えていることは以下

  • どんなテンプレを追加するのかを考えたい
    • まぁでも、simple、playground、libraryかなぁ
    • libraryはちょっと難易度高めというか、なにが妥当なテンプレとなるのかも含めて検討が必要そう
  • どうやって進めようか
    • gigetを使ってテンプレDLするようになったので、いったんGitHubに上げる必要がある
    • テンプレ追加のPRをマージして、そのあとにテンプレ選択の実装PRを作る感じかなぁ
    • ホントはもっとスマートな方法がいいな
  • この後の話
    • コマンドライン引数
    • ドキュメント整備
にー兄さんにー兄さん

template選択のための再帰関数の実装ができた!

これであらゆる形式のテンプレート構造にも対応できそうだ

にー兄さんにー兄さん

まだ選択部分が粗削りなんで

  • コードのリファクタ
    • 主にどこにテンプレートなどを書くか
  • テンプレートの色付け

などの対応をしてマージする

にー兄さんにー兄さん

コマンドライン引数について考える
create-babylon-appでは最終的に、コマンドライン引数を使ってすべての設定項目を網羅できるようにしたい
なぜかというと、もしかしたら(CIとかで?)機械的にプロジェクトを生成したい人がいるかもしれなくて、そうなったときに対話式の入力は相性が悪いので

にー兄さんにー兄さん

とはいえ、今収集している情報って

  • プロジェクト名
  • テンプレート名
  • インストールするか?

なので、これらを設定できれば良い

にー兄さんにー兄さん
project name --name -n string
template name --template -t string
do install --install -i boolean
にー兄さんにー兄さん

terminalizerを使うにせよ、普通に動画を撮るにせよ
pnpm create babylon-app を使うには現状をリリースしないといけない
あれ、そうなんだっけ

にー兄さんにー兄さん

リリースしないとダメかなぁと思ったけど、強引な方法でキャッシュを上書きするという技で乗り越えられそうかも

にー兄さんにー兄さん

pnpm packで作成したパッケージアーカイブで、
C:/Users/<user>/Appdata/pnpm-cache/dlx/xxxxxxx/xxxxx/node_modules/create-babylon-appの中身を差し替えるというもの

いったん普通に実行してローカルキャッシュが作成されたらそれを上書きする

にー兄さんにー兄さん

よし、目標を達成できたので、
いったんこのスクラップはクローズします

このスクラップは3ヶ月前にクローズされました