はじめに
実務にて、PythonのDjangoフレームワークにて構築されたWebアプリケーションに対して、後付けでVue.jsを適用したのでその流れを自分の備忘として残します。
Djangoのテンプレート機能(主なライブラリとしてjQuery)を利用して作成していたWeb画面を全てVue.js(Webpackビルド)に置き換えをしました。
Vue.js導入にあたって、Vue-Router,Vuexも導入
フロントエンドのライブラリはBootstrap-vueとjQueryを採用
※ DOM操作以外の既存コードは極力流用したいがためにajax部分も含めてjQueryを採用しました。
既存アプリケーションの構成
Djangoのテンプレート機能とREST frameworkが共存している構成
フロントエンドのライブラリは主にBootstrap4とjQueryを利用していました。
:root
└─ :django-root
├─ manage.py
└─ :django-mysite
├─ settings.py
├─ urls.py
└─ :my-app
├─ :static
├─ :css
├─ :images
└─ :js
├─ :templates
└─ index.html
├─ __init__.py
├─ models.py
├─ serializer.py
├─ urls.py
└─ views.py
Vue.jsのインストール & プロジェクト作成
まずはvue-cliのインストール
$ npm install -g vue-cli
webpackビルド用のプロジェクトを作成
$ vue init webpack vue-app
vue-router,vuexを入れるか問われるのでYESを選択
忘れたときは以下コマンドを実行します。
$ npm install vue-router --save
$ npm install vuex --save
この時点で以下の様なディレクトリ構造になります。
:root
├─ :django-root
└─ :vue-app
Webpackの設定
Webpackでビルドしたhtml,css,jsファイルをDjango側のディレクトリ(templates,static)配下に配置するため設定を変更
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
// proxyTable: {},
proxyTable: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
pathRewrite: { // 開発サーバーでもDjangoのAPIにアクセスできるように設定
'^/api': 'api'
}
}
},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
// Use Eslint Loader?
// If true, your code will be linted during bundling and
// linting errors and warnings will be shown in the console.
useEslint: true,
// If true, eslint errors and warnings will also be shown in the error overlay
// in the browser.
showEslintErrorsInOverlay: false,
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
// デフォルトのSourceMapは相対パスを参照しているらしく、この環境ではバグになるらしい。
cssSourceMap: false
},
build: {
// Template for index.html
// index.htmlの出力先をDjangoのtemplates配下に変更
index: path.resolve(__dirname, '../../django-root/myapp/templates/dist/index.html'),
// Paths
// 静的ファイルの出力先をDjangoのstatic配下に変更
assetsRoot: path.resolve(__dirname, '../../django-root/myapp/static'),
assetsSubDirectory: 'build',
assetsPublicPath: '/static/',
Django側のURL設定
Django側に出力したindex.htmlを配信するためのURLを追加
DjangoのREST APIはそのまま利用するため、URLは明示的に分ける必要があります。
urlpatterns = [
url(r'^$', schema_view),
url(r'^admin/', admin.site.urls),
url(r'^v1/api', include('myapp.urls')), # 既存のAPIやtemplateのレンダリング
url(r'^v2/vue', views.top), # Vue.js root url
]
Django側のViewsに追加
urls.pyに追加したのでviews.pyにもレンダリング用の設定を追加
# **** <Vue.js テンプレート配信> ****
def top(request):
"""Renders the about page."""
assert isinstance(request, HttpRequest)
return render(request, 'dist/index.html')
ライブラリの導入
- jQuery: ajax通信、既存コード流用時に必要になる。
- Bootstrap-vue: UIはBootstrapで統一する。
- fontawesome/vue: Bootstrap-vueにはアイコンがないため導入
- vue-loading-spinner: ローディングアイコンを自作するのが面倒だったため導入
以下コマンドを実行
$ npm install jquery --save
$ npm i bootstrap-vue --save
$ npm i --save @fortawesome/fontawesome-svg-core \
$ npm i --save @fortawesome/fontawesome-svg-core
$ npm i --save @fortawesome/free-solid-svg-icons
$ npm i --save @fortawesome/vue-fontawesome
main.jsでライブラリをimport
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'
import App from './App'
import router from './router'
import store from '@/store/index'
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faTrash, faSearch, faDownload } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
library.add(faTrash)
library.add(faSearch)
library.add(faDownload)
Vue.component('font-awesome-icon', FontAwesomeIcon)
Vue.use(BootstrapVue)
Vue.config.productionTip = false
/* eslint-disable */
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})
jQueryは使用する各vueファイルにて読み込みとしました。
<script>
import JQuery from 'jquery'
let $ = JQuery
入れた後で import $ from 'jquery’
と書けばよかったと気づきました。
vue-app配下のディレクトリ構成
以下が完成形です。
:vue-app
├─ :build
├─ :config
├─ :node_modules
├─ :src # vue-appで使用するメインのソースの格納場所
| ├─ :components # 単一ファイルコンポーネントのソース格納場所
| | ├─ :mixin # MIXINとして作成したコンポーネントの格納場所
| | | └─ API.vue # API通信周りの関数を定義したMIXIN
| | ├─ :pages # 各画面のコンポーネントの格納場所
| | | └─ TopPage.vue # TOP画面のコンポーネント
| | └─ :partial # 画面部品としてのコンポーネントの格納場所
| | ├─ LoadingIcon.vue # ローディングアイコンのコンポーネント
| | └─ PageHeader.vue # ヘッダーのコンポーネント
| ├─ :lib # 純粋なJSファイルの格納場所
| | └─ utility.js # 汎用的に使用できる関数を集めたソース
| ├─ :router # vue-router関連のソース格納場所
| | └─ index.js # vue-routerのルーティング定義
| ├─ :store # vuex関連のソース格納場所
| | ├─ :modules # モジュール分割した状態管理ソースの格納場所
| | | └─ User.js # Userの状態管理
| | └─ index.js # vuexの共通ソース
| ├─ App.vue # Vueインスタンスから一番最初に呼ばれるコンポーネント
| └─ main.js # Vueインスタンスの生成、ライブラリの読み込みなど
└─ :static # ビルドしない静的ファイル
└─ favicon.ico
終わりに
フロントエンド開発は未経験でしたが、
先人の知恵(記事)を参考にしながら試行錯誤した結果、比較的見通しの良い構成になったと思います。