環境構築と単一ファイルコンポーネント — 開発を始める最小構成
Vue のプロジェクトを作るコマンドは 1 行です。ただし対話でいくつか質問され、選んだ内容で生成物が変わります。あとから足せるものと、最初に決めておくと楽なものがあるので、何を聞かれるのかを先に知っておくと迷いません。
この章では公式の scaffold である create-vue でプロジェクトを作り、生成されたファイルが何のためにあるかを読みます。そのあと、Vue の開発単位である単一ファイルコンポーネントの構造を見ます。
この章で学ぶこと
- create-vue の対話で何を聞かれ、どれを選ぶべきかを判断できる
- 生成されたディレクトリと設定ファイルの役割を説明できる
- 単一ファイルコンポーネントの 3 つのブロックの使い分けが分かる
プロジェクトを作る
Vue 公式の Quick Start が案内しているコマンドはこれです1。
npm create vue@latest
Node.js の要件は ^22.18.0 || >=24.12.0 です。22.18.0 以上の 22 系か、24.12.0 以上が必要で、23 系は対象外です。奇数系を使っている場合は切り替えます。
Vite のテンプレート (npm create vite@latest の vue-ts) でも Vue プロジェクトは作れますが、生成されるのは最小構成です。create-vue のほうがルーターや状態管理、型検査、リンターの設定まで組み合わせてくれるので、実務で使う構成に近い形から始められます。
対話で聞かれること
質問はこの順に出ます。
| # | 質問 | 内容 |
|---|---|---|
| 1 | Project name (target directory) | 作成先のディレクトリ名。コマンドの引数で渡した場合は出ません |
| 2 | Package name | package.json の name。ディレクトリ名がそのまま使える場合は出ません |
| 3 | Use TypeScript? | TypeScript を使うか。機能選択より先に聞かれます |
| 4 | Select features to include in your project | 機能の複数選択。下の表を参照 |
| 5 | Select an End-to-End testing framework | 4 で End-to-End Testing を選んだ場合のみ。Playwright か Cypress |
| 6 | Select experimental features to include in your project | 実験的な機能の複数選択。何も選ばずに進められます |
| 7 | Skip all example code and start with a blank Vue project? | サンプルコードを消して空の状態から始めるか |
4 番の機能選択で選べるのは 7 つです。
| 選択肢 | 内容 | 本ガイドでの扱い |
|---|---|---|
| JSX Support | テンプレートの代わりに JSX を書けるようにする | 扱いません |
| Router (SPA development) | Vue Router を入れる | 15 章と16 章で扱います |
| Pinia (state management) | 状態管理ライブラリを入れる | 17 章で扱います |
| Vitest (unit testing) | 単体テストの環境を入れる | 扱いません |
| End-to-End Testing | Playwright か Cypress を入れる | 扱いません |
| Linter (error prevention) | oxlint と ESLint を入れる | 扱いません |
| Prettier (code formatting) | コード整形を入れる | 扱いません |
6 番の実験的な機能では Vue 3.6 (Release Candidate) と、Prettier を Oxfmt に置き換える選択肢が出ます。本ガイドは安定版の 3.5 を基準にしているので、どちらも選びません。対話で作る場合はこの質問が必ず出るので、必要なければ何も選ばずに進めます。
学習用に最小の構成で始めるなら、TypeScript だけを有効にして他を外すのが分かりやすいです。本ガイドは Router と Pinia も後半で扱うので、通しで読むなら最初から入れておくと差分が少なくて済みます。
対話を飛ばす
フラグで指定すると対話が出ません。CI や、同じ構成を作り直すときに使えます。
# TypeScript + Router + Pinia の構成を対話なしで作る
npm create vue@latest my-app -- --ts --router --pinia
--default は追加機能なしの構成になりますが、TypeScript は有効になります。--bare はサンプルコードを省く指定で機能フラグではないため、単独で渡すと対話が始まります。
依存をインストールして起動する
cd my-app
npm install
npm run dev
生成されたものを読む
TypeScript、Router、Pinia の 3 つを選んだ場合の構成です。
my-app/
├── index.html エントリの HTML。ここに #app がある
├── vite.config.ts Vite の設定。@ → ./src の別名もここ
├── env.d.ts Vite が注入する型の宣言
├── tsconfig.json 分割した設定を参照するだけの親
├── tsconfig.app.json ブラウザで動くコード向け
├── tsconfig.node.json 設定ファイルなど Node で動くコード向け
├── public/ 変換せずそのまま配信されるファイル
└── src/
├── main.ts アプリを組み立てて #app にマウントする
├── App.vue 最上位のコンポーネント
├── assets/ CSS や画像。ビルド時に変換される
├── components/ 再利用するコンポーネント
├── views/ ルートに対応する画面単位のコンポーネント
├── router/ ルート定義
└── stores/ Pinia のストア
選んだ機能で増減します。Linter を選ぶと eslint.config.ts と .oxlintrc.json が、Prettier を選ぶと .prettierrc.json が加わります。Vitest を選ぶと vitest.config.ts と tsconfig.vitest.json が増え、親から参照される設定が 3 つになります。
composables/ は生成されません。ロジックを切り出すディレクトリなので、必要になった時点で自分で作ります (8 章で扱います)。
エントリポイント
src/main.ts がアプリを組み立てる場所です。
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
createApp() でアプリのインスタンスを作り、use() でプラグインを登録し、mount() で index.html の #app に差し込みます。ルーターや状態管理を足すときはここに use() を追加します。
tsconfig が分かれている理由
tsconfig.json の中身は参照だけで、実際の設定は分割されています。ブラウザで動くコードと、vite.config.ts のように Node で動くコードでは、使える API と型が違うためです。混ぜると window を参照できない場所で参照が通ってしまったり、逆に Node の API が使えないことになります。
アプリ側の tsconfig.app.json には noUncheckedIndexedAccess が入っています。添字アクセスの結果に undefined が混ざる前提で型が付くので、const first = items[0] の型は string | undefined になります。読み出すだけならエラーになりませんが、items[0].length のように undefined を許さない位置で使うと止まります。安全側に寄せた設定です。
型検査は npm run type-check で走ります。中身は vue-tsc --build で、分割された設定をまとめて処理します。素の tsc ではなく vue-tsc を使うのは、.vue ファイルの中身を解析する必要があるからです。
用意されるコマンド
| コマンド | 内容 |
|---|---|
npm run dev | 開発サーバーを起動する |
npm run build | 型検査とビルドをまとめて実行し dist/ に出力する |
npm run build-only | 型検査を飛ばしてビルドだけ実行する |
npm run preview | ビルド結果をローカルで配信して確認する |
npm run type-check | 型検査だけを実行する |
npm run test:unit | Vitest で単体テストを実行する (Vitest を選んだ場合) |
npm run lint | oxlint と ESLint を順に実行する (Linter を選んだ場合) |
npm run format | Prettier で整形する (Prettier を選んだ場合) |
Linter を選ぶと lint が oxlint と ESLint を順に呼ぶ 2 段構成になります。ESLint 側の設定には oxlint と重複する規則を無効化する仕組みが入っているので、同じ指摘が二重に出ることはありません。
単一ファイルコンポーネントの 3 ブロック
Vue のコンポーネントは .vue という拡張子の 1 ファイルで、テンプレートとロジックとスタイルを同じ場所に書きます。
<script setup lang="ts">
import { ref } from 'vue'
const name = ref('Vue')
</script>
<template>
<p class="greeting">こんにちは、{{ name }}</p>
</template>
<style scoped>
.greeting {
font-weight: bold;
}
</style>
3 つのブロックの役割はこうなっています。
| ブロック | 役割 |
|---|---|
<script setup lang="ts"> | このコンポーネントのロジック。ここで宣言した変数と関数はテンプレートから使えます |
<template> | 画面の構造。HTML に Vue の記法を足したものを書きます |
<style scoped> | このコンポーネント用のスタイル |
順序は決まっていません。create-vue の生成物は <script setup> を先に書いているので、本ガイドもそれに合わせます。
script setup が省いているもの
<script setup> を付けると、トップレベルで宣言したものがテンプレートから使えます。return を書く必要はありません。インポートしたコンポーネントもそのまま使えるので、登録の記述も要りません。
<script setup lang="ts">
import Greeting from './Greeting.vue'
</script>
<template>
<Greeting />
</template>
scoped が何をするか
<style scoped> を付けると、Vue がコンポーネントごとに固有の属性を要素へ振り、セレクタにその属性を足します。これでクラス名の衝突を自分で管理しなくて済むので、コンポーネントごとに素直な名前を付けられます。
範囲は「そのコンポーネントの中だけ」ではありません。単一のルート要素を返す子コンポーネントには、そのルート要素に親の属性も付きます。 子自身が <style scoped> を持つなら両方の属性が付き、持たないなら親の属性だけです。どちらでも親のセレクタはそのルート要素に当たります。一方、子が複数のルート要素を返す場合は、どの要素にも親の属性は付きません。
単一ルートの子に親のスタイルが届くのは、レイアウト上の余白を親が決めたい場面で役に立ちます。一方で意図せず子の見た目を変えてしまうこともあるので、この経路があることは頭に入れておきます。
子の内部 (ルートより深い要素) にスタイルを当てたい場合は :deep() で貫通させます。ただし子の内部構造に依存する書き方になるので、使いすぎると変更に弱くなります。
Vue CLI をどう扱うか
Vue には webpack ベースの Vue CLI という古いツールチェーンがありますが、公式は メンテナンスモードだと位置づけています。新規プロジェクトは Vite で始めることを推奨し、webpack 固有の機能が必要な場合だけ例外としています2。
すでに Vue CLI で動いているプロジェクトが壊れるわけではありません。ただし新しく作るなら create-vue を使います。
エディタの設定
create-vue は .vscode/extensions.json に推奨拡張を書き込みます。中心になるのは Vue - Official (識別子は Vue.volar) で、.vue ファイルの構文解析と型情報を担当します。以前は Volar という名前でしたが、現在は Vue 公式の拡張として提供されています。
まとめ
- プロジェクトは
npm create vue@latestで作ります。Vite のテンプレートでも動きますが、公式の scaffold は create-vue です - Node は 22.18.0 以上の 22 系か 24.12.0 以上が必要で、23 系は対象外です
- 対話は TypeScript を使うかが先で、機能の複数選択はそのあとです。実験的な機能の質問も対話では必ず出るので、Vue 3.6 の候補版を使わないなら何も選ばずに進めます
- フラグを渡すと対話を飛ばせます。ただし
--defaultでも TypeScript は有効になり、--bareは単独では対話を止められません tsconfig.jsonが分かれているのは、ブラウザ向けと Node 向けで使える API が違うためです。アプリ側にはnoUncheckedIndexedAccessが入っています- 型検査は
vue-tscが担います。.vueの中身を解析する必要があるので、素のtscでは足りません - 単一ファイルコンポーネントは
<script setup>、<template>、<style scoped>の 3 ブロックです。<script setup>を使えばreturnとコンポーネント登録が要りません scopedの範囲はコンポーネントの内部だけではありません。単一ルートの子には、そのルート要素に親の属性も付きます (複数ルートの子には付きません)- Vue CLI は廃止ではなくメンテナンスモードです。新規プロジェクトでは使いません
- Vue — クイックスタート — 公式の手順と Node の要件
- Vue — ツール — create-vue と Vue CLI の位置づけ
- Vue — SFC の構文仕様 — ブロックの仕様
- Tailwind CSS ガイド — スタイリングを深く扱う姉妹ガイド
次に読む
- リアクティビティ — 宣言した値の変更が画面に反映される仕組み
- テンプレート構文とディレクティブ —
<template>に書ける記法