## 目的
以下の内容から『[[Neovim]]に関係なく、**型安全に[[Nuxt]]の開発をする部分**のみを抽出したスライドを作成する』ために、情報を整理する。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://publish-01.obsidian.md/access/35d05cd1bf5cc500e11cc8ba57daaf88/favicon-64.png" />
<span class="link-card-v2-site-name">Minerva</span>
</div>
<div class="link-card-v2-title">
📘完全武装をしてNeovimでも安全で快適なNuxt3の開発をするのだ
</div>
<div class="link-card-v2-content">NeovimでNuxt3とTypeScriptを型安全かつ快適に開発するための設定方法を解説します。Auto-importsの無効化や未使用importの自動削除、未定義タグの検知、フォールスルー属性対応など、VSCodeやWebStormでは得られないNeovim特有の課題とその解決策を詳しく紹介しています。詳しい手順や設定例は記事でご確認ください。</div>
<img class="link-card-v2-image" src="https://publish-01.obsidian.md/access/35d05cd1bf5cc500e11cc8ba57daaf88/%F0%9F%93%98Articles/attachments/2024-07-26.webp" />
<a data-href="📘完全武装をしてNeovimでも安全で快適なNuxt3の開発をするのだ" class="internal-link"></a>
</div>
%%[[📘完全武装をしてNeovimでも安全で快適なNuxt3の開発をするのだ]]%%
特に
- [[Nuxt4]]を使う
- 上記を執筆以降に
- 新しく登場した実用的な新機能の導入を検討する
- 非推奨となっている箇所のフォロー
### 環境
| 対象 | バージョン |
| ------------------------------------------- | ------ |
| [[macOS]] | 15.7.2 |
| [[Bun]] | 1.3.5 |
| [[Neovim]] | 0.11.5 |
| [[vtsls]] | 0.3.0 |
| [[@vue language-server\|vue_ls]] | 3.2.2 |
| [[vue-tsc]] | 3.2.2 |
| [[Vue - Official (VSCode)\|Vue - Official]] | 3.2.2 |
```
├── @fsouza/
[email protected]
├──
[email protected]
├──
[email protected]
├──
[email protected]
├──
[email protected]
├──
[email protected]
└──
[email protected]
```
## プロジェクト作成
```console
toki nuxt nuxt4-sandbox
```
```
◇ Templates loaded
│
◇ Which template would you like to use?
│ minimal – Minimal setup for Nuxt 4
│
◇ Creating project in nuxt4-sandbox
│
◇ Downloaded minimal template
│
◇ Which package manager would you like to use?
│ bun
│
◇ Initialize git repository?
│ Yes
│
◇ Dependencies installed
│
◓ Initializing git repositoryInitialized empty Git repository in /Users/tadashi-aikawa/tmp/nuxt4-sandbox/.git/
◇ Git repository initialized
│
◇ Would you like to install any of the official modules?
│ No
│
└ ✨ Nuxt project has been created with the minimal template.
```
起動確認。
```console
bun dev -o
```
### 初期ファイル作成
`app/app.vue`
```html
<template>
<NuxtPage />
</template>
```
`app/pages/top.vue`
```ts
<template>
<Header1 text="hello!" />
</template>
```
`app/components/Header1.vue`
```html
<script setup lang="ts">
defineProps<{
text: string;
}>();
</script>
<template>
<h1 v-text="text"></h1>
</template>
```
`package.json` の `scripts`
```json
{
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"typecheck": "nuxt typecheck",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
}
```
## 元記事との比較
### [[Auto-imports (Nuxt)|Auto-imports]]を無効化したい
https://nuxt.com/docs/4.x/guide/concepts/auto-imports
**今は使ったほうが楽かも。**
- ソースコードから型定義をビルドし、それがIDEに認識されるまでは正しく動かない
- [[ホットリロード]]していればOK
- 最近の[[LSP]]ならリアルタイムに認識してくれる
- import不要にもかかわらず、ソースコードによってはimport文が混在する
- **パスがついていない方を選択すれば平気**
- コードジャンプのときに型定義ファイルを経由する必要がある
- v3から直接ジャンプできるようになった
- [[📰Vue Language ToolsのGo to Definitionはいつからvueファイルへ直接ジャンプできるようになったか]]
#### コンポーネント名がファイル名と異なる点
`components/nest/Hoge.vue` が `<NestHoge>` でしか解決できないのは好きじゃない。解決方法としては
1. `nest/NestHoge.vue` のようにディレクトリと一致するprefixをつける
- その場合 `NestNestHoge.vue` にはならない
2. [[Auto-imports (Nuxt)|Auto-imports]]を無効化する
#### [[Auto-imports (Nuxt)|Auto-imports]]を無効化する段階
`components/` 以外の無効化。`composables/` や `utils/` などはこれで無効化される。
```ts
export default defineNuxtConfig({
imports: {
scan: false,
},
})
```
`components/` も含めた無効化。
```ts
export default defineNuxtConfig({
imports: {
scan: false,
},
components: {
dirs: [],
},
})
```
### 未使用[[import (ESM)|import]]を削除したい
**[[vue-tsc]]が必要。**[[VSCode]]も[[Neovim]]も。
- scriptタグで利用されないモノが消されてしまう問題
- これは大丈夫そうだった
- scriptタグでもtemplateタグでも利用されていないものが残ってしまう
- [[vue-tsc]]インストールで解決
自動にしたいなら[[ESLint]]や[[Prettier Plugin Organize Imports]]など。
### 未定義タグ/属性問題にコーディング段階で気づきたい
エラーは出ない。[[VSCode]]も。
```html
<template>
<Header100 text="hoge" />
<Header1 text="hoge" hyaku="take" />
</template>
```
[[nuxt.config]]に[[vueCompilerOptions.strictTemplates]]を追加する。ここは変わらず。
```ts
export default defineNuxtConfig({
typescript: {
tsConfig: {
vueCompilerOptions: {
strictTemplates: true,
},
},
},
});
```
ちゃんとエラーが出るようになった。もちろんエディタでも。
```console
$ bun typecheck
app/pages/top.vue:2:4 - error TS2339: Property 'Header100' does not exist on type '{}'.
2 <Header100 text="hoge" />
~~~~~~~~~
app/pages/top.vue:3:24 - error TS2353: Object literal may only specify known properties, and 'hyaku' does not exist in type '{ readonly text: string; } & VNodeProps &
AllowedComponentProps & ComponentCustomProps'.
3 <Header1 text="hoge" hyaku="take" />
~~~~~
Found 2 errors.
```
> [!hint]
> [[VSCode]]だと `Vue: Restart Vue and TS servers` コマンドが必要。
### フォールスルー属性を使いたい
`id` のように通常の[[HTML]]で使用できる[[属性名 (HTML)|属性名]]を指定してもエラーになってしまう。
```html
<template>
<Header1 id="h1" text="hoge" />
</template>
```
```error
app/pages/top.vue:2:12 - error TS2353: Object literal may only specify known properties, and 'id' does not exist in type '{ readonly text: string; } & VNodeProps & All
owedComponentProps & ComponentCustomProps'.
2 <Header1 id="h1" text="hoge" />
```
[[nuxt.config]]で[[vueCompilerOptions.fallthroughAttributes]]を有効にすると、一般的な[[HTML]]属性などはすべて通るようになる。
```ts
export default defineNuxtConfig({
typescript: {
tsConfig: {
vueCompilerOptions: {
strictTemplates: true,
fallthroughAttributes: true,
},
},
},
});
```
```html
<Header1
id="ok"
class="ok"
role="ok"
text="ok(Header1のproperty)"
unknown="NG"
@click="ok"
@unknown="NG"
/>
```
`data-testid` など正規ではないものは受け付けないが、[[vueCompilerOptions.dataAttributes]] を指定すれば型チェックをスキップできる。
```ts
export default defineNuxtConfig({
typescript: {
tsConfig: {
vueCompilerOptions: {
strictTemplates: true,
fallthroughAttributes: true,
dataAttributes: ["data-testid"],
},
},
},
});
```
```html
<template>
<Header1 data-testid="エラーにならない" />
</template>
```
#### [[キャメルケース]]への変換抑制
以下のケース。
```html
<template>
<Header1 aria-atomic />
</template>
```
[[Vue]]としては `aria-atomic` を `ariaAtomic` と認識するはずだが、上記はちゃんと `aria-atomic` として認識される。これは [[vueCompilerOptions.htmlAttributes]] のデフォルト値が `["aria-*"]` であり、[[キャメルケース]]へ変換されないから。
試しに以下のように設定するとエラーになる。
```ts
export default defineNuxtConfig({
typescript: {
tsConfig: {
vueCompilerOptions: {
strictTemplates: true,
fallthroughAttributes: true,
htmlAttributes: [],
},
},
},
});
```
## 個人的な意見
### [[Auto-imports (Nuxt)|Auto-imports]]はフレームワーク機能だけに留める
個人の趣向を含めなければ、どっちでもいい。
```ts
export default defineNuxtConfig({
imports: {
scan: false,
},
components: {
dirs: [],
},
})
```
- **暗黙的**な場合のデメリット
- ファイル名や定義が[[TypeScript]]の方針に従っていない
- [[React]]との頭の切り替えも大変そう
- 個々人の環境で不便が生じそうな気がする
- IDE環境や[[Vue Language Tools]]のバグの影響を受けやすくなりそう
- 状況によっては不具合の特定が難しくなりそう
- **明示的**な場合のデメリット
- import挿入と掃除が面倒
- 追加はオートコンプリートでいける
- コピペしたコードは面倒だけど...
- 掃除は[[ESLint]]や[[Prettier Plugin Organize Imports]]でいける
- 構成が変わったときに面倒
- 編集の仕方次第だけど面倒なことには変わりない
### タグや属性は型安全にする
これは絶対にやったほうがいい。人間でもAIでも品質が上がる。
```ts
export default defineNuxtConfig({
typescript: {
tsConfig: {
vueCompilerOptions: {
strictTemplates: true,
fallthroughAttributes: true,
dataAttributes: ["data-testid"],
},
},
},
});
```
- **メリット**
- **圧倒的シフトレフト**
1. IDE(静的チェック) `人間はここで気付ける`
2. CLI(静的チェック) `AIはここで気付ける`
3. 実行 `いままではここ`
- 具体的には
- IDEの段階でエラーに気づける
- commit/push前のhooksでエラーに気づける
- CIでエラーに気づける
- AIが実行権限をもたなくてもエラーに気づける
- **デメリット**
- ほぼない