Vue 3 でマルチプレイブラウザゲームを作る (1) 概要編
はじめに
「Vue.js を勉強してみよう」と思い、シンプルなブラウザゲームを作ってみました。
Vue は初めて、かつ、JavaScript もあまり触っていないという初心者です。
初心者の気持ちを忘れないうちに記事にまとめることで、これから Vue を学ぶ人の足がかりになればいいなと思い、筆を執りました。一方で、「こうしたほうがいい」「こういうやり方もある」というのもあると思いますので、アドバイスいただければ幸いです。
知識レベルとしては以下のような感じです。
- 知らない:Vue 含めた Web 系の開発
- 知っている:基礎的な HTML/CSS、コマンドラインは一応使える
題材
複数ブラウザでのじゃんけんゲームを題材にしました(Web じゃんけん)。
最初の参加者がメンバーを募り、メンバーが揃ったらじゃんけんをする、というシンプルなものです。
プログラムのソースコードは GitHub に上げてあります。
Vue の基礎
Vue とは
Vue は JavaScript フレームワークです。
Vue で開発すると何が嬉しいのか(何ができるようになるのか)というと、
- データの更新が自動的に画面に反映される(リアクティビティー)
- 機能単位でファイルを管理できる(SFC)
の 2 点に集約されると思います。
リアクティビテイー
(Vue を使わずに)ピュア JavaScript で開発する場合は、変数管理の後に画面更新が必要です。じゃんけんゲームの場合、じゃんけんに勝ったら勝利点変数を 1 増やし、その後、HTML の DOM を操作して画面に勝利点変数を表示します。
Vue で開発すると、変数の値を更新した時点で自動的に画面にその内容が表示されるので、手間が減り、画面更新漏れも防げます。
SFC
従来は、1 つの .html
ファイルにいろんな画面要素がある一方で、それぞれの要素を操作するロジックは複数の .js
ファイルにばらけたりしており、見通しが悪くなっていました。
Vue で開発すると、機能(コンポーネント)ごとの分割になる一方で、HTML + CSS + JavaScript がまとめて 1 ファイルになるため、コンポーネントベースの開発がやりやすくなります(管理方法については好みもありますので、必ずしも SFC を使わなくても大丈夫です)。
さらに
上記メリットを享受できるうえで、
- 学習コストが低い
- 動作が高速
- JavaScript / TypeScript 両対応
などといったところも好評のようです。
イマイチな点
私が初めて Vue に触れてイマイチだなと思ったのは、Vue にいくつか種類があるため、解説記事などを読む際にどの Vue が対象なのか見分けないと混乱することがあった、という点です。
- 2 種類の API
- インストールか CDN か
- SFC 使用の有無
- サーバー側での使用(SSR)
2 種類の API
Vue の API は
- Options API:従来からある低~中規模アプリ向け API
- Composition API:Vue 3 で新たに導入された大規模アプリ向け API
の 2 種類があり、書き方が異なっていますので、自分と同じ書き方の解説記事を選ぶ必要があります。
本稿は Options API で記述しています。個人的にはピュア JavaScript に近い書き方ができる Composition API のほうが好きなのですが、うまく動かせないところがあり、泣く泣く Options API にしました。なお、Options API が非推奨になったという誤解が一部であるようですが、公式で否定されています。
インストールか CDN か
公式のクイックスタートも最初にインストールのやり方が紹介されているので、順番に読み進めているとあたかもインストール必須の印象を受けますが、その先を読むと分かるように、CDN 版(<script src="https://~">
でインターネットから Vue を読み込む)を使えば何もインストールせずに使えて簡単です。
インストール版はアプリをビルドするので高速に動作しますが、ビルドに時間がかかるので(私の環境ではほんの少しのアプリでも 30 秒くらいかかりました)、初心者が試行錯誤するには向かないと思います。
本稿は CDN 版を使用しています。
SFC 使用の有無
SFC(単一ファイルコンポーネント)を使うかは好みですが、使う使わないで書き方が変わるので、自分と同じ書き方の解説記事を選ぶ必要があります。SFC を使っている解説記事には .vue
ファイルが出てきます。
本稿は SFC を使用しています。
サーバー側での使用
Vue はサーバー側で使うこともできますが(SSR: Server-Side Rendering)、ブラウザ側(クライアント側)で使う場合とは異なりますので、ブラウザ側の解説記事を選ぶ必要があります。
本稿はブラウザ側のみ Vue を使用しており、サーバー側では Vue は使用していません。
その他、公式サイトのサンプルコードが不完全で全体像が掲載されていないのも分かりづらい点でした。
Hello, world!
CDN 版 Vue 3 (Options API) + SFC で Hello, world! してみました。ソースコードは GitHub に上げてあります。
ファイルは 2 つありますが、メインとなる hello_world.vue
は以下です。
<template>
<div>
<p class="hello">Hello, world!</p>
<button @click="onButtonClicked">おまけ:{{ counter }}</button>
</div>
</template>
<style>
.hello {
background-color: azure;
}
</style>
<script>
export default {
data() {
return {
counter: 0,
};
},
methods: {
onButtonClicked() {
this.counter++;
},
},
}
</script>
<template>
ブロックに HTML、<style>
ブロックに CSS、<script>
ブロックにプログラムを書きます。
<template>
ブロックの Hello, world! 部分はピュア HTML なので迷わないと思いますが、そこで参照しているスタイルを同じファイル内の <style>
ブロックにすぐ書けるのが分かりやすいです。
Hello, world! だけだと簡単すぎるので、ちょっと Vue っぽいのということで、おまけボタンを付けました。クリックするとカウントアップしていきます。
ボタンクリックで <script>
ブロックの methods 内にある onButtonClicked() が呼ばれます。そこで、data 内で宣言している変数 counter をインクリメントします。
<template>
ブロックのボタンラベルに {{ counter }}
がありますが、ここで変数 counter の値を表示します。counter の値が変化すると自動的に表示を更新してくれます。DOM 操作を(自分では)一切せずに内部データとの同期処理が行われて便利です。
もう 1 つのファイル hello_world.html
は以下です。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta content="initial-scale=1.0, width=device-width" name="viewport">
<title>Hello, world!</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/vue3-sfc-loader"></script>
<script>
function loadModuleOptions() {
return {
moduleCache: {
vue: Vue
},
async getFile(url) {
const res = await fetch(url);
if (!res.ok) {
throw Object.assign(new Error(res.statusText + " " + url), { res });
}
return {
getContentData: asBinary => asBinary ? res.arrayBuffer() : res.text(),
}
},
addStyle(textContent) {
const style = Object.assign(document.createElement("style"), { textContent });
const ref = document.head.getElementsByTagName("style")[0] || null;
document.head.insertBefore(style, ref);
},
}
}
window.onload = function () {
const options = loadModuleOptions();
const { loadModule } = window["vue3-sfc-loader"];
const vueApp = Vue.createApp(Vue.defineAsyncComponent(() => loadModule("./hello_world.vue", options)));
vueApp.mount(document.body);
}
</script>
</head>
<body>
</body>
</html>
ごちゃごちゃとスクリプトが書かれていますが、vue3-sfc-loader 配布元のサンプルコードほぼそのままなので、定型文ということでいいと思います。
やっていることは、hello_world.vue
を読み込んで <body>
要素の配下に挿入(Vue 用語では「マウント」)しています。
ブラウザで .html
のほうを開き、F12(デベロッパーツール)で要素を確認すると、空だった <body>
の配下に .vue
の <template>
の内容が挿入されているのが分かります。
注意点として、.html
を開く際、ローカルにあるファイルをダブルクリックして開いても正常に動作しません。レンタルサーバーでも自鯖でも構わないので、Web サーバー上に 2 つのファイルを配置したうえで http(s) 経由で .html
を開く必要があります。サーバー側で Vue が動作している必要はなく、普通の Web サーバーで大丈夫です。
筆者は
- CORESERVER(V1 CORE-MINI)
- 自 PC WSL の Node.js サーバー
の 2 つで Hello, world! が動作したことを確認しています。
要素技術
基礎を押さえたところで、次回から Web じゃんけんの作成に進んでいきます。
本稿で使用する(勉強する)主な技術は以下です。
- Vue(ブラウザ側)
- CDN 版 Vue 3
- 単一ファイルコンポーネント(SFC)
- 子コンポーネント
- Vue 以外(主にサーバー側)
- Node.js + Express サーバー
- ソケット通信
- SQLite
Vue はブラウザ側(クライアント側)のみで使用しますが、Web じゃんけんはサーバー側とクライアント側で協調して動作するので、Vue を使わないサーバー側も作っていきます。
概要編まとめ
概要編では Vue の基礎を押さえ、インストール不要の Hello, world! で動作確認をしました。
題材となる Web じゃんけんの方向性も決めました。
次回はサーバーとクライアントの役割分担を決めていきます。
次回
確認環境
項目 | 環境 |
---|---|
OS | Windows 11 Pro 23H2 + WSL 2 + Ubuntu 24.04.1 LTS |
Web サーバー | Node.js v22.12.0 + Express |
Vue | CDN 版 v3.5.13 + vue3-sfc-loader v0.9.5 |
ブラウザ | Google Chrome 131.0.6778.205 / Firefox 133.0.3 |
主な改訂履歴
- 2025/01/02 初版。
- 2025/01/04 次回について記載。
Discussion