😩

Nuxt+TS+CompositionAPI+Vercel+VSCodeのセットアップ手順

9 min read

ずっとNext.jsを使っていたんだが、Nuxt.jsに切り替えるにあたって何回も挫折したので、正直二度とやりたくないが 一応メモする。

最終更新: 2021年7月17日

筆者はNuxtに関しては初心者ですので、細かい説明が不正確かもしれません。また、Vue/Nuxtはすごい速度で進化しています。仕様変更に注意してください

何をセットアップするか

  • yarn create nuxt-appで以下を済ませる
    • TypeScript化
    • Prettier+ESLint
    • TailwindCSS対応
    • PWA対応
  • コンフィグをTS化する
    • srcディレクトリにまとめる
    • OGPを設定する
  • @nuxtjs/composition-api を入れる
    • propsを自動補完できるようにする
  • Netlifyは遅いのでVercelを使いたい
    • VercelでSSRできるようにする

事前に入れておくVSCodeのエクステンション

https://qiita.com/newt0/items/aeddc6a179ea3a464ed5

こちらの記事を参照。

Nuxtのセットアップ

yarn create nuxt-app <プロジェクト名>

以下のように選択していく。

? Project name: (プロジェクト名)
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: Tailwind CSS
? Nuxt.js modules: Axios - Promise based HTTP client, Progressive Web App (PWA)
? Linting tools: ESLint, Prettier
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
# SSRを使うのでVercelでは別途設定が必要
? Deployment target: Server (Node.js hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert 
selection)
# ここでDependabotを入れられる
? Continuous integration: None
? Version control system: Git

この選択により、以下のパッケージがインストールされる。(2021年7月17日現在)

package.json
package.json
{
  "dependencies": {
    "@nuxtjs/axios": "^5.13.6",
    "@nuxtjs/pwa": "^3.3.5",
    "core-js": "^3.15.1",
    "nuxt": "^2.15.7"
  },
  "devDependencies": {
    "@babel/eslint-parser": "^7.14.7",
    "@nuxt/types": "^2.15.7",
    "@nuxt/typescript-build": "^2.1.0",
    "@nuxtjs/eslint-config-typescript": "^6.0.1",
    "@nuxtjs/eslint-module": "^3.0.2",
    "@nuxtjs/tailwindcss": "^4.2.0",
    "eslint": "^7.29.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-nuxt": "^2.0.0",
    "eslint-plugin-vue": "^7.12.1",
    "postcss": "^8.3.5",
    "prettier": "^2.3.2"
  }
}

コンフィグをtsに変え、各種設定をする

https://github.com/nuxt-community/typescript-template

上のテンプレートで初めて知ったんだが、@nuxt/typesNuxtConfigという型が用意されている。さっきTypeScriptを選んだくせに、自動生成されるコンフィグでは活用されていないので、自分で指定しないといけない。

mv nuxt.config.js nuxt.config.ts

コンフィグをTypeScriptに変え、以下のように型を指定する。

nuxt.config.ts
+ import { NuxtConfig } from '@nuxt/types'

- export default {
+ const config: NuxtConfig = {
}

+ export default config

これでコンフィグが自動補完されるようになった。

srcディレクトリにまとめる

管理しやすいようsrcディレクトリにまとめる。

nuxt.config.ts
const config: NuxtConfig = {
+  srcDir: 'src/',
}
tsconfig.json
{
-  "baseUrl": ".",
+  "baseUrl": "./src",
}  

コンフィグにsrcDirを追加し、tsconfigのbaseUrlを書き換える。

そして以下のようなファイル構成にする。

-| レポジトリ/
---| node_modules/
---| nuxt.config.js
---| package.json
---| src/
------| components/
------| pages/
------| static/
------| store/

OGP設定

https://www.to-r.net/media/nuxt-setup/

headmetaに以下のように書けばいいとのこと。

nuxt.config.ts
import { NuxtConfig } from '@nuxt/types'

const title = 'タイトル'
const description = '説明'
const url = 'https://example.com'
const ogImage = `${url}/ogp.jpg`

const config: NuxtConfig = {
  ...
  head: {
    title: '(サイト名)',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { name: 'format-detection', content: 'telephone=no' },
      { hid: 'description', name: 'description', content: description },
      { hid: 'ogTitle', property: 'og:title', content: title },
      { hid: 'ogType', property: 'og:type', content: 'website' },
      { hid: 'ogUrl', property: 'og:url', content: url },
      {
        hid: 'ogImage',
        property: 'og:image',
        content: ogImage,
      },
      { property: 'og:site_name', content: title },
      {
        hid: 'ogDescription',
        property: 'og:description',
        content: description,
      },
      { name: 'twitter:card', content: 'summary_large_image' },
      { hid: 'twitterSite', name: 'twitter:site', content: title },
      { hid: 'twitterUrl', name: 'twitter:url', content: url },
      { hid: 'twitterTitle', name: 'twitter:title', content: title },
      {
        hid: 'twitterDescription',
        name: 'twitter:description',
        content: description,
      },
      {
        hid: 'twitterImage',
        name: 'twitter:image:src',
        content: ogImage,
      },
    ]
  }
  ...
}

OGP画像は相対パスを指定してはいけないので注意。

OGP画像やFaviconはstaticディレクトリに適宜追加すること。

ついでにPWAを日本語に

nuxt.config.ts
  // PWA module configuration: https://go.nuxtjs.dev/pwa
  pwa: {
    manifest: {
-      lang: 'en',
+      lang: 'ja',
    },
  },

Nuxt用のComposition APIを入れる

React使いがVueに移って一番苦労するのがAPIの選択かもしれない。

Class APIがVue3のRFCでrejectされただとか、日々変わる状況をググるたびに気にしないといけない。

ReactならHookへの移行、NextならgetStaticPropsへの移行、という風に一本道だったが、Vue/Nuxtは 移行のパターンが多すぎて本当に面倒。 早く一つにまとまってくれ!

今回はTypeScriptとの親和性やナウさを考えてComposition APIを選択する。

@nuxtjs/composition-api を入れる

データ取得などを包括的にやってくれる@nuxtjs/composition-apiを入れる。

yarn add @nuxtjs/composition-api

nuxt.config.tsに追記する。

nuxt.config.ts
{
  buildModules: [
    // https://go.nuxtjs.dev/typescript
    '@nuxt/typescript-build',
    // https://go.nuxtjs.dev/tailwindcss
    '@nuxtjs/tailwindcss',
+    // https://composition-api.nuxtjs.org
+    '@nuxtjs/composition-api/module'
  ]
}

propsをVSCodeに自動補完させる

https://zenn.dev/dialbird/articles/fcf9f68398979d

React+TSなら当たり前にできるのに、Vueは一手間かかるのが面倒。

具体的には、Veturvue-intellisenseで自動生成したデータを渡さないといけない。

準備

yarn add -D vue-intellisense 

package.jsonに以下を追記。

package.json
{
  "scripts": {
+    "build:intel": "vue-int --input src/components --output .vscode/vetur --recursive"
  },
+  "vetur": {
+    "tags": ".vscode/vetur/tags.json",
+    "attributes": ".vscode/vetur/attributes.json"
+  }
}

Veturに読ませる

yarn run build:intel

これで.vscode配下に設定ファイルが書き出されるので、<kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>からのRestart VLS (Vue Language Server)を実行する。

これでpropsを自動補完できるようになった。2021/07/17現在、型の間違い([Vue warn]: Invalid prop)についてエディタ上では警告されないので注意。

TODO: これをVSCodeのタスクにする

VercelにSPAとしてデプロイできるようにする

Netlifyの無料プランのCDNが日本に対応したら、ここは飛ばす。

2021年7月17日現在、Netlifyは日本だと遅い。仕方ないのでVercelを使う。

VercelでNuxtをデプロイさせると、こんな設定が適用されるはず。しかしこれはnuxt generateで静的に書き出した場合のための設定。

Error: No Output Directory named "dist" found after the Build completed. You can configure the Output Directory in your Project Settings. Learn More: https://vercel.link/missing-public-directory

ビルドスクリプトはnuxt buildにしているので、こんなエラーが出る。ということで、Vercelでもビルドできるように設定しないといけない。

https://nuxtjs.org/docs/2.x/deployment/vercel-deployment
touch vercel.json

vercel.jsonを以下のように書く。

vercel.json
{
  "version": 2,
  "builds": [
    {
      "src": "nuxt.config.ts",
      "use": "@nuxtjs/vercel-builder",
      "config": {
        "serverFiles": ["package.json"]
      }
    }
  ],
  "routes": [
    {
      "src": "/sw.js",
      "continue": true,
      "headers": {
        "Cache-Control": "public, max-age=0, must-revalidate",
        "Service-Worker-Allowed": "/"
      }
    }
  ]
}

これでVercelの設定が上書きされる。

@nuxtjs/vercel-builderの説明と違ってnuxt.config.tsを指定している点に注意。あとPWAの設定も必要。これを書かないとサービスワーカーのsw.jsが404になるらしい。

以上を書いたらいよいよデプロイだ!

postcssのType 'Plugin' is not generic エラーを直す

21:25:44.339  	node_modules_dev/@nuxt/types/config/build.d.ts(124,58): error TS2315: Type 'Plugin' is not generic.

が、こんなエラーが出てしまった。

https://github.com/nuxt/vercel-builder/issues/550#issuecomment-825480917

どうやら postcss@8を入れたのに、@nuxt/typespostcss@7を想定している故のエラーらしい。PostCSSってほんとこの手のトラブル多いね...

tsconfig.json
{
+  "skipLibCheck": true,
}

Danielさんのアドバイスの通り、"skipLibCheck": trueを追記する。これで依存ライブラリの型宣言のチェックが飛ばされ、デプロイできるはず。

21:38:03.019  	[log]  ----------------- Collect artifacts ----------------- 
21:38:06.838  	[info] Collect artifacts took: 3819.041303 ms
21:38:07.576  	Uploading build outputs...
21:38:07.792  	Deploying build outputs...
21:38:15.162  	Build completed. Populating build cache...
21:38:15.163  	[log]  ----------------- Collect cache ----------------- 
21:38:25.096  	[info] 77 files collected from .nuxt
21:38:37.291  	[info] 30944 files collected from .vercel_cache
21:38:49.343  	[info] 29760 files collected from node_modules_dev
21:38:59.815  	[info] 4154 files collected from node_modules_prod
21:38:59.819  	[info] Collect cache took: 44655.389298 ms
21:39:31.479  	Uploading build cache [123.41 MB]...
21:39:36.415  	Build cache uploaded: 4.935s
21:39:36.949  	Done with "nuxt.config.ts"

ついにデプロイ成功!アーティファクトとキャッシュの収集に割と時間がかかる。アーティファクトって書くと厨二感すごいな


あまりに手間がかかりすぎて疲れたので、解説はここまでとする!

あとは

  • FaviconやOGP画像をちゃんと追加
  • コンポーネントの整理
  • レイアウトやstoreの整備

をしていこう。