Django+Reactアプリケーション開発の準備 ルーティング設定とReactのビルド自動化

# はじめに

Djangoのプロジェクト内にReact appを作成するだけでは、それぞれ

* Django => 8000 port 
* React => 3000 port


というポートで接続して確認することになります。


* ReactのWelcomeページを8000番で表示
* Bootstrapの適用
* Reactのビルド自動化

までやりたいと思います。
(Djangoのサーバを起動したときに同時にビルドするようになります)

# セットアップ

```
$ django-admin startproject project
$ cd project
$ create-react-app frontend
$ cd frontend
$ yarn run build
```

django project内にreact appを作成してビルドしました。
起動してみます。

```
$ ./manage.py runserver
```

このままの状態では、8000番ポートに出力されるのはdjangoプロジェクトのスタートページです。
まずこれをReactのWelcomeページにしたい。

# ReactのWelcomeページを8000番で表示

設定ファイルを以下のように編集します。

```project/settings.py

......

# DIRSを追記

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'frontend', 'build'),
        ],
        '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',
            ],
        },
    },
]

......

STATIC_URL = '/static/'

# STATICFILES_DIRSを追記 
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'frontend', 'build', 'static'),
]

```

```project/urls.py
from django.contrib import admin
from django.urls import path, re_path
from django.views.generic import TemplateView

urlpatterns = [
    path('admin/', admin.site.urls),

    re_path('.*', TemplateView.as_view(template_name='index.html')),
]
```

これで、以下のように8000番ポートでReactのWelcome画面にルーティングされるようになりました。

![スクリーンショット 2018-09-15 0.44.47.png](https://qiita-image-store.s3.amazonaws.com/0/174325/274913e8-1faf-d592-512d-58ca778d40e8.png)

# Bootstrapを適用してみる

とりあえずgetbootstrap.comからproject/frontend/public/index.htmlにコピペ

```project/frontend/public/index.html
<!doctype html>
<html lang="ja-jp">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

    <title>Hello, world!</title>
  </head>
  <body>
    <!-- ここだけ追記 -->
    <div id="root"></div>
    <h1>Hello, world!</h1>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
  </body>
</html>
```

ビルドしてサーバ起動。

```
$ pwd
project/frontend

$ yarn run build

$ cd ../

$ ./manage.py runserver
```

ブラウザで確認。

![スクリーンショット 2018-09-15 0.56.49.png](https://qiita-image-store.s3.amazonaws.com/0/174325/88eb42f3-ca79-5600-7f31-9689cdfe0293.png)

オッケ〜:thumbsup:

# build自動化

このままわざわざfrontendに行ってbuildするのは面倒なので、runserverと同時にビルドするように設定します。
`./manage.py runserver react`としたとき、ビルドするようにします。
つまり、argv(argument vector:コマンドライン引数)の3つ目が`react`のときにです。

```manage.py
#!/usr/bin/env python
import os
import sys

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc

# 以下追記

    try:
        if sys.argv[2] == "react":
            project_root = os.getcwd()
            os.chdir(os.path.join(project_root, "frontend"))
            os.system("yarn run build")
            os.chdir(project_root)
            sys.argv.pop(2)
        execute_from_command_line(sys.argv)
    except IndexError:
        execute_from_command_line(sys.argv)
    else:
        execute_from_command_line(sys.argv)
```
(例外処理しないと何故か`sys.argv[2]`なんてないと怒られます
`print(sys.argv[2])`で普通に出力されるのになんででしょう？教えてください...:bow_tone1:

適当に`project/frontend/public/index.html`を編集して`./manage.py runserver react`を実行してみましょう。

これだけでReactがビルドされて出力結果が変わっているはずです。

# 参考
https://www.youtube.com/watch?v=kmpY6g5hYZI を参考にしています。
というか結構そのまま日本語にしてます。