QuasarFramework(Vue.js) + Django でアプリケーション開発（導入編）

QuasarFrameworkという、マテリアル風なVue.jsのCSSテンプレートと、Djangoでアプリケーションを作る際の導入部分をまとめました。
今回はDjangoのプロジェクトはすでに作成済み（開発用サーバーが動くところくらいまで）ということで説明をしていきます。

# 環境
* mac os High Sierra 10.13.3
* Djangoのプロジェクトを作成済み

# 参考
django インストール
https://docs.djangoproject.com/ja/2.0/intro/install/

チュートリアル1
https://docs.djangoproject.com/ja/2.0/intro/tutorial01/

QuasarFramework
http://quasar-framework.org/

# ファイル構成

以下のように、backendと、frontendを分けています。

quasar-django
│
┣ backend/ (今回はDjango)
│   ┣ src/...
│   ┣ ..
│   ┣ ..
│   ┣ ..
│
┣ frontend/ (今回はQuasarFramework)
│   ┣ src/...
│   │   ┣ static/quasar
│   ┣ ..
│   ┣ ..
│   ┣ ..

# QuasarFrameworkを設定する

## QuasarFrameworkをinstallする

```shell
# quasar cli install
$ npm install -g quasar-cli
# quasar プロジェクトの作成
$ quasar init default quasar-django
$ cd quasar-django
$ npm install

# 確認する
$ quasar dev
```

## QuasarFrameworkの出力モードを変更する

routesの設定を、history modeに変更します

```routes.js
...
mode: 'history',
...
```

config/index.js をhistory mode用に修正します。

```javascript
...
build: {
  env: require('./prod.env'),
  publicPath: '/',
  productionSourceMap: false,
}
...
```

## ビルドしたファイルの出力先を変更する

ビルドしたファイルの出力先をbackend側に設定します。(`quasar build`で出力されるファイルの保存先です。)

staticファイルの出力先を変更します。

```javascript:script.build.js
targetPath = path.join(__dirname, '../../backend/src/static/quasar')
```

index.htmlを出力先を変更します。

```javascript:webpack.prod.conf.js
new HtmlWebpackPlugin({
  filename: path.resolve(__dirname, '../../backend/src/static/quasar/index.html'),
...
}),
```

webpack.base.conf.jsを修正する。

```javascript:webpack.base.conf.js
output: {
  path: path.resolve(__dirname, '../../backend/src/static/quasar'),
  publicPath: config[env.prod ? 'build' : 'dev'].publicPath,
  filename: 'js/[name].js',
  chunkFilename: 'js/[id].[chunkhash].js'
},
```

cssファイルの出力先のcss-utils.jsを修正します。

```javascript:css-utils.js
...
module.exports.purify = function(cb) {
  var css = glob.sync(path.join(__dirname, '../../backend/src/static/quasar/**/*.css'))
  var js = glob.sync(path.join(__dirname, '../../backend/src/static/quasar/**/*.js'))
...
}
```

script.clean.jsを修正します。これは、quasar cleanを実行したときに削除されるファイルを削除します。

```javascript:script.clean.js
shell.rm('-rf', path.resolve(__dirname, '../../backend/src/static/quasar/*'))
shell.rm('-rf', path.resolve(__dirname, '../../backend/src/static/quasar/.*'))
```

## Django側の設定:ハッシュ値が入ったjavascriptファイルをdjangoで読み込む
Djangoで、ハッシュ値が入ったcssファイルを読み込む必要があるため、django-webpack-loaderを使って実装します。

* `$ pip install django-webpack-loader` で django-webpack-loaderをinstallする
* settings.py に以下のように設定を追記する。

```python:settings.py
INSTALLED_APPS = (
  ...
  'webpack_loader'
  ...
  )

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

# 読み込みたいハッシュ値入りのファイルパスが、STATICFILES_DIRS + '/' + BUNDLE_DIR_NAME になるように設定します。例えば、static/quasar/app.hash7.js のようにファイルが配置されている場合、以下のように設定します。
WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'quasar/',
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json')
    }
}
```


## QuasarFramework側の設定: webpack.prod.conf.js　にwebpack-stats.jsonを作成するように設定する

まず、webpack-bundle-trackerをnpm installします。

```shell
$ npm install --save-dev webpack-bundle-tracker
```

```javascript:webpack.prod.conf.js

var BundleTracker = require('webpack-bundle-tracker')

plugins: [
...  
// ここは、frontend側のフォルダを基準にしてpathを設定する
new BundleTracker({
  filename: '../backend/src/webpack-stats.json'
}),
...
]
```

あとめちゃめちゃはまったのが、`webpack-stats.json`のpublicPathです。
webpack.prod.conf.js　で必ず`publicPath`の設定します。これがないと、django側で、render_bundleでrenderingするときに、pathの設定がうまくされません。

webpack.prod.conf.jsに直接指定する場合は以下のように指定します。

```javascript
output: {
    path: config.build.assetsRoot,
    publicPath: '/static/quasar/',
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  // filename: utils.assetsPath('js/[name].js'),
  // chunkFilename: utils.assetsPath('js/[id].js')
},
```

もしくは、index.jsにpublicPathを追加して、指定することもできます。

```javascript
build: {
  env: require('./prod.env'),
  publicPath: '/static/quasar/',
  productionSourceMap: false,

  // Remove unused CSS
  // Disable it if it has side-effects for your specific app
  purifyCSS: true
},
```

`quasar build`を実行して、backend/src/webpack-stats.jsonが出力されていれば成功です。

## Django側: index.htmlを作成する
`quasar build`で出力されるindex.htmlファイルを利用して, templates/index.htmlファイルを以下のようなコードで作成します。

```html
{% load staticfiles %}
{% load render_bundle from webpack_loader %}

<!DOCTYPE html>
<html lang=en>
  <head>
    <meta charset=utf-8>
    <meta name=format-detection content="telephone=no">
    <meta name=msapplication-tap-highlight content=no>
    <meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width">
    <title>Quasar App</title>
    <link rel=icon href=statics/quasar-logo.png type=image/x-icon>
    <!-- <link href=/static_in_pro/our_static/quasar/app.636237cac568b3b5bca021d177df3447.css rel=stylesheet> -->
    {% render_bundle 'app' 'css' %}
  </head>
  <body>
    <div id=q-app></div>
    <script type=text/javascript src="{% static 'quasar/js/manifest.js' %}"></script>
    <script type=text/javascript src="{% static 'quasar/js/vendor.js' %}"></script>
    <script type=text/javascript src="{% static 'quasar/js/app.js' %}"></script>
  </body>
</html>
```

また、urls.pyに、上記のindex.htmlのTemplateViewを作成します。

```python:urls.py
from django.urls import path
from django.views.generic import TemplateView

# django2.0 以降では、re-pathを使う
urlpatterns = [
  re_path('.*', TemplateView.as_view(template_name='index.html'), name='index_quasar'),
]
```

`$ python manage.py collticstatic`と、`$ python manage.py runserver`を実行して、`http://127.0.0.1:8000/`にアクセスして、QuasarFrameworkで作成したページが表示されていれば成功です！

# まとめ
初めの設定がちょっと面倒ですが、Djangoは、DjangoRestFrameworkがあるので、フロントエンドと、バックエンドを分けて作成しやすそうですね。