5/22(金)〜5/23(土)にかけて、TSKaigi 2026 というイベントに行ってきました。興味深いトークがあった一方で、AI 生成と見られる発表資料が多数あったのが印象的でした。ほとんどの登壇者は AI で作ったと言ってないので推測ではあるのですが *1、見るだけで「AI 生成だな」と分かる感じでした。体感6割は AI 生成だったと思います。
AI 生成は時短にもなるし、良い資料を書くための補助にもなります。これまで発表するのが億劫に感じていた人も、AI の力を借りて発表しやすくなります。そういった点で、AI を活用してスライドを作るのは良いことだなと思います。実際 id:mizdra も以前、スライド中のイラストやサンプルコードの生成に AI を活用しました。満足のいくものがすぐに作れて、とても便利でした。
一方で AI の使い方には注意が必要だと思います。あんまりにも AI 生成そのまま過ぎると、残念なスライドになってしまいます。TSKaigi 2026 でもそのようなスライドが多数見られて、色々思うところがありました。
見出しの英語・日本語併記はかなりの資料で見かけました。スライド内で徹底されている訳でもないことから、英語話者向けというわけでもなさそうですし、多分装飾として書かれているのだと思います。1文内での色分けも多かったです。重要なところの強調、あるいは装飾として使われているように見えました。ギチギチまで文字やイラストを詰め込むのは、時々見かけました。話すことがいっぱいあるからこうなっていると思いきや、口頭ではほんの一部しか触れられていなかったので、これといった理由があるわけではなさそうでした。恐らく AI による装飾の一種でしょう。
TSKaigi 2026 では体感6割が AI 生成感のあるスライドでしたが、AI 生成感がないだけで AI を使っているスライドもあるはずです。そう考えるとスライドの作成に AI を使うのは既に当たり前なのかもしれません。時代ですね。一方で、あまりにも AI 生成そのままの残念な発表が多いと、聞き手としてはうんざりするなと思いました (正直 id:mizdra は TSKaigi 2026 でうんざりしていた)。今後他のイベントでもこのようなことが増えるのではと不安に感じています。何か手を打つ必要があるのかもしれません。
「全バージョンが LTS なら、何と比較して Long Term なサポートなんやねん」と思った人もいるかもしれません。ちょっと混乱するのですが、Node.js における「LTS」は major バージョンに割り当てられるステータスのようなものです。新たな major バージョンがリリースされると、まず半年間 Current というステータスになって、その後 30ヶ月間 LTS になります。Current では新機能がどんどん実装されていきますが、LTS ではセキュリティ修正などを主に受け付ける期間になります *1。
OWNER=$(gh repo view --json owner -q .owner.login)REPO=$(gh repo view --json name -q .name)# Setup common repository settings
gh repo edit \--delete-branch-on-merge\--enable-auto-merge\--enable-discussions=false\--enable-projects=false\--enable-secret-scanning\--enable-secret-scanning-push-protection\--enable-wiki=false# Enable Code scanning
gh api -X PATCH /repos/$OWNER/$REPO/code-scanning/default-setup -fstate=configured
# Enable immutable releases
gh api -X PUT /repos/$OWNER/$REPO/immutable-releases
# Setup rulesetsDEFAULT_BRANCH_PROTECTION=$(gh api /repos/mizdra/npm-package-template/rulesets/13184851)VERSION_TAG_PROTECTION=$(gh api /repos/mizdra/npm-package-template/rulesets/13184887)
gh api -X POST /repos/$OWNER/$REPO/rulesets --input - <<<$DEFAULT_BRANCH_PROTECTION
gh api -X POST /repos/$OWNER/$REPO/rulesets --input - <<<$VERSION_TAG_PROTECTION# Require actions to be pinned to a full-length commit SHA
gh api -X PUT /repos/$OWNER/$REPO/actions/permissions -Fenabled=true -Fsha_pinning_required=true
いくつかの設定は gh repo edit でできるのでそれで設定して、残りは gh api で REST API 叩いて設定してる。欲しかった REST API 全部存在してて GitHub すごい。
Emacs にはエディタの動作を切り替える仕組みがあり、これを「Mode」と呼ぶ。Mode には major mode と minor mode の二種類がある。major mode は特定のファイルタイプに特化した機能を提供するもので、1つのファイルにつき 1つだけ割り当てられる。一方 minor mode は1つのファイルに複数割り当て可能なもの。
Emacs 側の議論はちゃんと追ってないけど、多分 tree-sitter の構文定義が統一されているので major mode も統一しているのだろう。
Language Server の設定
先ほど少し触れたが、Emacs には Eglot という Language Client が組み込まれている。major mode と Language Server の起動コマンドの組のリストからなる eglot-server-programs という変数があり、この定義に従って Language Server が起動される。ちなみにデフォルトでは JavaScript と TypeScript では typescript-language-server が Language Server の実装として使われる。
勘の良い人は気づいたかもしれないが、Eglot は 1 つの major mode に複数の Language Server を起動することができない。eglot-server-programs の先頭に定義されている Language Server が優先して起動されることになる。
つまり今回 id:mizdra が紹介した init.el では、*.css に対して TypeScript/CSS 両方の Language Server を起動できない。TypeScript の Language Server だけが起動される。そのため @css-modules-kit/ts-plugin が提供する言語機能 (クラスセレクターの Go to Definition や Find All References など) は機能するが、CSS の Language Server が提供する言語機能 (プロパティの補完など) は機能しない。
Neovim は LSP のサポートを組み込んでいる。ただし、デフォルトではどの Language Server も起動されないようになっている。ユーザが Language Server を起動するための設定が必要になる。
まず Language Server をインストールする必要がある。TypeScript の Language Server は typescript-language-server と vtsls の二種類がある。今回は typescript-language-server を使ってみる。以下のコマンドでインストールできる。
npm i -g typescript-language-server typescript
そして init.lua に以下のような設定を書く。
-- 補完を有効にするための設定
vim.cmd[[set completeopt+=menuone,noselect,popup]]
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(ev)
local client = vim.lsp.get_client_by_id(ev.data.client_id)
if client and client:supports_method('textDocument/completion') then
vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true})
endend,
})
-- TypeScript の Language Server の設定
vim.lsp.config('ts_ls', {
init_options = { hostInfo = 'neovim'},
cmd = {'typescript-language-server', '--stdio'},
filetypes = {'javascript',
'javascriptreact',
'javascript.jsx',
'typescript',
'typescriptreact',
'typescript.tsx',
},
root_markers = {'tsconfig.json', 'jsconfig.json', 'package.json', '.git'},
})
-- TypeScript の Language Server を有効に
vim.lsp.enable('ts_ls')
-- 補完を有効にするための設定
vim.cmd[[set completeopt+=menuone,noselect,popup]]
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(ev)
local client = vim.lsp.get_client_by_id(ev.data.client_id)
if client and client:supports_method('textDocument/completion') then
vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true})
endend,
})
-- TypeScript の Language Server を有効に
vim.lsp.enable('ts_ls')
これだけみると、「nvim-lspconfig から提供される Language Server の設定はどこで読み込んでるんだ?」とびっくりするかも (id:mizdra はびっくりした)。実は vim.lsp.enable('ts_ls') を実行した時に読み込まれている。Package 内の lsp/* から Language Server の設定が自動で探索される挙動となってて、結果として nvim-lspconfig/lsp/ts_ls.lua が読み込まれている。