Nuxt3の素振り
Nuxt 3 - Roadmap によると、nuxt@3.0.0
のリリースが2022年6月に控え、そろそろ安定版になりそうなので今のうちに軽く素振りをしておく。
上記は2022年6月2日現在の画像。
🎉 Another grand Nuxt project just made! Next steps:
📁 `cd nuxt-app-20220602`
💿 Install dependencies with `npm install` or `yarn install` or `pnpm install --shamefully-hoist`
🚀 Start development server with `npm run dev` or `yarn dev` or `pnpm run dev
初期化後はnpm
、yarn
、もしくはpnpm
で依存のインストールを行う。
書き忘れたがNode.jsのバージョンは v16.13.0 を使っている。
インストール直後の構造。
tree -L 3 -I node_modules
.
├── README.md
├── app.vue
├── nuxt.config.ts
├── package.json
├── tsconfig.json
└── yarn.lock
package.json
の内容。
{
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview"
},
"devDependencies": {
"nuxt": "3.0.0-rc.3"
}
}
ちょっと前はgenerate
コマンドがなかったような気がする。
なんか色々できてすごいという話。nuxi
コマンドについて、以前はpackage.json
にかかれていたコマンドがnuxt
じゃなくてnuxi
だったような?と思って、手元でyarn nuxt -v
、yarn nuxi -v
とかして確認してみたけど、どうやらnuxt
コマンドはnuxi
コマンドのエイリアスっぽい?
出力が全く同じだった。
Nuxt CLI v3.0.0-rc.3 08:20:16
Usage: npx nuxi dev|build|preview|start|analyze|generate|prepare|typecheck|usage|info|init|create|upgrade|test|add|new [args]
Use npx nuxi [command] --help to see help for each command 08:20:16
✨ Done in 0.17s.
Components auto-imports がデフォで入っている。
Differences with Nuxt 2 / Vue 2 という項目があって面白かった。
- Better performance
- Composition API
- TypeScript support
が違うらしい。
CSRとSSRのメリデメの話。
後半に Coming in Nuxt 3 として Hybrid Rendering と Rendering on CDN edge workers の話があった。
useAsyncData
やref
など、よく使う機能が自動でインポートされていますよ、という話。
'#imports'
を使うことによって、明示的にインポートすることもできるらしい。
<script setup>
import { ref, computed } from '#imports'
const count = ref(1)
const double = computed(() => count.value * 2)
</script>
Typed API routes が良さそうだと思った。
yarn nuxi typecheck
コマンドで型チェックができて良い。
が、試しに実行したらエラーになってしまった。悲しい...🥲
yarn nuxi typecheck
yarn run v1.22.19
$ /Users/yuki/Src/frameworks/nuxt/nuxt-app-20220602/node_modules/.bin/nuxi typecheck
Nuxt CLI v3.0.0-rc.3 08:36:50
Need to install the following packages:
typescript
vue-tsc
Ok to proceed? (y) y
app.vue:3:6 - error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & Partial<{}> & Omit<Readonly<ExtractPropTypes<{}>> & VNodeProps & AllowedComponentProps & ComponentCustomProps, never> & Readonly<...>'.
Type '{}' is missing the following properties from type 'Readonly<ExtractPropTypes<{ appName: { type: StringConstructor; default: string; }; version: { type: StringConstructor; default: string; }; title: { type: StringConstructor; default: string; }; readDocs: { ...; }; followTwitter: { ...; }; starGitHub: { ...; }; }>>': version, title, appName, readDocs, and 2 more.
3 <NuxtWelcome />
~~~~~~~~~~~
Found 1 error in app.vue:3
ERROR Command failed with exit code 2: npx -p vue-tsc -p typescript vue-tsc --noEmit 08:37:01
at makeError (node_modules/nuxi/dist/chunks/index5.mjs:1242:11)
at handlePromise (node_modules/nuxi/dist/chunks/index5.mjs:2071:26)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Object.invoke (node_modules/nuxi/dist/chunks/typecheck.mjs:43:7)
at async _main (node_modules/nuxi/dist/cli.mjs:46:20)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
あと Stricter checks で型チェックを厳密に出来る、みたいなのもあったけど、これは別にtsconfig.json
を直接編集する感じでいいかなぁ。
export default defineNuxtConfig({
typescript: {
strict: true
}
})
また、デフォのtsconfig.json
は以下のようになっており、./.nuxt/tsconfig.json
を利用していることが分かる。
{
// https://v3.nuxtjs.org/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}
これを確認するとなるほど色々頑張っていることが分かる。自動生成されるファイルなので、strict
とか勝手に将来変わったらちょっと苦労するかもな〜とか思ったりした。ここまで来て原因を追求できる人ならいいけど、初学者は少し詰まりそう、かも?
./.nuxt/tsconfig.json
// Generated by nuxi
{
"compilerOptions": {
"jsx": "preserve",
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"skipLibCheck": true,
"strict": false,
"allowJs": true,
"noEmit": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"types": [
"node"
],
"baseUrl": "..",
"paths": {
"~~": [
"."
],
"~~/*": [
"./*"
],
"@@": [
"."
],
"@@/*": [
"./*"
],
"~": [
"."
],
"~/*": [
"./*"
],
"@": [
"."
],
"@/*": [
"./*"
],
"assets": [
"assets"
],
"public": [
"public"
],
"#app": [
"node_modules/nuxt/dist/app"
],
"#app/*": [
"node_modules/nuxt/dist/app/*"
],
"vue-demi": [
"node_modules/nuxt/dist/app/compat/vue-demi"
],
"#head": [
"node_modules/nuxt/dist/head/runtime"
],
"#head/*": [
"node_modules/nuxt/dist/head/runtime/*"
],
"#components": [
".nuxt/components"
],
"#imports": [
".nuxt/imports"
],
"#build": [
".nuxt"
],
"#build/*": [
".nuxt/*"
]
}
},
"include": [
"./nuxt.d.ts",
"../**/*"
]
}
未完成っぽいので、Nuxt 3 - Components directory から見ていく。
試しにcomponents/TheHeader.vue
を作成し、
<template>
<header>header!!!</header>
</template>
app.vue
から呼び出すと、呼び出せることが確認できた。便利。
<template>
<div>
<TheHeader />
</div>
</template>
Component Names にあるように、ディレクトリがネストしていてもいい感じに対応するっぽいが、コンポーネントの命名としては
For clarity, we recommend that the component's filename matches its name. (So, in the example above, you could rename Button.vue to be BaseFooButton.vue.)
としたほうが良いらしい。
実際にやってみて、動作することを確認できた。
Dynamic components として、resolveComponent を使うという話や Dynamic Imports で Lazy という接頭辞をつけるという話、あとは <ClientOnly> Component の話があったりした。
<ClientOnly> Component、<template #fallback>
でサーバーサイドでのレンダリングを定義できるっぽい。
<template>
<div>
<Sidebar />
<ClientOnly>
<!-- this component will only be rendered on client side -->
<Comments />
<template #fallback>
<!-- this will be rendered on server side -->
<p>Loading comments...</p>
</template>
</ClientOnly>
</div>
</template>
これ、動作を確認してみたけどクライアント側で少しLoading comments...
という表示がチラつくようだった。
pages/index.vue
を追加し、さらにapp.vue
を使っている場合はNuxtPage
を使うように書き換える必要がある。
<template>
<h1>Index page</h1>
</template>
この書き換え時にはDevサーバーの再起動が必要だった。
<template>
<div>
<NuxtPage />
</div>
</template>
Pages の成約として
Pages must have a single root element to allow route transitions between pages. (HTML comments are considered elements as well.)
というのはあるらしい。コメントもだめっぽいので、ちょっと気をつける必要がありそう。
<template>
<div>
<!-- This page correctly has only one single root element -->
Page content
</div>
</template>
<template>
<!-- This page will not render when route changes during client side navigation, because of this comment -->
<div>Page content</div>
</template>
Dynamic Routes は_id.vue
から[id].vue
に変わっている。このページの追加時もサーバーの再起動が必要だった。もともと、こんなにサーバーの再起動って必要だったっけ?
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue
<template>
<p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>
http://localhost:3000/users-foo/1 にアクセスしてfoo - 1
と表示されることを確認した。