TypeScript における SyntaxKind の調べ方
個人開発で TypeScript Graph というものを作っています。
TyeScript Graph はTSファイルの依存関係を視覚化するものです。 その機能に加えて、コードの複雑度を計測して表示できたら良いなと考え、現在色々試しています。
そのために、構文をどう解析して複雑度の計測処理を組み立て行くのかのヒントとするため、各構文要素の SyntaxKind を調べています。 良い感じに調査できるコードを書けたので残しておきます。
シンプルな解析コード
const a = false ?? true; を TypeScript Compiler API を用いて分解し、それぞれの SyntaxKind を見ていきます。
import ts from 'typescript'; const sourceFile = ts.createSourceFile( 'sample.ts', 'const a = false ?? true;', ts.ScriptTarget.ESNext, ); const visit = (depth: number) => (node: ts.Node) => { console.log( [depth, node.getText(sourceFile), ts.SyntaxKind[node.kind]].join('|'), ); ts.forEachChild(node, visit(depth + 1)); }; console.log('depth|code|SyntaxKind'); console.log('--|--|--'); visit(0)(sourceFile);
実行すると以下がコンソールに出力されます。
| depth | code | SyntaxKind |
|---|---|---|
| 0 | const a = false ?? true; | SourceFile |
| 1 | const a = false ?? true; | FirstStatement |
| 2 | const a = false ?? true | VariableDeclarationList |
| 3 | a = false ?? true | VariableDeclaration |
| 4 | a | Identifier |
| 4 | false ?? true | BinaryExpression |
| 5 | false | FalseKeyword |
| 5 | ?? | QuestionQuestionToken |
| 5 | true | TrueKeyword |
| 1 | EndOfFileToken |
※マークダウンが壊れることがあります。
その他のツール
こういうツールもありました。
npm link で開発中の CLI アプリをシンプルに実行可能にする
ソフトウェア開発と認知負荷
これは ゆるWeb勉強会@札幌 Advent Calendar 2023 - Adventar の7日目の記事です!
自分はフロントエンドエンジニアをしています。
2023年は色々な場面で認知負荷と戦いました。 UI/UXデザイン、コード、マネジメント、色々なことをうまくやるには認知負荷を下げることが大事だなぁと感じたので、その辺りについて書きます。
コードと認知負荷

アプリケーションやコードの複雑さと戦うために、我々はコードの mentenability を上げます。 コードは、modulability や testability や readability など様々な特性を良い方へと改善することで、結果的に maintainability が良くなります。
modulability や testability は、コードの持つ特性としては比較的観測しやすい特性と言えそうです。 modulability であれば「他のロジックと共通的に使用できている」など、testability であれば「信頼できるテストが書かれている」など、実際に modulable である testable であることがコードに現れます。
readability などは understandability (理解容易性)に抱合されると思いますが、これらはどうでしょう。 これによる影響が現れるのは人の頭の中・心の中であったりする上、人によって差があり、実際にどの程度の理解容易性があれば良いのか、どうすれば理解容易と言えるのかは、指標を定義しにくいものです。「これで充分」と言えるゴールがない。Linter などを利用すれば、ある程度 readability を良くできます。とはいえ、アプリケーションの本質的な複雑さや、本質的でないものの難しいために複雑になってしまっている箇所は多くあり、そういった部分の認知負荷を下げるのは困難です。また、特に他人の書いたコードは、どんなに understandability が良い状態であったとしてもそれ以外の人にとっては(特に初見では)認知負荷が高いです。
コードの認知負荷を軽減するためにしたこと
初見のコードについては特に、コードを読み始める前の段階で何らかの取っ掛かりがあれば、認知負荷を軽減することができると考えました。
自分は普段、フロントエンドのコードベースを相手にしており、TypeScriptを使っています。 TypeScript のコードベースの認知負荷を下げるため、 TypeScript Graph というファイル間の依存関係グラフを mermaid のダイアグラムで視覚化するツールを作りました。 これによって、コードベース内のプログラムの構造についての認知負荷を下げることができます。

また、コードの認知負荷が最も影響するタスクとしてレビューがあります。 レビューでは他人の書いたコードを読まねばならず、認知負荷との戦いになります。 そこで、PullRequest で変更のあったファイルの周辺の構造のみを TypeScript Graph で視覚化してPRのコメントに投稿する、danger-plugin-typescript-graph という danger.js のプラグインと、 delta-typescript-graph-action という GitHub Action を作りました。この2つはどちらも同じ機能を実現していますが、 danger-plugin は GitHub Action が使用できない環境のために実装しています。

自分の業務では danger-plugin-typescript-graph を使用していますが、導入したのが最近であるため効果の程はまだわかりません。 個人的には、PullRequestのレビュー時の初期認知負荷軽減に役立っていると感じています。 また、依存の方向など構造に誤りが無いかを容易にチェックできる点も良いです。
マネジメントと認知負荷

なぜウォーターフォールがうまく機能しないのか。 色々な理由があるでしょうが、その一つに認知負荷があると考えています。
新規開発や大きな変更を計画的に行うため、何ヶ月もかけて念入りに要件定義や設計を行ってから開発(実装タスク)を開始することがあります。
このようなプロジェクトでは、設計書がプログラマーの手に渡る頃には、認知負荷が高い状態になっていますね。
そして、認知負荷が高いプロジェクトでは、考慮漏れや実装漏れなどなど不具合が多発します。
大きなプロジェクトの認知負荷を軽減するためにしたこと
数ヶ月かけて行うようなプロジェクトでは、プロジェクトをユースケースに分解して、優先度の高いもの(コスパの良いもの)からリリースするようにしました。 ユースケース一つであればやることは明確で、仕様も設計も実装も、それらのマネジメントも、分解前と比べて認知負荷は低いものとなっているはずです。
アジャイル開発のように常にユースケースごとにインクリメントしながら開発したいところですが、それをするには常にエンジニアに話が来るよりも前に対処せねばなりません。 この問題を解決するには、現場全体のプロセスも改善する必要があります。 自分の環境はまだそこには至れておらず、これから改善していきたいと考えています。
タスクマネジメントの認知負荷を軽減するためにしたこと
タスクが多くあり、しかも複雑に絡み合っている場合があります。
自分もそういう状況になりました。その際、プロダクトバックログや看板ではなく、 mermaid のフローチャートダイアグラムでタスク管理をしてみました。
例えば以下のような感じです。(だいぶ細かいタスク粒度ですが)

これにより、各タスクの繋がりやクリティカルパスが視覚的に理解できるようになり、次にどのタスクに取り掛かるべきかを開発者自身が判断できるようになります。 また、単なるリストよりも状況を把握しやすく無用な不安を取り除く効果がありました。
💭 こういう見せ方を実現している良い感じのタスク管理ツールがあればぜひ教えてください!
UI/UXデザインと認知負荷

エンジニアは、UI/UXデザインについて無知な状態でも、デザイナーと議論しなければならないことがあります。 UI/UXデザインについて無知であると、「わかりやすい」「わかりにくい」など感覚的な意見しか述べることができず、根拠を持って議論することができないでしょう。
自分もそのような状況に陥りました。 そこで、デザインについての知識をつけるべく「UX デザインの法則」という本を読んでみたのですが、これがとても良い書籍でした。
書籍では10の心理学的法則を紹介し、それぞれがどのようにUXに関わるかが説明されています。 また、書籍の元になっている Home | Laws of UX では他にもいくつかの心理学的法則が紹介されています。
認知に関わる心理学的法則
Home | Laws of UX で紹介されている心理学的法則うち、直接的に認知に関わる法則を列挙します。
ヤコブの法則
ユーザーは他サイトで多くの時間を費やしているので、あなたのサイトにもそれらと同じ挙動をするように期待している。
フィッツの法則
ターゲットに至るまでの時間は、ターゲットの大きさと近さで決まる。
ヒックの法則
決定にかかる時間は、とりうる選択肢の数と複雑さで決まる。
ミラーの法則
普通の人が短期記憶に保持できるのは、7(±2)個まで。
実はこの「マジカルナンバー 7」は重要ではない。重要なのは、人の短期記憶は、文字であれ単語であれ「何らかのチャンクを」7(±2)個記憶できること。つまり、コンテンツを小さなチャンクに分けることで、ユーザーの認知負荷を下げられる。とのこと。
美的ユーザビリティ効果
見た目が美しいデザインはより使いやすいと感じられる。
フォン・レストルフ効果
似たものが並んでいると、その中で他とは異なるものが記憶に残りやすい。
共域の法則
明確に定義された境界線を持つエリアを共有している要素は、グループとして認識される傾向がある。
近接性の法則
近くにあるもの、近接しているものは、同じグループとして知覚されやすい。
人は曖昧なイメージや複雑なイメージを、できるだけ単純な形として認識し、解釈する。
類似性の法則
人間の目は、デザインの中の似たような要素を、たとえそれらの要素が離れていても、完全な絵、形、グループとして認識する傾向がある。
連続性の法則
視覚的に繋がりのある要素は、つながりのない要素よりも関連性が高いと認識される。
シリアル・ポジション効果
ユーザーは、シリーズの最初と最後の項目を最もよく覚えている傾向がある。
UI/UXデザインの認知負荷軽減のためにしたこと
これらの心理学的法則に鑑みると、自分が関わるプロダクトにおいて自分が気になったのは以下2点でした。
- プロダクトにおける複数の異なる概念それぞれを、UIコンポーネントの見た目で識別できない
- プロダクトにおける同一の概念が、プロダクト内の複数の箇所で異なる見た目で提供されている
これには、プレグナンツの法則と類似性の法則が関わっていると考えました。
プロダクト内の複数の異なる概念それぞれはUIコンポーネントの見た目で識別できるべき
プロダクト内のすべての概念に適用するのは難しいので、これは極論かとは思います。 しかし少なくとも重要な概念は見た目で、しかも瞬時に、認知可能であると良さそうです。
以下は、異なる概念A,B,Cを表すデザインです。

それぞれ少し違います。
そしてプレグナンツの法則 は以下のようなものです。
人は曖昧なイメージや複雑なイメージを、できるだけ単純な形として認識し、解釈する。
よく見ると異なる見た目ではありますが、プレグナンツの法則によればこれらのイメージは単純な形で認識されてしまい、ユーザーは「同じ概念である」または「同じような概念である」と誤認してしまうことでしょう。
そのため、以下のように明らかに異なるものであることを強調した方が良いはずです。

プロダクトにおける同一の概念はプロダクト内のどこでも同じ見た目であるべき
これも極論です🙏🏻
シチュエーションによって異なる見た目とすることが有効な場合もありますよね。
ただ、類似性の法則は以下の通りで、
人間の目は、デザインの中の似たような要素を、たとえそれらの要素が離れていても、完全な絵、形、グループとして認識する傾向がある。
これに鑑みると、プロダクト内では極力、同じ概念のものを同じ見た目で提供することで認知負荷を下げることができると言えます。
現在自分は、これら心理学的法則に則ったUIにすべきという考えを啓蒙しています。 そしてその考えは賛同を得られており、そう遠くない未来にはプロダクトの認知負荷を下げられると確信しています。
おわりに
UI/UXに関わる心理学的法則、認知に関わる心理学的法則をお読みになられたエンジニアの方は、すでに気づいているのではないでしょうか。
認知に関わる心理学的法則はコードの認知にも関わるのです。
この記事で紹介した心理学的法則のほとんどがUI/UXに限定されない「汎用的な心理学的法則」であるため、人の認知に汎用的に適用できます。 これらの法則を意識してコードベースを構築し、コードを書くことで、より認知負荷の低いコードベースとなり、メンテナビリティの良いコードベースとなるはずです。
そしてまた、マネジメントの認知負荷低減がコードベースの認知負荷低減につながる可能性があること、さらにはUIの認知負荷低減がコードベースの認知負荷低減につながる可能性があることにも気づいているのではないでしょうか。
マネジメント面で認知負荷が低ければ、複雑な事を考えずにすみ、コードをシンプルに保てるのではないだろうか。
UXを良くするためにUIの認知負荷を下げると、自然と概念ごとにUIコンポーネントが作られ、概念ごとにAPIができるのではないか。 そして、それはデザインシステムとなり、ドメイン知識となり、フロントエンドもバックエンドも認知負荷の低い、整理されたコードベースとなるはずではないか。
理想論ではあるかもですが、自分はソフトウェア開発の活動全般において、認知負荷を下げることが大事なのだと確信しています。 今後も認知負荷を下げるためにはどうすれば良いのかを学び、より良い開発者体験を実現していきたいと考えています。

Graph DB を調べる
以下のエントリーで TypeScript プロジェクトにおける依存関係を可視化するツールを作りたいと書きました。
まずは Graph DB についてちょっとだけ調べました。 気軽さを重視したい。
Amazon Neptune
Amazon Neptune は、グラフアプリケーションの構築と実行を容易にする、クラウド向けに構築されたフルマネージドデータベースサービスです。Neptune は、組み込みのセキュリティ、継続的なバックアップ、サーバーレスコンピューティング、および AWS の他のサービスとの統合を提供します。
- 非機能要件が凄まじく充実している。適当に使うのに向いているだろうか?
- Gremlin Client で接続できる
- どのくらい料金がかかるのかわからないが、個人で適当に使う分には高いということはなさそう?
Neo4j
- docker イメージが用意されていて適当に使うのには良さそう
- JavaScript Driver が用意されている
- neo4j にロックインしてしまうのは嫌だ
- Gremlin Server を介して Gremlin で操作することも可能らしいが、面倒そう。
- Gremlin Server の docker イメージ があるのでこれを使うと楽?
Azure CosmosDB
- Gremlin Client で操作する
- 自分が知っている限りでは、 Azure Functions と組み合わせて気軽に始めることができて良い。
まとめ
Amazon Neptune を使ってみようかな。もう少しドキュメント読んでみる。 気軽に使えると良いけど。
ローカルでは Neo4j と Gremlin Server にしてみても良いかもしれない。楽ならば。
typescript-graph を本格的に作り込みたい
TypeScript のプロジェクトにおいて、PRのレビューの際に、レビュー対象のファイルなどの構造についてやその変化をより把握しやすくするために、tsc を使用して各ファイルや変数や関数などの関係をグラフデータに落とし込んで参照できるようにしたいと考えています。
以前、ブラウザ上でローカルの TypeScript プロジェクトのファイルの関係性を可視化するツールを作りました。
👇GitHubPages で公開してます 🔗 typescript-graph

これにはいくつか問題点がありました。
- 小さいプロジェクトならまだしも、大きなプロジェクトとなると、有益な情報を抽出するのにかなり苦労する。
- ブラウザ上では tsc を動かせないので、適当な解析結果しか出せない。
- UI が適当なので、僕以外動かせない
ただ、この程度のものでもコードレビューで問題点を見つけたり共有することができ、成果を得ることができました。
コードレビュー時に、誰でも簡単に利用でき、正確な情報を出力することを目標として、作り込みを行いたいと考えています。
具体的には、
- tsc を使って正確な解析結果を得る
- GraphDB を使って検索などブラウジングをしやすくする
- ブランチ同士の差分を可視化する
- ローカルのCLIでサクッと確認できる or CI でサクッと動いてPRに投稿する(かなり曖昧)
進め方は、適当ですが以下のように考えています。
- GraphDB について調べる(何が使いやすいか)
- ローカルプロジェクトに対し、TSC を使用してグラフデータを作るスクリプトを作る
- グラフデータを GraphDB に登録するスクリプトを作る
- GraphDBに登録したグラフデータを可視化するツールを作る
- 現在使用中のブランチとベースブランチの差分を可視化するツールを作る
あと、今までブログの更新頻度がかなり低かったので、なにかやる度に何か書こうと思う。
続くと良いが。
2022 ナンプレアプリ開発まとめ

これはドワンゴ Advent Calendar 2022 の13日目の記事です。 qiita.com
自分は普段、ドワンゴの教育事業部にてN予備校のWebフロントエンドを開発しています。 この記事では趣味で個人開発しているナンプレアプリについて、今年の活動を報告します。
ナンプレアプリ numberp とは
ブラウザで動作するナンプレ(数独)のアプリです。 ゲーム画面はもちろん、問題の生成処理も自作しています。 全てフロントエンドで完結していて、バックエンド処理はありません。
- GitHub URL
numberp は「ナンバーピー」と呼んでいます。ナンプレっぽいドメインを探していたときに見つけたのがこれでした。
Vue から React へ移行した
モチベーション
2021/12 にドワンゴ教育事業部のWebフロントエンドエンジニアとして N予備校の開発に携わることとなりました。N予備校では React を使用してフロントエンドを構築しています。
自分は React の経験がなかったため、キャッチアップを目的としてナンプレアプリを Vue から React へ移行することとしました。
移行にあたって発生した作業
主に以下の作業を行いました。
- コアロジックのパッケージ化
- React でのアプリケーション構築
コアロジックのパッケージ化
ナンプレの問題を解く・生成するコアロジックをパッケージ化し、それ以外の部分を React で再構築することで React への移行を実現しました。
コアロジックは以下のリポジトリで管理しています。 https://github.com/ysk8hori/numberplace-generator
パッケージは GitHub Packages で公開しています。 https://github.com/ysk8hori/numberplace-generator/pkgs/npm/numberplace-generator
パッケージ化前から境界を設けていた
もともと、Vue のプロジェクトの中で以下のように境界を設け、依存が双方向にならないよう整理していました。
当時は、境界を設けることで「認知負荷の抑制」や「テスト容易性向上」などの効果を感じていました。そして、当時は実感を得られていませんでしたが、境界には区切られた部分のパッケージ化が容易となる効果もあります。
モノリスとして作っている段階では、境界で区切られたコンポーネントをパッケージ化する必要性も、フレームワークを乗り換える必要性も感じることはなかなかできません。しかしながら時間が経つと、技術の変遷や自身の成長がきっかけとなり、アーキテクチャやフレームワークを変更したくなるものです。
今回、Vue から React へ乗り換えることとなり、この効果を体感することができました。
パッケージを分けるだけでは不十分
境界を設けていたことによって、コアロジックのパッケージ化は簡単に行えましたが、「使用方法が難しい」という問題が残ってしまいました。というのも、問題の生成を行うために DI コンテナに何らかのインスタンスを登録したり、問題生成のためにいくつかのクラスを生成して使用する必要があったりと、凝った作りになっていました。生成した問題の構造も複雑でした。
このままでは、作った自分でも利用するのが難しい状態です。
そこで、関数を一つ呼び出すだけで問題が生成されるように変更しました。
import { generateGame } from "@ysk8hori/numberplace-generator"; // Generate standard 9x9 size number place game. const [puzzle, solved] = generateGame({ width: 3, height: 3 }); console.log(pazzle.toString()); /* 9, , , , , ,4, , 6, , ,4,9,2,3,5, 2, ,4, ,6,3, ,1,9 , , , , , ,5,6,2 5, , , , , , ,3, ,3, ,9, , ,7, ,1 7, , , ,5,6, ,9, ,2, ,3, , ,6,7, 3, , ,7, ,1,2,4, */ console.log(solved.toString()); /* 9,5,3,8,1,7,4,2,6 6,8,1,4,9,2,3,5,7 2,7,4,5,6,3,8,1,9 8,9,7,1,3,4,5,6,2 5,1,2,6,7,8,9,3,4 4,3,6,9,2,5,7,8,1 7,4,8,2,5,6,1,9,3 1,2,5,3,4,9,6,7,8 3,6,9,7,8,1,2,4,5 */
ちなみに返却される puzzle や solved の型は以下の Game です。かなりシンプルかと思います。
/** Numberplace game. */ export type Game = { cells: Cell[]; toString: () => string; }; /** One cell. */ export type Cell = { /** Position of cell. */ pos: Position; /** Answer filled in cell. If not filled in, undefined. */ answer: undefined | string; }; /** Position of x and y. */ export type Position = Readonly<[number, number]>;
内部構造に詳しくなくても利用可能な IF とすべき
ですよね。
React でのアプリケーション構築
コアロジックはパッケージ化し流用することができましたが、UI やゲームの状態管理機能などは全て作り直しています 🤣
特筆すべきことはそんなにないのですが、あえて挙げれば...
Vue で作成した際には、ユーザーの操作やゲームの管理については Application という領域を設けて Vue と切り離して実装していたのですが、今回はそれをしませんでした。 というのも、今回は React のキャッチアップが目的だったので、できるだけ React の機能を使って作ろうと考えたためです。
機能追加
盤面の種類を増やした
もともと Vue で作っていた頃には、好きなサイズを指定して問題を生成&プレイ可能にしていました。 今回は複数のサイズに加え、盤面の対角線上のマスでも一意にする必要がある問題や、背景色の異なる四角いエリアでも一意にする必要がある問題を生成&プレイ可能としました。
マテリアルデザインのアイコンで遊べるようにした
同じドワンゴアドベントカレンダーで、ニコ生フロントエンドのミスケンさんが以下の記事を書かれていました。
そこで紹介されていたのが smart-svg というSass製SVG爆速表示ライブラリ。
自分が作っているナンプレアプリは各マスに表示する数字などにSVG画像を使用していましたので、早速使ってみました。 性能は測っていないのですが...使いやすかったので、ついでに数字の代わりにマテリアルデザインアイコンで遊べるようにしてみました。
改善点
改善した点をあげていきます。
UI をロックしない! そう、 WebWorker ならね!
問題生成処理は 1 スレッドで CPU パワーを使って行いますが、大きな問題だと問題が生成されるまでに数秒から十数秒、時には数十秒かかります。そして、何も考えずにブラウザで JavaScript を実行する場合は基本的にメインスレッド(UI スレッド)で動くので、問題生成を行うとその間 UI をロックしてしまいます。
そこで、今回は WebWorker を使用して別のスレッドで問題生成処理を行い、UI をロックしないよう改良しました。

vite を使用しているのですが、 Web Worker が非常に簡単に使えて体験が良かったです。
オフラインでも遊べる!
スマホにアプリとしてインストールして使いたかったのと、オフラインでも使用可能とするために PWA にしています。 ServiceWorker は何にも使用していませんが。
性能向上した
問題生成処理の性能を上げました。これにより、16×16 などの大きな盤面の問題の生成が可能となりました。良かったね(白目) とはいえ、生成にかなり時間を食うことがあります。また、その間CPUパワー使いまくるので、気になる方は諦めてください...。 まだまだ改善の余地があります...。
運用面の改善
リリース、テスト、ライブラリのアップデートなど、今後長くアプリケーションを運用していけるよう整えました。
CI 充実化
CI を充実させ、unit test の他、 Chromatic での VRT(Visual Regression Testing) も行うようにしています。また、タグを作成した際には自動で本番環境へデプロイします。開発体験がとても良いです。
| タイミング | CI で行うこと |
|---|---|
| PR 作成 | 単体テスト storybook のビルド |
| Develop → Main への PR 作成 | 単体テスト Chromatic での VRT |
| リリースタグ作成 | 本番環境へのデプロイ |
なお、PR 作成時に storybook のビルドだけを行っていますが、どこかに公開したりはしていません。これは、 renovate によって storybook 関連ライブラリのアップデートが行われた際に storybook のビルドが失敗するようになった場合に検知できるようにしています。
Chromatic で VRT
Chromatic は割とすぐに無料枠を食いつぶしてしまうので、default ブランチからリリース専用のブランチへマージする PR でのみ VRT を行うようにしています。見た目が絶対に変わらないであろう PR や、コミットコメントの修正をコミットした際などに高価な VRT を行うのはもったいないですね。 Chromatic は最高です。
renovate によるライブラリの自動アップデート
Renovate を導入しライブラリの最新化が自動で行われるようにしています。CI が通ればデフォルトブランチへのマージを自動で行う設定としているので、ほとんど手間が必要ありません。Renovate 導入には CI でのテストを充実させる必要があります。 Renovate は最高です。
Sentry でエラーの監視を可能とした
Sentry を入れてみました。 自分と、自分の親戚のおじさんくらいしか使用していないのでそんなに意味はないですが・・・。
失敗談
Rust の WebAssembly にしようとして挫折した
性能向上のため Rust でも問題生成処理を作成したのですが、以下の理由により日の目を見ることはありませんでした。
WebAssembly で使用不可能な crate に依存していた
Rust で作ればなんでも WebAssembly として動かせるものと思い込んでいました・・・。 そうではなさそう。未だによくわかっていないので、また今度チャレンジするつもりです。
そんなに性能上がらなかった
なんなら若干遅いくらいでした。どうして・・・。 問題生成処理は割と単純な繰り返し処理が多いので JavaScript でも十分に性能が出るのかもしれません。
まとめ
Vue から React への移行においては、境界をうまく設けて、フレームワークやライブラリへの依存箇所を限定し、依存の方向を整理し疎結合な作りとしておくことで、アプリケーションの寿命が伸びるのだということを実感することができました。
また、業務で使う技術のキャッチアップや、逆に今は業務で使っていないが使えそうな技術のキャッチアップもできて、良い個人開発ができました。
来年はもう一度 Rust にチャレンジしたいな〜。
GitHub Repository に公開した package を GitHub Actions でインストールする
状況
僕は、numberplace-generator という数独の問題を生成するパッケージを GitHub Actions に公開しています。
そして、numberplace-generator で生成した問題を遊ぶ numberplace という SPA を作っています。
numberplace は numberp という名前で Amazon S3 でホスティングしています。
何をしようとしていたか
GitHub Actions を使って、numberplace の main ブランチに push が行われたときには本番環境へデプロイし、PullRequest が作られた際にはテスト環境へデプロイするようにしたいと考えていました。
問題点
npm ci で 401 になってしまいます。
詳細
以下は npm ci 時のログです。 chokidar のワーニングが出ているところを鑑みるに、途中まで npm ci は動いているのですが、途中から E401 の権限のエラーが発生しています。 おそらく GitHub Packages で公開している numberplace-generator のインストールで失敗しているものと考えました。
... npm WARN deprecated chokidar@2.1.8: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies npm ERR! code E401 npm ERR! Incorrect or missing password.
エラーの全容はこちら
解決方法
以下の Workflow でビルドまで成功しました。(S3 へのデプロイは現時点ではまだ失敗)
name: Deploy for test on: pull_request: types: [opened, reopened, synchronize] jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Use Node.js uses: actions/setup-node@v3 with: always-auth: true node-version: 16.14.0 registry-url: 'https://npm.pkg.github.com' scope: '@ysk8hori' - name: Install Dependencies run: npm ci env: NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - name: Build run: npm run build # ...
ポイント
ポイントは以下の2つでした。
actions/setup-nodeをする- 環境変数
NODE_AUTH_TOKENを指定する
actions/setup-node では setup-node の設定と NODE_AUTH_TOKEN を元に .npmrc ファイルを生成するようです。
詳細は下記公式サイトに記載があります。
あとがき
.npmrc なしで開発できていたので、ここで詰まることは想定外でした。VSCode で GitHub Packages にログイン済みだったのだろうとは思いますが。
npm にパッケージを公開していればこの設定は不要だったのかと考えると、 GitHub Packages での公開はあまり得しないように思いました。そのうち npm での公開に切り替えるかもしれません。


