diadia

興味があることをやってみる。自分のメモを残しておきます。

django vueを追加する

MPAでvueを使いたい。。。
色んな方法で実現できると分かった。

  • cdnを使う方法
  • vue cliを使う方法
  • vue cliを使わないで行う方法

最終的にはvue cliを使って構築するのがわかりやすいと感じた。cdnはもちろんかんたんだけれどもvuetifyを組み合わせて使う方法が全然わからなかった。

vue cliを使わない方法を試してみたのでそのメモを記す。 ファイルの構成を以下のようなりわかりやすいと感じた。

PROJECT
 - assets
 - django-project
 - node_modules
 - package-lock.json
 - package.json
 - webpack-stats.json
 - webpack.config.js

仕組みは ./node_modules/.bin/webpack --config webpack.config.jsを実行するとwebpack-stats.jsonがPROJECTのディレクトリに生成される。このファイルをdjango-webpack-loaderが読み込みvueが表示される仕組み。

webpackについてはこれを見ればわかる。 https://qiita.com/soarflat/items/28bf799f7e0335b68186:totle

webpack.config.jsはwebpackの設定ファイル。 エントリーポイントや、ファイルの出力場所、プラグインなどを設定することができます。

モジュール化するためにjavascript

export default function

を使うようだ。 それについてはここに詳しく書いてある. ES6のexportについて詳しく調べた - Qiita

webpackコマンドはnode_modules/.bin/webpackに実行ファイルがあるので別にパスを通さなくてもこれで実行すれば良い。

webpackのメリット

  • 機能ごとにファイルを分割(モジュール化)する開発ができる
  • 自分が作成したモジュールだけでなく、外部モジュール(npmなどでインストールできるパッケージvuetifyなど)も利用できる
  • リクエスト数を減らせる
  • 依存関係を解決したファイルを出力できる

外部モジュールを利用するときはどのようにすれば利用できるのか...

npmにインストールする。

npm install jquery --save

そしてmain.js(エントリポイントでimportすれば良い)

import $ from 'jquery';

参考記事: django-webpack-loader のセットアップ - Qiita

Vue cliを使ってMPAを実現する

webpackのみでdjangoとvueを統合する場合はwebpack.config.jsでcss関係の調整が必要で知識が必要になる。 これは自分で調整するために行うので別途知識を補充する必要がある。
一方vue cliを使う方法はvue cliが色々なパッケージの調整をしてくれるのでcssについて考える必要がなくてなんとか環境を構築することができた。

Vue CLI は、アプリケーションの構築の複雑さを抽象化するために作られた次世代の cli ツールです。Vue CLI でアプリを起動すると、公式の WebPack の更新や構成の変更、Vuetify の更新を困難なアップグレードプロセスなしで取得することもできます。

クイックスタート — Vuetify.js

環境構築方法をメモしておく。

前提: - vuetifyを導入する - django-webpack-loaderを使って構築する

環境

Django==2.2.6
django-webpack-loader==0.7.0

webpack-bundle-tracker@0.4.3
vue/cli@4.4.6

最初にdjangoのインストール

pip install django

プロジェクトの作成

django-admin startproject myproject
cd myproject

以下を入力してプロジェクトの起動

python manage.py runserver

http://127.0.0.1:8000ここにアクセスして以下が表示されればココまではおっけい。 f:id:torajirousan:20200703094305p:plain

djangonのプロジェクトテンプレート準備する

  • settings.pyにおいてテンプレートディレクトリを定めること
  • テンプレートを作成する
  • urls.pyでテンプレートを表示させる設定を行う
#myproject/myproject/settings.py

#以下を追加
TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')

#DIRSにTEMPLATES_DIRを加える
TEMPLATES = [    
{        
'BACKEND': 
'django.template.backends.django.DjangoTemplates',        
'DIRS': [TEMPLATES_DIR,],        
'APP_DIRS': True,        
'OPTIONS': {            
'context_processors': [                'django.template.context_processors.debug',                'django.template.context_processors.request',                'django.contrib.auth.context_processors.auth',                'django.contrib.messages.context_processors.messages', 
           ],
        },
    },
]

テンプレートを作成する。

# myproject/templates/application.html


<h2>ああああああ</h2>

urls.pyのセッティング

#myproject/myproject/urls.py

from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView


urlpatterns = [
    path('admin/', admin.site.urls),
    path("",
        TemplateView.as_view(template_name="application.html"),
        name="app",
    ),
]

ここまでは通常のdjangoのプロジェクトを作っていく流れです。ここからvue cliを使ってvueのプロジェクトを作成していきます。

pip install django-webpack-loader==0.7.0
#myproject/myproject/settings.py
#以下を追加する
FRONTEND_DIR = os.path.join(BASE_DIR, 'frontend')


WEBPACK_LOADER = {
    'DEFAULT': {
        'CACHE': DEBUG,
        'BUNDLE_DIR_NAME': '/bundles/',  #最後にスラッシュを忘れないこと
        'STATS_FILE': os.path.join(FRONTEND_DIR, 'webpack-stats.json'),
    }
}

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'webpack_loader', #これを追加
]

settings.pyに記述したwebpack_loaderやWEBPACK_LOADERはdjango-webpack-loaderに関するものである。
INSTALLED_APPSでdjango-webpack-loaderを有効にする。
WEBPACK_LOADERの'STATS_FILE'でwebpack-stats.jsonを読み込むパスを定める。webpack-stats.jsonはバンドル化したファイルに関連するファイルで、これを通じてバンドル化したファイルを読み込むのだろうと推測している。詳しくはまだ調べきれていない。

次にvueのプロジェクトを作成する。

npm install -g @vue/cli
vue --version

@vue/cli 4.4.6
vue create frontend

vuetifyをvue cliを使ってプロジェクトに加える。この方法を使うとwebpackのみで構築する方法と違ってwebpack.config.jsを自分でいじる必要がなくなるのでハマるリスク回避できる。webpackのみでハマったのでこれはありがたいです。

cd frontend
vue add vuetify

関連するパッケージをインストールする。

npm install

このバージョンをインストールしないと後々DJANGO側でエラーが出てしまい困ることになるので重要。

npm install --save-dev webpack-bundle-tracker@0.4.3
npm run serve

下のように表示されればおっけい f:id:torajirousan:20200703110443p:plain

vue.config.jsを編集する。

const BundleTracker = require("webpack-bundle-tracker");

module.exports = {
    publicPath: "http://127.0.0.1:8080/",
    outputDir: './dist/',

    chainWebpack: config => {

        config.optimization
            .splitChunks(false)

        config
            .plugin('BundleTracker')
            .use(BundleTracker, [{filename: '../frontend/webpack-stats.json'}])

        config.resolve.alias
            .set('__STATIC__', 'static')

        config.devServer
            .public('http://0.0.0.0:8080')
            .host('0.0.0.0')
            .port(8080)
            .hotOnly(true)
            .watchOptions({poll: 1000})
            .https(false)
            .headers({"Access-Control-Allow-Origin": ["\*"]})
            }
        };
cd frontend
npm run serve
python manage.py runserver

これでdjangoのテンプレートとvueを統合することができた。
次に各エンドポイントに応じてテンプレートを変更することを実現させる。これはもちろん使用されるテンプレートに応じてvueを使い分けるということである。

これはvue.config.jsを修正すれば良い。module.exportsにpagesを加えれば良い。またpagesの値を定める。

const BundleTracker = require("webpack-bundle-tracker");


//追加事項
const pages = {
    'vue_app_01': {
        entry: './src/main.js',
        chunks: ['chunk-vendors']
    },
    'vue_app_02': {
        entry: './src/main2.js',
        chunks: ['chunk-vendors']
    },
}


module.exports = {
    pages: pages, //これを追加
    publicPath: "http://127.0.0.1:8080/",
    outputDir: './dist/',
    ...
    ...
    }

次に./src/main2.jsを作成する。これは例として以下のようなファイルとする。

import Vue from 'vue'
import App2 from './App2.vue' #後でファイルを作成する
import vuetify from './plugins/vuetify';

Vue.config.productionTip = false
Vue.config.delimiters = ["[[", "]]"];


new Vue({
  vuetify,
  render: h => h(App2)
}).$mount('#app')

App2.vueの作成

cd src
touch App2.vue
<template>
  <v-app>
    <v-app-bar
      app
      color="primary"
      dark
    >
      <div class="d-flex align-center">
        <v-img
          alt="Vuetify Logo"
          class="shrink mr-2"
          contain
          src="https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png"
          transition="scale-transition"
          width="40"
        />

        <v-img
          alt="Vuetify Name"
          class="shrink mt-1 hidden-sm-and-down"
          contain
          min-width="100"
          src="https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png"
          width="100"
        />
      </div>

      <v-spacer></v-spacer>

      <v-btn
        href="https://github.com/vuetifyjs/vuetify/releases/latest"
        target="_blank"
        text
      >
        <span class="mr-2">Latest Release</span>
        <v-icon>mdi-open-in-new</v-icon>
      </v-btn>
    </v-app-bar>

    <v-content>
      <HelloWorld/>
    </v-content>
  </v-app>
</template>

<script>
import HelloWorld from './components/HelloWorld';

export default {
  name: 'App',

  components: {
    HelloWorld,
  },

  data: () => ({
    //
  }),
};
</script>

次に必要なdjangoプロジェクトのテンプレートを調整する

urlpatterns = [
    path('admin/', admin.site.urls),
    path("",
         TemplateView.as_view(template_name="application.html"),
         name="app",),
    #以下を追加する
    path("test/", 
        TemplateView.as_view(template_name="test.html"),
         name="app",),
]
touch templates/test.html
{% load render_bundle from webpack_loader %}

<div id="app">

</div>

vue_app_02


{% render_bundle 'chunk-vendors' %}
{% render_bundle 'vue_app_02' %}

これでテンプレートによって別のvueを使うことができるようになる。

参考: Integrating Django and VueJs with Vue CLI 3 and Webpack Loader

html - Exception Value: string indices must be integers : Render bundle error vue + django - Stack Overflow

render_bundle failing with TypeError: string indices must be integers · Issue #227 · owais/django-webpack-loader · GitHub