Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Prettier 3.0 の VSCode 拡張対応における技術的な意思決定~VSCode 拡...

sosukesuzuki
September 06, 2023
1.8k

Prettier 3.0 の VSCode 拡張対応における技術的な意思決定~VSCode 拡張で dynamic import が動かない~

VSCode 拡張で dynamic import が動かない

sosukesuzuki

September 06, 2023
Tweet

Transcript

  1. 自己紹介 SUZUKI Sosuke • Ubie 株式会社プロダクト開発エンジニア • サイボウズ フロントエンドエキスパートチーム •

    筑波大学 情報学群 情報科学類 B3 • Prettier メンテナー • Babel コミッター @__sosukesuzuki @sosukesuzuki
  2. 目次 1. Prettier 3.0 リリース 2. Prettier 3.0 はすべてが ECMAScript

    Modules 3. prettier-vscode における ECMAScript Modulesの問題 4. 言語サーバーの開発と挫折 5. worker_threads による回避策 5. まとめ
  3. Prettier 3.0 リリース trailingCommaのデフォルト値がes5からallに Internet Explorer のサポート終了により、主流のウェブブラウ ザのすべてがtrailingComma: allのJavaScriptを解釈できる ようになった。

    日本語とラテン文字の間にスペースを入れない Markdownのフォーマットで、日本語 /中国語とラテン文字の 間にスペースを挿入しないようになった。今回のリリースの中 で最も賛否が分かれるであろう変更。 .gitignoreのファイルを無視する .prettierignoreだけでなく.gitignoreのファイルもデフォルトで 無視するように。 --ignore-path=.prettierignoreをつければ今 まで通り。 *.d.tsファイルが本体パッケージに含まれる ライブラリとして使うときの型定義が本体パッケージに含まれ るようになった。 @types/prettier を別途インストールする必要 はもうない。 https://prettier.io/blog/2023/07/05/3.0.0.html Prettier 3.0 におけるユーザー影響が大きい変更4選
  4. CommonJS から ECMAScript Modules へ Prettier 3.0 はすべてが ECMAScript Modules

    • Prettier 2.x まではソースコードは CommonJS で書かれていた • Prettier 3.0 からはソースコードがすべて ESM になった ◦ 実行されるときもNode.jsのネイティブESM ◦ メリット ▪ (Prettierチームにとって)開発者体験が向上する ▪ Tree Shakingの精度が高くなる ▪ ビルドスクリプトの複雑さが軽減される ▪ Pure ESM パッケージのために使っていた workaround を除去できる ◦ dynamic import を使ってプラグインや設定ファイル (.prettierrc)を読み込む • 2.x ではrequireを使っている
  5. CommonJS から ECMAScript Modules へ Prettier 3.0 はすべてが ECMAScript Modules

    ./node_modules/.bin/prettier ./bin/index.cjs ./internal/cli.mjs ./internal/internal.mjs 1. エントリポイントはCJSファイル 2. CLIの本体ファイル(ESM)を読み込む 3. コア実装(ESM)を読み込む 4. プラグインや設定ファイルも import で読み込む import(“./internal/cli.mjs”) import(“./internal/internal.mjs”) plugins .prettierrc import import
  6. prettier-vscode prettier-vscode における ECMAScript Modulesの問題 • Prettierの公式VSCode拡張 • 正式な名前は「Prettier -

    Code formatter」 ◦ 紛らわしいのでリポジトリ名から、 prettier-vscodeと呼ぶことにする • 開いているファイルをフォーマットしてくれる ◦ format on save を設定しておくと便利 ◦ Range formatting もサポートしている • なんとブラウザでも動く (= codespacesでも動く?)
  7. prettier-vscodeのPrettier3.0対応 prettier-vscode における ECMAScript Modulesの問題 • Prettier 3.0からJavaScript APIはすべてPromiseを返す •

    prettier-vscodeはPrettierのJavaScript APIを使うので、全部にawaitをつけて回る必要がある const formatted = prettier.format(text, options); const formatted = await prettier.format(text, options); Prettier 2.x Prettier 3.x
  8. prettier-vscodeのPrettier3.0対応 prettier-vscode における ECMAScript Modulesの問題 • 本番ビルドした結果全然動いてなかった (debug モードだと動いていた )

    • 調査の結果、dynamic importの実行が全部エラーになることがわかった ローカルで試したら 全然動かないです。多分 dynamic import が動いてな い...。 Prettierのビルドいじって頑張って みたけど動かない ...。 マジか
  9. prettier-vscodeのPrettier3.0対応 prettier-vscode における ECMAScript Modulesの問題 ESLint の flat config も設定ファイ

    ルを dynamic import してるはずだ けど、VSCode 拡張ちゃんと動いて いるよね。なんでだろう? たしかに 調べてみます
  10. 言語サーバーを使ったアーキテクチャ prettier-vscode における ECMAScript Modulesの問題 • vscode-eslintなどの一部のVSCode拡張は言語サーバーを使っている • VSCode拡張の本体は、その言語サーバーにとってはクライアントである •

    クライアントと、別に立ち上がる Language Serverプロセスとが通信しあう ◦ LSP(Language Server Protocol) 言語サーバー vscode-eslint ESLint を実行してくれ foo.jsの3行目に ◯◯エラーが出てるよ
  11. 言語サーバーを使わないアーキテクチャ prettier-vscode における ECMAScript Modulesの問題 • prettier-vscode は言語サーバーを使わない • 全てを

    VSCode 拡張本体の中で処理する prettier-vscode 今開いてるファイルに Prettierを実行して上書きす るぞ〜
  12. 言語サーバーからは dynamic import ができる prettier-vscode における ECMAScript Modulesの問題 • クライアント(拡張の本体)では

    dynamic import ができない • しかし、言語サーバーからなら dynamic import ができる 言語サーバー VSCode拡張本体 foo.js dynamic import
  13. 【余談】問題の原因を推測する prettier-vscode における ECMAScript Modules対応とその問題 • VSCode拡張クライアントでdynamic importしたときに起こるエラーは ◦ TypeError:

    A dynamic import callback was not specified. • これは、Node.js の vm.Script 環境で dynamic import を呼び出したときに発生する ◦ つまり、VSCodeでは拡張を実行するときに vm.Script環境に隔離していそう • prettier-vscode開発中のデバッグモードではこの問題は起こらなかった ◦ 多分、デバッグモードではこの隔離が有効になっていない
  14. 挫折... 言語サーバーの開発と挫折 • イチから作れというのならまだ適当にやればよかった • が、prettier-vscodeの挙動を維持しながら言語サーバーを使ったアーキテクチャに移行するというのが 本当に困難だった ◦ 実装や仕様がわからないソフトウェアの挙動を維持しながらアーキテクチャを大幅に変えるのは一 般に困難な気がする

    • 努力の残骸たち(マジで苦しかった) ◦ https://github.com/sosukesuzuki/vsce-doc-formatting-sample ◦ https://github.com/sosukesuzuki/prettier-language-server-vscode-client ◦ https://github.com/sosukesuzuki/prettier-language-server-deprecated • 言語サーバーを導入する方法は諦めた
  15. worker_threads による回避策 worker_threads による回避策 • vm.Script環境ではdynamic importができない • が、vm.Script環境で新たにスレッドを立てれば、そのスレッド内からは dynamic

    importができる ◦ (わざわざプロセスを作る必要はなかったので worker_threads を使うことにした) VSCode拡張 メインスレッド worker_threadで作った新しいスレッド foo.js dynamic import
  16. worker_threads による回避策 worker_threads による回避策 • worker_threads のスレッド内でのみ Prettier 3.0 を実行するアーキテクチャへ

    ◦ (Prettier 2.0 を使っている場合はメインスレッドで実行する ) prettier-vscode メインスレッド worker_threadで作った新しいスレッド .pretterrc プラグイン Prettier本体 dynamic import フォーマットした い フォーマットした よ
  17. まとめ まとめ • VSCode拡張でdynamic import が動かない • 言語サーバー導入しようとしたけど難しかった • だからworker_threadsでスレッド立てて、そこから

    dynamic importするようにした • 今のところ重大なバグ報告は来ていないが、実装者的には普通にバグってそうな気がする • 怪しい挙動があったら教えて下さい https://opencollective.com/prettier か https://github.com/sponsors/sosukesuzuki から寄付をくれると、 メンテを継続しやすくなります。