下林明正のブログ

個人的かつ雑多なブログです。

ReactとNext.jsのチュートリアルをやって、高級AIに質問しながら簡単なライフカウンターをつくった

以前の

shimobayashi.hatenablog.com

からほとんど何もやってなかったので全部忘れた。 せっかく正月休みを取ったので再度勉強しようと思って、とりあえずKindle本のハイライトだけ読んだ上で新しくなったReactのチュートリアルをやった。

ja.react.dev

真面目に自分でコードを書きながらやったら数時間くらいかかった気がする。

その後、Create React Appがもう推奨されなくなったことだけは知ってたけど、何かしらのフレームワークを使えという圧をめっちゃドキュメントから感じたので、せっかくなので業務などでも知識が活きそうなNext.jsのチュートリアルもやることにした。

nextjs.org

別にしょぼいコードをちょっと書いてみたいだけなんだが……と思いつつ、がんばってチュートリアルをやった。これは結構時間がかかって、日を跨いだ。

その時の残骸がこれ。

github.com

正直、自分がつくりたいサービスよりも圧倒的に複雑なものをチュートリアルでつくったと思う。

チュートリアルでやったあれ何だっけ?と自分のリポジトリ見ながら記憶を辿れるのは良いと思う。 けど、今はPages RouterってやつとApp Routerってやつの過渡期らしく、チュートリアルで覚えたのはApp Routerだけどちょっと古いコードとかは基本Pages Routerっぽいので、どれくらい知識が活きるのか、という話はありそう。

今更Vercelもはじめて触ったけど確かにこれは楽そう。herokuを初めて触ったころを思い出した。 Next.js自体もなんかクライアントサイドとサーバーサイドのロジックを割とシームレスに書ける感じで次世代開発体験って感じがした。これもRails 2を初めて触ったころを思い出した。

とりあえずこれで自分で何かコードを書いて動かせる状態にはなった。


この間にオンライン飲み会を挟んで、酒に酔った勢いでOpen AIに金を払って高級AIを利用できるようにした。 毎月$20もかかるので、Spotifyの3倍以上のうれしさが欲しい。

ので、せっかくだからChatGPTになるべくコードを書かせてMtGで使うライフカウンターを実装をしてみた。

github.com

life-counter-app.vercel.app

多分ちゃんと動いてるはず。

ライフカウンターという題材を選んだのは、思いついたネタの中では比較的継続的にメンテする可能性がありそうな気がしたから。 別に、通常は既存のアプリを使ったら良いとは思う。

ChatGPTは思ったよりも割とちゃんとコードを書いてくれたけど、手直ししながらじゃないと厳しい感じはした。 サボってあんまりちゃんとドキュメントも確認してないので、もしかしたら変なコードがたくさん入ってるかも知れない。

逆に、デザイン的な作業はあんまりうまくやってくれなかった。 まあもしかしたら、これは自分のスキルの問題もあるかも知れない。

でも全体的には、結構役立ってたと思う。結構待ち時間が長かったりもするので、自分のChatGPTの使い方がこなれてくるともっと役立てられそうな気はする。


技術的な勉強もできたし、ChatGPTの使い方もちょっと分かってきた気がするので、有意義だった気がする(他にも、Wizardry風のゲームをつくるとしたら仮置きのモンスターグラフィックをつくらせてみたいな、とか妄想して画像を吐き出させて遊んだりもしてた)。 なんか全体的に時代の進歩を感じたので、普段取り残されているのだと思う。

気が向いたら以下のようなこともやってみたい

  • ChatGPTにテストも書かせる
  • ChatGPTにコードコメントも書かせる
  • 何らかの方法で背景画像に任意の画像を指定できるようにする
  • 何か良い感じの背景画像をDALL-Eに描かせる

Dependabotが起動するGitHub Actions Workflowを単にre-runしても権限が変わらなくなっていた

shogo82148.github.io

によると過去の公式ドキュメントでは

You can also manually re-run a failed Dependabot workflow, and it will run with a read-write token and access to secrets. Before manually re-running a failed workflow, you should always check the dependency being updated to ensure that the change doesn’t introduce any malicious or unintended behavior.

公式日本語訳:

失敗したDependabotワークフローを手動で再実行することもできます。これは、読み書きできるトークンを持ち、シークレットにアクセスできる状態で実行されます。 失敗したワークフローを手動で再実行する前には、更新される依存関係を常にチェックし、その変更によって悪意ある、あるいは意図しない動作が入り込むことがないようにすべきです。

と書いてあったようだけど、先ほど Automating Dependabot with GitHub Actions - GitHub Docs を確認したところ、

When you manually re-run a Dependabot workflow, it will run with the same privileges as before even if the user who initiated the rerun has different privileges. For more information, see "Re-running workflows and jobs."

となっていて、どうやらre-runしただけでは権限が変わらなくなっていたようだった。

Re-running workflows and jobs - GitHub Docsを読んでも権限の変え方はパッと見つからなかった。


じゃあどうすんの?というところで、当該のPRに空コミットをpushすると変わるんじゃ無いか?という噂をもらったので試してみたところ、確かにGITHUB_TOKENは色々とwriteになり、Secret sourceもDependabotではなくActionsになった。どういう理屈なのかは全然分かってない。

このあたり何が使われているかは、jobの実行ログみたいなところのSet up jobステップを開くとズラズラと書いてあるのでそこから確認できる。 Automatic token authentication - GitHub Docs

ちなみに空コミットはgit commit --allow-emptyでできます。


まあそもそもre-runで突破すること自体が応急処置的だと思うので、本当は根本対処した方が良いんだろうとは思う。 軽く検索しただけでも根本対処の選択肢はいくつか出てくるように見えた。

Reactハンズオンラーニング を読んだ

新しめのJavaScriptとかTypeScriptについては以前軽く勉強していたけど、Reactなど主力コンポーネントたちについては勉強できてなくて最近のフロントエンドの世界の雰囲気が掴めていないことに課題を感じていたので、同僚におすすめされたこの本を読むことにした。

良かった点

  • Reactだけに限らず、新しめのJavaScriptの書き方からはじまってwebpackやBabelなどおおよそ現代的なフロントエンド開発で最低限把握しておくべきコンポーネントたちについてステップバイステップで広く浅く教えてくれた
    • 個人的には、フロントエンドの世界は主要なコンポーネントがたくさんあってめんどくさいな……と思っていたので、ありがたい
    • レビューでは「ハンズオンではない」という意見も多そうだけど、自分にとっては良いハンズオンになったと思う。一方で、たしかに完全な初心者がこの本から学び始めるのは難しいと思う
    • ちなみに、なぜフロントエンドのことを知らない自分が「おおよそ現代的なフロントエンド開発で最低限把握しておくべきコンポーネントたち」を知っているのかというと、業務で関係はあるから
  • ぼちぼち新しい本なので、ぼちぼち新しい情報が載っている
    • 変化の早い分野なので新しい情報であることは重要
    • 初版は原著が2020年7月、翻訳版が2021年8月っぽい

微妙だった点

  • ハンズオンということで当たり前ではあるんだけど、この本独自の重要な知見とかそういうのはあまりなさそうな印象だった
    • なので、時間とやる気がある人ならネットで検索しながら勉強するような形でも特に遜色ない学習はできそう。自分はお金を払ってショートカットした
  • 読んでてあまりワクワクしなかった
    • こういうことができるようになるんだぜ!すごいぜ!みたいなワクワク感は不思議とあまり感じなかった
    • まあこれは僕の感性とか想像力の問題かも

そんなわけで、ある程度プログラミングの経験はあるけどReactや最近のフロントエンドの世界をほぼ知らない人にとっては良い本なんじゃないかと思いました。そうじゃない人にとってはあまり価値は無いかも知れない。

あとは実際にコードを書いていって身につけていけると良さそう。 まだ2d6とか書くとダイスロール結果を仮想リストでたくさん表示してくれるだけのかんたんなおもちゃをテキトーに書いただけの状態。

次は、Demo of String_random.jsで遊ぶのが好きなんだけどいい感じの文字列が出るまでGenerateボタンを連打するのが面倒だと思っていたので、生成結果を仮想リストで大量に表示してくれるおもちゃをつくろうかと思っている(ダイスロールはその布石)。便利そうなのでどっかでホスティングもしたい。

ただ今の所思いついてるネタはそれくらいで、その先はどうしようかなあというところ。

例えば、無料でホスティングしてくれるようなヘッドレスCMSと組み合わせてなんかつくると面白そうだし勉強にもなりそうだなあと思うけど、具体的にそれで何をつくるとうれしいのかというところにアイディアが無い。 普通に考えたらブログなんだけど、別にはてなブログで良いと思うし……。 まあ、ありがちだけど自己紹介ページとかを置き換えるのは良いかも。以前はGitHub Pagesで静的にやってたけど、結局編集が楽じゃないと放置するので今はScrapboxにしてて、しかしこれはこれでそっけないとは思ってた。 元気があったらなんか無料のクラウドデータベースとかと組み合わせてなつかしの一行掲示板とか設置してみたい気もする(すぐに破壊されそう)。

それにしても読むのに時間がかかってしまった。どうせ一気に全部は頭に入らないので、もっと読み飛ばせばよかったと思う。 次に読む本としてはチームトポロジーをすでに並行して読んでいたので、まずはそちらを読み終わりたいところ。

Google App Script(GAS)でスクリプトプロパティをユーザー入力で設定する方法

先に断っておくとGASについて詳しくないです。

APIトークン的な情報をGASで扱いたいけど外部には露出させたくないときに、調べてみるとプロパティストアというやつが使えそうだった。

しかし、どうやら新エディタではプロパティストアへのインターフェースが消滅しているらしく、プロパティストアにセットするコードを書き捨てましょうみたいな情報とか、セットしたいときだけ旧エディタを使いましょうみたいな情報しかパッと見つからなかった。

コードを書き捨てするのは汎用性が低いし、旧エディタもいつまで使えるのかよく分からない(もしかしたら一生使えるのかも知れないが、調べてない)。

ユーザー入力を受け取る何かしらの方法があるだろうと思って調べてみたところ、以下のような方法がありそうだった。

これらを統合すると、以下のようなコードになると思う。

function onOpen() {
  SpreadsheetApp.getUi()
      .createMenu('カスタムメニュー')
      .addItem('APIトークンを設定する', 'showApiTokenPrompt')
      .addToUi();
}
function showApiTokenPrompt() {
  var ui = SpreadsheetApp.getUi();
  var result = ui.prompt(
    'APIトークンを入力してください。',
    'APIトークン:',
    ui.ButtonSet.OK_CANCEL);

  var button = result.getSelectedButton();
  var text = result.getResponseText();
  if (button == ui.Button.OK) {
    const scriptProperties = PropertiesService.getScriptProperties();
    scriptProperties.setProperty('API_TOKEN', text);
  }
}

APIトークンを使いたいときは、

    const scriptProperties = PropertiesService.getScriptProperties();
    this.asanaToken = scriptProperties.getProperty('API_TOKEN');

こういう調子で動くことは確認できた(スプレッドシートの右上に少し待つと「カスタムメニュー」が表示されるので、そこから入力プロンプトを表示させられる)。

ちなみにGASエディタ上でこうした関数を直接実行するとGASが紐付いているスプレッドシートの方でプロンプトが出るようだった。 コード的には当然という気もするけど見えないタブで開いてたので気付かなくて、エディタからは実行できないのかな?とか当初は思ってた。

ただ、これだけだと全員が編集権限を持っている時に他人がGASのコードを書いたり旧エディタを使ったりすることで依然としてAPIトークンを取り出すことができてしまう。 その対策としては、自分以外は閲覧権限までに絞っておくことくらいしか今の所思いついていない(閲覧権限しか無い状態だと、GASのエディタが見えない・そもそもGASが実行されないようだった)。

ちゃんと調べてないけどきっとAPIトークンを隠蔽するもっと適した方法があっても良いはず。何かご存知でしたら教えて下さい。

GAS(Google App Script)を使ってGoogle Spreadsheetの条件に一致するすべてのシートの内容を結合して、さらにSpreadsheet側でQUERY関数とかで絞り込む

ググっても意外とこれだというものを見つけられなかったのでメモっておきます。

要件

  • 1つのスプレッドシート(Google Spreadsheet)に手動でつくられたいくつかのシートと自動的に生成される複数のシートがぶら下がっている
  • 自動的につくられたシートはシート名で識別可能
  • 自動的につくられたシートのすべての行から条件に一致する行だけを抜き出して、適当なシートで一覧したい

結論

スクリプトエディタで以下の関数を定義する。

function getAllTargetRows() {
  var allSheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  var allTargetSheets = allSheets.filter(function(sheet) {
    // シート名が年月日っぽいものだけに絞る
    return /\d{4}\/\d{1,2}\/\d{1,2}/.test(sheet.getName());
  });
  
  var allRows = [];
  allTargetSheets.forEach(function(sheet) {
    var rows =  sheet.getDataRange().getValues();
    allRows = allRows.concat(rows);
  });
  
  return allRows;
}

適当なシートの適当なセルで以下の内容を入力する。

=QUERY(getAllTargetRows(), "select * where Col2 = 'hoge'")

GAS初心者なのでこれがベストかどうかは知らないです。

過程

  • GASを使わなくても関数の組み合わせでなんとかなるのではと思ったけど、すべてのシートを取得するような関数が見つけられなかったので無理そうと判断した
    • シートが増えるペースなどによってはシートが増えたら人間が手動更新するでも良いかも知れない。今回は手動更新したくないなと思った
  • 最初は{'Sheet1'!A:Z;'Sheet2'!A:Z}みたいな書き方でシートを結合してやれないかと思ってGASで対象となるシート名の一覧を返すだけの関数を定義していたけど、よくよく調べてみるとQUERY関数は検索範囲を文字列で受けることはできなさそう(要調査)、INDIRECTは単一の範囲しか受け取れ無さそうで先述のフォーマットの文字列を渡してもエラーになった(要調査)ので、こりゃもうGAS側でやった方が楽だなと判断した
  • GAS側でどこまでやるべきか検討したが、すべてのシートの行を結合して返すところまでやってくれればあとはVLOOKUPなりなんなり使えばよくて、その方が後々融通もききそうなのでそのようにすることにした
  • 結果、上述のGASが出来上がった

実践Terraform を読んだ

周囲でTerraformの機運が高まっているので自分も乗っかるために勉強することにした。 そもそもあまり日本語書籍の選択肢が無いらしく、とりあえずこれを読んでおけばよかろうという雰囲気だった。

本書は、Terraformを使ってAWS上にシステムを構築するノウハウを、200以上のサンプルコードとともに紹介する、Terraform初級者から中級者向け解説書です。ECS Fargateなどのマネージドサービスを中心にアーキテクチャ設計を行い、Terraformで実装します。サンプルコードはGitHubでも公開していますので、手を動かしながら一緒に学びましょう。

ECS+Fargate+RDSで動くような典型的なウェブアプリケーションをTerraformで構築するとしたらこうなるよ、というところからスタートして解説してくれるという流れだった。 タイミング的にそういう仕事をする人も多そうなので、そういう面でも参考になるのではないか。

また、これはTerraformではこう書きます、ここを気をつけてね、ということの繰り返しで大半はTerraformのコードだった。ので、自分は割と読み飛ばしてフムフムなるほどと思うのに使ったという感じだった。 ただ、気をつけポイントが結構多くてこれはやりながらじゃないととてもじゃないけど覚えられないなという気持ちにもなった。 Terraformの使い方とか概念とかで特別難しいところがあるというよりはそういう細かい気をつけポイントを外さないようにするというのが肝要かなと思ったので、そういう意味でもやはりやりながら覚えるのが良さそうと思った。

とりあえずTerraformを触り始めるのに最低限必要な知識は得られたような気分になったので、あとはとにかく機会を見つけて触っていこうと思う。 特に機会が無くても既存のなにかをterraform importしまくって動かすだけでも勉強にはなりそうなので、そういうところからはじめてみるでも良いのか知れない。 まっさらな状態からはじめるよりは難易度は高くなってしまいそうだけど、まあ対象が複雑じゃなければいけるんじゃないだろうか。少なくともそういう気分にはなった。

WSL2のセットアップに関するメモ

WSL2のインストール

docs.microsoft.com

に従って進めたら特に問題なくインストールできた。 ディストリビューションはUbuntuにしといたほうが今後何かと楽できるのかな~と思いつつ、これまで特に深く考えずDebianを使ってきているのでまたDebianにした。

このDebian, 基本的なコマンドがあまり入ってないので困り次第チマチマapt-get installし続けている。

ついでにWindows Terminalとやらをおすすめされていたので、元々putty使い続けてるの辛いなと思っていたので使い始めてみた。

VSCodeとの連携

元々

marketplace.visualstudio.com

をインストール済みだったのでエクステンションのページを見ながら適当にいじっていたらうまくいった。

ただ、WSL側でcode .って打ってもコマンドが見つからないし、調べてもShell Command: Install 'code' command in PATHをVSCodeから実行しろっていう情報が出てくるけどそんなの見当たらなかったのでどうしよう、となった。結局、

github.com

を見て、/mnt/c/Users/username/AppData/Local/Programs/Microsoft VS Code/binにPATHを通して解決した(VSCode側がリモートになにかインストールしたのかと思ってたけど、codeコマンドに関してはそういうわけではないようだった)。

vim

WSL側でvimを立ち上げたときに色々とセットアップしたあとでもおかしな色になってしまって、ターミナル自体は256色出せてるように見えるしvimも256色モードにもなってるみたいだしなんでだろう?と思っていたところ、これはどうやら利用しているテーマ特有の問題?っぽくて、以下の操作をすることで解消できた。

github.com

知らんがな、という気分にはなったけど仕方がない。

感想

大したこと何もしてないけど、今の所WSL2自体は何不自由なく動いているように見える。 Windowsのファイルシステムがデフォルトでマウントされてるのも便利そう。

Virtual Boxを使っていた頃はVMの起動やらファイルシステムのマウントやらがめんどくさかったので、イメージが壊れたのを機に移行して良かったかも知れない。