【Django】DjangoによるWeb開発プロジェクトPart3 - webpackでフロントエンドをDjangoから独立させるまで  -

## はじめに

今日はフロントエンドの設定を行います。

## フロントエンドをDjangoと独立させてマネジメントできるようにwebpackを追加する

一先ず、今後どうなるかは分かりませんがRails5の開発と同じくバックエンドとフロントエンドでそれぞれの別に、独立したマネジメントツールで運用したいため、Djangoにもwebpackをインストールする事にします。
以前、[npmマネージャーからwebpackをインストールしていましたが](https://qiita.com/himrock922/items/5cfc21b0b296cd97b9c8)、今回はyarnマネージャーからインストールする事にします。

```bash
% sudo pkg update
% sudo pkg install yarn
```

なお、Djangoでwebpackを読み込むために[jango-webpack-loader](https://github.com/owais/django-webpack-loader)と言うWrapperを使います。
こちらは、webpack-bundle-trackerによって生成された出力ファイルをDjangoで使えるようにします。
また、今回はフロントエンドはbootstrap-vueを使う訳なのですが、それに伴いJavaScriptからcssを`import`できるように、各ローダを一緒にインストールしておきます。

### webpack, vue-bootstrapをインストール

```bash
% yarn add --dev webpack
% yarn add --dev bootstrap-vue
% yarn add --dev webpack-bundle-tracker css-loader style-loader babel-loader @babel/core vue
```

では、webpack.config.jsの設定を行なっていきましょう。

### webpack.config.jsの設定

```js:webpack.config.js
var path = require('path')
var BundleTracker = require('webpack-bundle-tracker')

module.exports = {
    entry: './frontend/packs/application.js',
    output: {
      path: path.resolve(__dirname, './public/bundles/'),
      filename: "[name]-[hash].js",
    },
    plugins: [
      new BundleTracker({filename: './webpack-stats.json'})
    ],
    module: {
        rules: [
            {
                test: /\.js$/,
                include: [ // use `include` vs `exclude` to white-list vs black-list
                    path.resolve(__dirname, "node_modules"), // white-list your app source files
                    require.resolve("bootstrap-vue"), // white-list bootstrap-vue
                ],
                loader: "babel-loader"
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
}
```

### エントリーポイントのapplication.jsを編集

application.jsでbootstrap-vueをimportするように記述します。ついでに必要なディレクトリを作成していきます。

```bash
% mkdir -p frontend/packs
% mkdir -p public/bundles
```

```js:frontend/packs/application.js
import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'

Vue.use(BootstrapVue);

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
```

以上で、development環境でwebpackのコンパイルを行います。

```bash
% ./node_modules/.bin/webpack --config webpack.config.js --mode=development
```

続いてはDjango側の設定です。

## Djangoのwebpack設定

pipでdjango-webpack-loaderをインストールします。その後、Djangoのsettings.pyを以下のように設定してあげましょう。

```bash
% pip install django-webpack-loader
```

```python:settings.py
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'public'),
)
WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'bundles/',
        'STATS_FILE': os.path.join(BASE_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',
]
```

テンプレートエンジンでwebpack_loaderとコンパイルしたmain.jsを読み込めるようにします。

```html:templates/application.html
{% load render_bundle from webpack_loader %}
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>{% block title %}Django Auth Tutorial{% endblock %}</title>
      {% render_bundle 'main' %}
  </head>
  <body>
    <main>
      {% block content %}
      {% endblock %}
    </main>
  </body>
</html>
```

## ログイン画面改善

webpackによるコンパイルが完了したので、BootStrapでログイン画面のデザインを改良してきましょう。下記のテンプレートを参考にします。
[https://getbootstrap.com/docs/4.0/examples/sign-in/](https://getbootstrap.com/docs/4.0/examples/sign-in/)

```css:packs/css/signin.css
html,
body {
  height: 100%;
}

body {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-align: center;
  align-items: center;
  padding-top: 40px;
  padding-bottom: 40px;
  background-color: #f5f5f5;
}

.form-signin {
  width: 100%;
  max-width: 330px;
  padding: 15px;
  margin: auto;
}
.form-signin .checkbox {
  font-weight: 400;
}
.form-signin .form-control {
  position: relative;
  box-sizing: border-box;
  height: auto;
  padding: 10px;
  font-size: 16px;
}
.form-signin .form-control:focus {
  z-index: 2;
}
.form-signin input[type="email"] {
  margin-bottom: -1px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
  margin-bottom: 10px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}
```

```js:frontend/packs/applications.js
import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'

Vue.use(BootstrapVue);

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import '../css/login.css'
```

```html:templates/login.html
{% extends 'application.html' %}

{% block title %}Login{% endblock %}
{% block content %}
<form method="post" class="form-signin">
  <h1 class="h3 mb-3 font-weight-normal"">ログイン画面</h1>
  {% csrf_token %}
  {{ form.as_p }}
  <button class="btn btn-lg btn-primary btn-block" type="submit">ログイン</button>
</form>
{% endblock %}
```

以上の設定でログイン画面を実装できました。

![スクリーンショット 2018-12-01 17.36.39.png](https://qiita-image-store.s3.amazonaws.com/0/144991/0eac49f2-1dd7-6450-f448-7539e5af09a7.png)


## まとめ

ログイン画面の画面がようやくリッチ(?)になりました。ただし、よく見てもらうと、`form.as_p`で展開しているフォーム部分にclass指定をしていないため、後々loginのviewをカスタマイズする必要があります。
ですが、そろそろ中身の実装に行きたいので、今回はここまで。

## シリーズ

[Part2](https://qiita.com/himrock922/items/bd020a0d313233556c97) ← [Part3](https://qiita.com/himrock922/items/facef344ad20f307720e) → [Part4](https://qiita.com/himrock922/items/563d52a5a9c74ee4e25e)
 
## 参考文献

[https://qiita.com/ynakahira/items/bd8580397fc2615b9dd8](https://qiita.com/ynakahira/items/bd8580397fc2615b9dd8)