- 投稿日:
五年くらい公私ともにTypeScriptを書いているが、なんか最近限界を感じたので吐露していく。半分くらいNode.jsに対する不満かもしれない。内容としてはただの書きなぐりの愚痴。
非同期制御多すぎ
async
とawait
を書く面倒さや、それが漏れた時のふるまいの微妙さ。
例えば終わらないJestというのは日常的に見る光景だと思うし、実務をしていてPromiseの例外ハンドリングをしていなかったからサーバーがクラッシュしたというのも聞いたことがある。
これはチーム開発において、チームの意識や技術レベルが低いと容易に引き起こされる問題であり、その面で考えると非常に微妙な言語仕様だと思う。
なんだかんだC10K問題はコンテナ大量起動で回避する世界線になってしまっている気がするので、標準が非同期である必要性はあんまないよねみたいな感触は抱いている。C10K問題回避のために非同期にしてるんだよね?そうだよね?(正直非同期にしたいのであればユーザー側がPromiseに包めばいいと思う)
Node.jsのLTS短すぎ
GitHubやAWSですら最新版への追従は遅れがちなくらいLTSが短い。2年くらいしかない。2年ごとにフルリグレッションなんてやってられない。不可能だ。
しかも破壊的変更を平気で入れてくるし、v16は予定より早くサポートが打ち切られた。正気とは思えない。
実行環境多すぎ
Node.js + 各種トランスパイラにDenoにBunに…他にも最近なんか出ていた気がするが忘れた。なんでこんなにあるのか…。
TypeScriptの型パズルに疲れた
型パズルするために開発してるんじゃないんだよ…。
型が信用できない
実務だと意図しているのか、していないのか型を騙している光景を多々見るが、これによって型が信用できない状態になっていることが往々にしてあり、割と殺意を覚える。なにも信用できない。何のためにこの言語使ってるんだっけ…?ナウいから?
CLI作る時のハマりどころが多い
nvmのようなバージョン管理システムを使っているとグローバルインストールが通常ユーザーとスーパーユーザーで別れる問題があり、sudo
実行が前提のCLIで誤った動作確認をしてしまいやすい。
他にもnpmjsで公開しているパッケージをnpm installしたものと、開発中に実行するのでは、意識してないと実行方式が変わってしまい、上手く動かないことがある。気を付ければいいのはそうだが、割とムカつく。
具体的にはshebang書いて無くて動いてなかったとかそういうやつ。基本的にjsファイルを直に叩いて動かす文化ないじゃん…。
ビルド工程が面倒くさい
ビルドに関してtscやswc、esbuildのように様々なトランスパイラが存在するほか、webpackやvite, esbuildといったバンドラの存在があり、バージョンアップで振る舞いが変わるので面倒くさい。TypeScript開発は膨大なパッケージに依存しがちで、何か不具合が起きた時に原因の特定が困難だが、根幹に破壊的変更が来ると割と精神的にきつい。
先ほどswcでビルドしたところ/dist/index.jsとして出てくるはずのものが、/dist/src/index.jsになっていた。正直こんなのはデグレードだ。ありえない。
もちろんこれはfix: pass in --strip-leading-paths to swc when buildingで対応されているのだが、正直しんどい。
てかNode.js系のパッケージって息を吸うようにデグレ起こすような気がするのは私だけだろうか。以前はNewRelicがプリフェッチしまくるバグとかあった気がするし、Jestのモックが正常に動かないケースにも遭遇したことがある。
エコシステムが壊れかかっている
TypeScriptでLintをするとなればESLintがデファクトスタンダードだと思うが、v8で導入されたFlat configがあまりにも不案内で、v9.7が出た今でさえ対応できていないPluginがゴロゴロある。むしろできてるほうが珍しい。
私も三日くらい格闘したが、いずれかのプラグインが不整合を起こすか、不整合を起こさなくなったと思ったら無視設定が機能しなかったり、今度はLint機能そのものが死んだりで手に負えないのであきらめた。v9に上げると使えなくなるプラグインもあるので、v8.57.0で旧式の設定を使うのがきっと無難だと思うが、これがいつまで続くのかという話だ。恐らく追従できないプラグインはサポートのやる気をなくすだろう。
Prettierも破壊的変更を繰り返しフォーマットをガタガタにしてくる困りものだ。こいつもv3が出て一年たった今でもVSCodeの公式拡張機能がv3に対応していない。一応ローカルにv3を入れれば最低限動くが、ネイティブで動いてほしいケースもあるので、そういう場合は運用に難儀する。過去に対応させようと手を付けてみたが、最新版はテストが落ちる状態になっていて、もはや救いがなかったので投げた。
正直ESLintとPrettierが死にかけている現状を見るに、もうなんというか駄目じゃないかという気がしてくる。
Biome.jsなんてのもあるが、あれはMarkdownのフォーマットができないとか、ESLintのプラグインをサポートしてないとかで使い勝手がいまいちよくないのだ。まぁ、MarkdownのフォーマットだけPrettier使うとかはアリか。
あとがき
とはいえ、フロントエンド開発において、ブラウザではJavaScriptしか動かないのでTypeScriptをの利用はやむを得ない側面もある。やむを得ないのだ。ただ、それ以外ではもう使う必要ないんじゃないかなと思うし、正直Node.js界隈が魔境というか地獄過ぎて、あんまり関わり合いになりたくないという思いが日に日に強くなっている今日この頃だ。
- 投稿日:
WSL上のUbuntuで動作するnginxでHTTPSに対応したサーバーを作る方法。実機でも同様の手順でいける
確認環境
Env | Ver |
---|---|
nginx | nginx/1.18.0 (Ubuntu) |
mkcert | v1.4.4 |
Ubuntu | 20.04.6 LTS |
Windows 11 | 22621.3880 |
手順
- Windows側にmkcertを入れる
- mkcertで証明書を作る
mkcert sandbox.test
- 以下のpemファイルが生成される
sandbox.test.pem
sandbox.test-key.pem
- 生成されたpemファイルを
/etc/nginx/conf.d/ssl/
に移動する /etc/nginx/conf.d/sandbox.test.conf
を作成し、以下のような記述をするserver { listen 443 ssl; client_max_body_size 100m; server_name sandbox.test; ssl_certificate conf.d/ssl/sandbox.test+1.pem; ssl_certificate_key conf.d/ssl/sandbox.test+1-key.pem; access_log /var/log/nginx/sandbox.access.log; error_log /var/log/nginx/sandbox.error.log; # ファイルホスト用 # location / { # root /usr/share/nginx/html/sandbox; # index index.html; # try_files $uri /index.html =404; # } # APサーバーへのリバプロ用 location ~ ^/.*$ { rewrite ^/.*$ / break; proxy_set_header X-Request-Path $request_uri; proxy_set_header X-Host $host; proxy_pass http://127.0.0.1:9999; } # fastcgi用 location ~ \.php$ { root /usr/share/nginx/html/sandbox; fastcgi_pass unix:/run/php/php8.0-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }
- nginxを再起動する
sudo service nginx restart
他の端末に証明書を撒く方法
mkcertのRoot CAをエクスポートして他の端末に突っ込めば、他の端末でもpemが流用できる
- 投稿日:
あると何かと便利だよねというので。
確認環境
Env | Ver |
---|---|
PHP | 8.0.29 |
サンプルコード
取り敢えずファイルをアップロードするだけのコード
<?php
if ($_FILES['image']) {
move_uploaded_file($_FILES['image']['tmp_name'], 'files/'. $_FILES['image']['name']);
} else {
?>
<html>
<body>
<form action="upload.php" enctype="multipart/form-data" method="POST">
<input type="file" name="image">
<button>upload</button>
</form>
</body>
</html>
<?php
}
- 投稿日:
ブラウザのタブがバックグラウンド状態になっているとJSの実行が止まることがあり、そうするとsetInterval()
が死ぬので、これを回避する技。
結論としてはWeb Worker APIのWorkerインターフェースを使うことで解決できる。
確認環境
Env | ver |
---|---|
Microsoft Edge | 126.0.2592.87 |
サンプルコード
/**
* @param {() => void} cb 実行するコールバック
* @param {number} interval 実行間隔
* @returns 停止用の関数
* */
const createWorkerInterval = (cb, interval) => {
const src = "self.addEventListener('message', (msg) => { setInterval(() => self.postMessage(null), msg.data) })";
const wk = new Worker(`data:text/javascript;base64,${btoa(src)}`);
wk.onmessage = () => cb();
wk.postMessage(interval);
return wk.terminate;
}
- 投稿日:
Node.jsのスクリプトを適当に書き次のようなWorkflowsを記述することで実行できる。勿論Dockerイメージを作ってそこから立ち上げることもできるので好みの問題。直に呼べる分、取り回しは楽だと思う
name: hoge
description: hoge
inputs:
GITHUB_TOKEN:
description: 'Workflowsを実行するリポジトリのGITHUB_TOKEN'
required: true
on:
workflow_call:
runs:
using: node20
main: dist/index.js
inputs:
やoutputs:
を記述すれば入出力の引数も定義できる。
inputs.GITHUB_TOKEN
について
これを書いておくとoctokitを使ってGitHubのAPIを叩けるようになる。普通は何かAPIを叩くはずなので書いておいた方が良い。
以下は一例。
const github = require('@actions/github');
const core = require('@actions/core');
async function run() {
const token = core.getInput('GITHUB_TOKEN');
const octokit = github.getOctokit(token);
const { data: pullRequest } = await octokit.rest.pulls.get({
owner: 'octokit',
repo: 'rest.js',
pull_number: 123,
mediaType: {
format: 'diff'
}
});
console.log(pullRequest);
}
参考
- Metadata syntax for GitHub Actions (docs.github.com)
- @actions/github