【DRF】venv仮想環境を用いて、DRFシステムで書籍管理システムを作成する(4)Vue.jsの導入
第3回目でAPIを動作させることができましたので、次の手順はフロントで使用する「Vue.js」の導入です。
10. Vue.jsの導入
Vue.jsとは?
Vue.jsは、Webアプリケーションにおけるユーザーインターフェイスを構築するためのJavaScriptフレームワークです。
SPA(Single Page Application)開発に使われていることが多いです。
特徴
- 学習コストが低い
- コードの記述量が少なく、開発スピードが早くなる
- コンポーネント化することで、再利用することができる
個人的にJavascriptが苦手なので「学習コストが低い」というのには素直に賛同できませんが、世間では上記のように言われています(苦笑)
公式ドキュメントは以下となります。一読すべしですね。
10-1.node/npmインストール
ということで、インストールの準備を始めたいと思います。
まずは node と npm がインストールされていることを確認します。
1 2 |
(venv) ~$ node -v (venv) ~$ npm -v |
私の環境では下記のようになりました。
1 2 3 4 5 |
(venv) ~$ node -v v20.12.2 (venv) ~$ npm -v 10.8.1 |
まだインストールされていない方は、下記サイトを参考にインストールしてください。
10-2.vue-cliインストール
1 |
(venv) ~$ sudo npm i -g @vue/cli |
10-3.vue.jsインストール
今回は django ディレクトリと同じ階層に vue.js をインストールしたいので、drf3 ディレクトリで vue create
コマンドでインストールします。
フォルダ名は vue
にします。
1 |
(venv) ~$ vue create vue |
インストール時にいくつかオプションが表示されるので、以下のように順番に選択していきます。
1)プリセットを選ぶ質問。 Manually select features(手動)を選択します。
1 2 3 4 5 |
? Please pick a preset: (Use arrow keys) toofie ([Vue 3] babel, router, vuex, eslint, unit-jest) Default ([Vue 3] babel, eslint) Default ([Vue 2] babel, eslint) ❯ Manually select features |
2)更にオプションが選択できるので、ひとまず
・Babel
・Router
・Linter / Formatter
を選択します。
説明にも書いていますが、スペースキーを押すことで選択することができます。
選択したら Enter キーを押して次へ進みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Vue CLI v5.0.8 ? Please pick a preset: Manually select features ? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed) ◉ Babel ◯ TypeScript ◯ Progressive Web App (PWA) Support ◉ Router ◉ Vuex ◯ CSS Pre-processors ❯◉ Linter / Formatter ◯ Unit Testing ◯ E2E Testing |
3)Vueバージョンの2系統と3系統が選べるので、ここは当然 3系統 を選択
1 2 3 4 5 6 7 |
Vue CLI v5.0.8 ? Please pick a preset: (Use arrow keys) ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, Router, Vuex, Linter ? Choose a version of Vue.js that you want to start the project with (Use arrow keys) ❯ 3.x 2.x |
4)routerでhistoryモードを使用するかを聞かれているので、Yesを選択
1 |
? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) |
5)Linter / formatterの設定を選択する質問。 ESLint + Standard config を選択
1 2 3 4 5 |
? Pick a linter / formatter config: ESLint with error prevention only ESLint + Airbnb config ❯ ESLint + Standard config ESLint + Prettier |
6)追加の Lint 機能を選択する質問で、 Lint on save を選択
1 2 3 4 |
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed) ❯◉ Lint on save ◯ Lint and fix on commit |
7)Babel、ESLint などの設定ファイルをどこに置くかを尋ねる質問で、 In package.json を選択
1 2 3 |
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files ❯ In package.json |
8)今回の設定を将来のプロジェクトで使用するためのプリセットとして保存するかどうかを尋ねる質問で、Nを選択
1 |
? Save this as a preset for future projects? (y/N) N |
全ての質問に回答後、インストールが始まります。
少し時間がかかるので、気長に待ちましょう。
確認
1 2 3 4 5 6 7 |
(venv) :~/source/drf3$ ls -al total 20 drwxr-xr-x 4 t******** t******** 4096 Sep 7 23:25 . drwxr-xr-x 17 t******** t******** 4096 Sep 3 22:26 .. drwxr-xr-x 4 t******** t******** 4096 Sep 7 23:13 django -rw-r--r-- 1 t******** t******** 60 Sep 3 23:06 drf3.code-workspace drwxr-xr-x 6 t******** t******** 4096 Sep 7 23:26 vue ←★作成されたディレクトリ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
(venv) :~/source/drf3$ cd vue (venv) :~/source/drf3/vue$ ls -al total 568 drwxr-xr-x 6 t******** t******** 4096 Sep 7 23:26 . drwxr-xr-x 4 t******** t******** 4096 Sep 7 23:25 .. -rw-r--r-- 1 t******** t******** 121 Sep 7 23:25 .editorconfig drwxr-xr-x 8 t******** t******** 4096 Sep 7 23:26 .git -rw-r--r-- 1 t******** t******** 231 Sep 7 23:25 .gitignore -rw-r--r-- 1 t******** t******** 315 Sep 7 23:26 README.md -rw-r--r-- 1 t******** t******** 73 Sep 7 23:25 babel.config.js -rw-r--r-- 1 t******** t******** 279 Sep 7 23:25 jsconfig.json drwxr-xr-x 643 t******** t******** 20480 Sep 7 23:26 node_modules -rw-r--r-- 1 t******** t******** 510210 Sep 7 23:26 package-lock.json -rw-r--r-- 1 t******** t******** 1102 Sep 7 23:25 package.json drwxr-xr-x 2 t******** t******** 4096 Sep 7 23:25 public drwxr-xr-x 6 t******** t******** 4096 Sep 7 23:25 src -rw-r--r-- 1 t******** t******** 118 Sep 7 23:25 vue.config.js |
10-4.webpack-bundle-tracker
vue ディレクトリで webpack-bundle-tracker をインストールします。
依存性を考慮し、--legacy-peer-deps
オプションを付けて実行しています。
1 2 |
(venv) ~$ cd vue (venv) ~/vue $ npm install webpack-bundle-tracker --legacy-peer-deps |
10-5.フロントサーバ起動
別の Ubuntu タブを開き、下記コマンドで Vueサーバを起動します。
1 |
npm run serve |
下記URLをクリックすると、Vue.jsの初期画面が表示されます。
アクセスURL
http://localhost:8080/
11.固定ページ追加
インストールが終わったところで、いよいよ Vue.js を色々と編集していきます。
11-1.urls 追加
プロジェクトの URL を設定します。
django/apps/urls.py
1 2 3 4 5 6 7 8 |
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('book/api/', include('apps.book.api.urls')), path('', include('apps.book.urls')) # (11-1)追加 ] |
次にトップページの URL を設定します。
django/apps/book/urls.py
(新規作成)
1 2 3 4 5 6 |
from django.urls import re_path from . import views urlpatterns = [ re_path('', views.IndexView.as_view(), name='index'), ] |
11-2.views 追加
TemplateView を使用(インポート)して、固定ページを作成します。
django/apps/book/views.py
1 2 3 4 |
from django.views.generic import TemplateView class IndexView(TemplateView): template_name = 'book/index.html' |
11-3.template の作成
テストで h1 タグの文字を入力しておきます。
django/apps/book/templates/book/index.html
(新規作成)
1 2 3 4 5 6 7 8 9 10 11 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Book System</title> </head> <body> <h1>Vue JS Toogie 参上!</h1> ←★これ </body> </html> |
11-4.バックエンドサーバー起動
バックエンドサーバーを起動して、画面が表示されることを確認します。
さきほど npm を実行したものとは違う、もともと触っていたタブで、バックエンドサーバを稼働させます。
1 |
(venv) ~$ python3 manage.py runserver |
下記バックエンドURLにアクセス
http://localhost:8000/
確認したら、Ctrl + c でサーバを停止させます。
12.Webpack導入
12-1. django-webpack-loaderのインストール
django-webpack-loader とはなんなのかを ChatGPT さんに質問したところ、以下のような回答を得ました。
具体的には、Webpackによって生成されたアセット(バンドルされたファイル)のパスをDjangoのテンプレート内で動的に取得するための仕組みを提供します。
主な機能は以下のようになります。
1. Webpackの出力をDjangoテンプレートで使用可能にする
Webpackのビルド結果(通常はJSON形式のマニフェストファイル)を読み込んで、Djangoのテンプレートで使用することができます。
2. キャッシュバスティング:
Webpackによって生成されたファイル名にはハッシュが含まれていることが多く、これによりキャッシュの問題を避けることができます。django-webpack-loaderはこれを簡単に扱うことができます。
3. 開発モードのサポート:
開発中には、Webpack Dev Serverを使用してホットリロードやライブリロードを行うことが多いですが、django-webpack-loaderはこれにも対応しています。
ということで、ルートディレクトリ(drf3/django)で下記コマンドを実行し、django-webpack-loader をインストールします。
1 |
(venv) ~$ pip3 install django-webpack-loader |
インストールの結果は以下のような感じ
1 2 3 4 5 |
Collecting django-webpack-loader Downloading django_webpack_loader-3.1.0-py2.py3-none-any.whl.metadata (22 kB) Downloading django_webpack_loader-3.1.0-py2.py3-none-any.whl (19 kB) Installing collected packages: django-webpack-loader Successfully installed django-webpack-loader-3.1.0 |
12-2.settings.py 変更
Django の settings.py に追記します。
- 一番先頭にosのインポート文を追記します。
- webpack_loader を INSTALLED_APPS に追加します。
- 一番下の方に Webpack Loader の設定を追記します。
apps/settings.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import os (~中略~) INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'webpack_loader', # (12-2)追加 'apps.book' ] (~中略~) # Webpack Loader WEBPACK_LOADER = { 'DEFAULT': { 'BUNDLE_DIR_NAME': 'dist/', 'STATS_FILE': os.path.join(BASE_DIR, '..', 'vue', 'dist', 'webpack-stats.json') } } |
Webpack Loader の設定で BASE_DIR の次が 「..」 となっていますが、これは今回作成するディレクトリ構造のため、1階層上であることを示しています。
12-3.template 変更
webpack_loader を使用できるように変更します。
render_bundle でフロントエンドからの情報を表示します。
apps/book/templates/book/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{% load render_bundle from webpack_loader %} ←★これ <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Book System</title> </head> <body> <h1>Vue JS Toogie 参上!</h1> <!-- 追加 --> <div id="app"></div> {% render_bundle 'app' %} ←★これ <!-- // 追加 --> </body> </html> |
12-4.vue.config.js 追加
vue ディレクトリ以下に vue.config.js が作成されているので、下記のように編集します。
drf3/vue/vue.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
const BundleTracker = require("webpack-bundle-tracker"); const path = require("path"); module.exports = { publicPath: "http://127.0.0.1:8080/", outputDir: "./dist/", chainWebpack: (config) => { config .plugin("BundleTracker") .use(BundleTracker, [ { path: path.resolve(__dirname, 'dist'), // ディレクトリパスを指定 filename: 'webpack-stats.json' // ファイル名のみを指定 } ]) config.output.filename("bundle.js"); config.optimization.splitChunks(false); config.resolve.alias.set("__STATIC__", "static"); }, devServer: { hot: true, // hotOnly を hot に変更 https: false, allowedHosts: 'all', // allowedHostsを設定 headers: { "Access-Control-Allow-Origin": ["*"] }, watchFiles: { paths: ['src/**/*', 'public/**/*'], // 監視するファイルパス options: { usePolling: true, }, }, }, }; |
12-5.Webpackのビルドが成功しているか確認
1 |
npm run build |
12-6.フロントエンド起動
frontend フォルダで vue.js を起動させます。
1 |
~/frontend $ npm run serve |
12-7.バックエンド起動
バックエンド側サーバを稼働させます。
1 |
(venv) ~$ python3 manage.py runserver |
12-8.確認
バックエンドの方の URL にアクセスします。
アクセスURL
http://localhost:8000/
左肩に、11-4で確認した「Vue JS Toogie 参上!」が表示され、それ以下はVue.jsのデフォルトページ内容が表示されました。
つまり Django のテンプレートに記載した文字と Vue.js の初期画面の両方が表示されたと言うことになります。
Django のテンプレートの文字(「Vue JS Toogie 参上!」)を削除すれば、完全にバックエンドとフロントエンドを分けることができたということになります。
テスト用に置いた h1 タグを削除しておきます。
apps/book/templates/book/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{% load render_bundle from webpack_loader %} <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Book System</title> </head> <body> <div id="app"></div> {% render_bundle 'app' %} </body> </html> |
閑話休題
ここで変な動きに気づきました。
ブラウザアクセス時になぜかバックエンドのURL(http://localhost:8000/)を指定すると、
http://localhost:8000/http://127.0.0.1:8080/
というURLにリダイレクトされるようになっていました。
どこか設定を間違った、足りていないのか色々調べましたが、全く直ってくれません。
仕方ないので、とりあえずはそのままにしておきますが、修正する方法が分かり次第、修正したいと思います。
なお、管理画面へは http://localhost:8000/admin/login/ でログイン画面が表示され、
APIへは、 http://localhost:8000/book/api/books/ でアクセス可能です。
フロントが絡むとおかしくなるので、vue.js 関連の設定かな? と感じています。
第4回目はここまで。次回はフロント側で使用するテンプレート用フレームワーク「Vuetify」をインストールしてみます。