概要
個人開発中のFlaskアプリでjavascriptが大きくなりすぎたため、jsファイルを分割して管理することにしました。
しかし分割しすぎるとパフォーマンスに問題がでるらしく、回避のためwebpackで数個のjsファイルにbundle(build)する形をとることにしました。
ここで困ってしまったのが、「FlaskとWebpackを併用する場合のフォルダ構造やデバッグ/ビルドの設定のあるべき姿」とは?という点です。
結局正解は分からないままなのですが、備忘録がてら自分がどうしたかを記載しておきます。
前提知識
Flaskとは
Webアプリのバックエンドをpythonで書くことができるフレームワークの1つです。他にはdjangoなどがあります。
Webpackとは
複数の JavaScript モジュールを一つ(またはいくつか)のファイルへバンドル(=bundle: 束にする、包む)してくれます。
モジュールを 1 つ(もしくは少数)にまとめることでブラウザからのリクエスト数を減らし、ファイル転送の効率が向上します。
採用した構造・設定
フォルダ構造
まずフォルダ構造については次のようにしました。
もともとFlaskアプリとして作っていたため、ちょっと歪な気がします。詳しい説明・今後修正したい点についてはコメントに記載の通りです。
root
├─.vscode
│ ├─launch.json # webpackでbundle→front/distからstaticにコピー→run.pyを実行する設定を記載
│ └─tasks.json # launch.jsonを構成する各タスクを定義
├─backend
│ ├─routes #flaskのpyファイルを配置
│ └─templates # front/back共用のため、rootに配置すべきだったかも。ここのhtmlファイルはstaticのjsをロードする。
├─env # venvの仮想環境 pythonに関わるもののためbackend下の方が適切かも
├─frontend
│ ├─dist # ビルド(webpackのbundle)結果は一旦ここに配置
│ ├─node_modules # node.jsのパッケージの実物
│ ├─src # module毎にjsをbundleする(複数のbundleファイルを出力する)
│ │ ├─moduleA
│ │ └─moduleB
│ ├─package.json # node.jsのパッケージのリストを記載
│ └─webpack.config.js # webpackのbundle設定を記載
├─static # distからbundleしたjsをここにコピー。cssもここ
├─ run.py # app.run() flaskの実行処理を記載
├─ requests.txt # backend下の方が適切かも
├─ LICENSE.txt
└─ .gitignore
設定内容
launch.json, tasks.json, webpack.config.jsの設定内容は次の通り。
F5キーでwebpackのバンドルからFlaskの実行、ブラウザの起動を行います。
※jsonにコメントは本来書けないので、コピペの時はコメントを消してください。
{
"version": "0.2.0",
"configurations": [
{
"name": "Flask with npm build",
"type": "python",
"request": "launch",
"program": "./run.py",
"console": "integratedTerminal",
"justMyCode": true,
"preLaunchTask": "build-and-copy-and-open-browser" //webpackのビルド,ビルド成果物のコピー,ブラウザ起動
},
{
"name": "Flask Only",
"type": "python",
"request": "launch",
"program": "./run.py",
"console": "integratedTerminal",
"justMyCode": true,
"preLaunchTask": "open-browser", //ブラウザ起動
}
]
}
{
"version": "2.0.0",
"tasks": [
{
// ビルド
"label": "build",
"type": "shell",
"command": "npm --prefix ./frontend run build",
"problemMatcher": []
},
{
// ビルド成果物のコピー
"label": "copy-js-files-from-dist-to-static",
"type": "shell",
"command": "cp ./frontend/dist/*.js ./static/",
"problemMatcher": []
},
{
// ビルド&ビルド成果物のコピー
"label": "build-and-copy",
"dependsOn": ["build", "copy-js-files-from-dist-to-static"],
"dependsOrder": "sequence",
"problemMatcher": []
},
{
// ブラウザ起動
"label": "open-browser",
"type": "shell",
"command": "start http://localhost:5000",
"problemMatcher": []
},
{
// ビルド,ビルド成果物のコピー,ブラウザの起動
"label": "build-and-copy-and-open-browser",
"dependsOn": ["build-and-copy", "open-browser"],
"dependsOrder": "sequence",
"problemMatcher": []
}
]
}
const path = require('path');
module.exports = {
devtool: 'source-map',
devServer: {
static: {
directory: path.join(__dirname, 'dist'), // 静的ファイルのディレクトリ
},
hot: true // ホットモジュールリプレースメントを有効にする
},
mode: 'development',
// エントリーポイント(主なJavaScriptファイル)
entry: {
'moduleA': './src/moduleA/main.js',
'moduleB': './src/moduleB/main.js',
},
// 出力先は一旦dist
output: {
filename: '[name].js',
path: path.resolve(__dirname,'dist')
},
};