LoginSignup
20
31

More than 5 years have passed since last update.

既存のDjangoアプリケーションにVue.jsを導入

Posted at

はじめに

実務にて、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

この時点で以下の様なディレクトリ構造になります。

ディレクトリ構成(vue-app追加)
:root
 ├─ :django-root
 └─ :vue-app

Webpackの設定

Webpackでビルドしたhtml,css,jsファイルをDjango側のディレクトリ(templates,static)配下に配置するため設定を変更

vue-app/config/index.js
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は明示的に分ける必要があります。

urls.py
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にもレンダリング用の設定を追加

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

main.js
// 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ファイルにて読み込みとしました。

hoge.vue
<script>
import JQuery from 'jquery'
let $ = JQuery

入れた後でimport $ from 'jquery’と書けばよかったと気づきました。

vue-app配下のディレクトリ構成

以下が完成形です。

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

終わりに

フロントエンド開発は未経験でしたが、
先人の知恵(記事)を参考にしながら試行錯誤した結果、比較的見通しの良い構成になったと思います。

参考にしたサイト

20
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
31