Make組ブログ

Python、Webサービスや製品開発、ライブラリー開発についてhirokikyが書きます

Webpack (v4) で複数のJavaScriptファイル、CSSファイルを分けてビルドする

webpackは便利ですが設定などは慣れが必要です。 僕は面倒なので、毎度自分の過去のプロジェクトからコピーして使っています。 その内容から抜粋してブログの記事にしています。

想定としてはSinglePageApplicationとしてはアプリを作らずに、フレームワークからJSを配布するWebアプリの構成です。 すべてのページをJSで作るならよいですが、一部のみアプリケーションとしたい場合はこの記事で説明されている設定を参考にしてください。

僕の考えですが、管理用のページや設定画面など一般的なWeb+DBの画面であれば、SPAとして作るのは手間が無駄に多いと考えています。 モデル定義+フォームの自動生成や、一般的なWeb+DBの画面構成はDjangoなどのWebフレームワークをそのまま使うほうが扱いやすいと思っています。 そのうえで、CSSはビルドしたい、Web画面で共通に使うJSをビルドしたい、アプリケーションとして動作するページのJSもVue.jsやvue-loaderなどで作りたい場合はよくあると思います。

SPAで作りたい人は vue-cli を使って、そのまま従うのが良いのではないでしょうか。

免責

この記事での情報や内容の正しさは保証しません。 最大限注意していますが、間違っていたり重大なバグがある可能性はあります。 それによって発生したどんな損害にも責任は持ちませんし、保証しません。自己責任で参考にしてください。

バージョン

$ webpack --version
4.6.0

記事内で特別に書きませんが、 style-loader などのインストールも必要です。 適宜、インストールしてください。

リポジトリー構成の想定

以下のように、 client 以下にJS、CSSのビルド用のディレクトリー、 web 以下にWebフレームワークで作るWebアプリのディレクトリーを分けています。 client ディレクトリーからビルドして、 web から使えるようにします。

repo/
  - client/
    - webpack.config.js
    - src/
        - editor.js
        - webcommon.js
  - web/
    - myproject/static/dev/js/  # Webアプリから配信

複数JSファイルをビルドする

アプリケーションとしてのJavaScriptと、Web画面で使うJavaScriptを分けてビルドしています。 editor.js をアプリケーションとしてのJS、 webcommon.js を(ナビゲーションバーの操作などの)一般的な画面のJSと考えてください。

module.exports = {
  mode: 'development',
  output: {
    path: __dirname + '/../',
    filename: '[name]'
  },
  entry: {
    'web/myproject/static/dev/js/editor.js': './src/editor.js',
    'web/myproject/static/dev/js/webcommon.js': './src/webcommon.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader'
        },
        exclude: /(node_modules|dist)/
      }
    ]
  },
  plugins: []
}

これで、 ./src/editor.js をエントリーポイントにするJSファイルが ../web/myproject/static/dev/js/editor.js にビルドされます。 entry の中身を増やせばビルドするJSファイルも増やせます。

フレームワーク側でのJSファイルの扱い

JSファイルはフレームワーク側で管理できるディレクトリーに書き出しています。 このとき、開発用のJSは static/dev 以下に保存しています。 Webアプリケーションが開発環境時にはこのディレクトリー内の静的ファイルを使うように設定して、本番環境時は別のファイルを使うようにしています (CloudFrontから配信された、UglifyされたJSやCSS)。 static/dev はGit管理しないようにすることでGitリポジトリーの肥大化も防げます。

Webpack 4でCSSをビルドする

JSファイルだけでなくCSSファイルを別途ビルドしたいことがあります。 ただし今回は、「JSファイル内のCSSを別に配信する」目的ではありません。 JSファイル内のCSSはそのまま組み込むようにしておいて、別途、CSSのみをビルドする方法を説明します。

webpackではCSSファイルはビルドできません。 extract-text-webpack-plugin を使ってうまくできるようにします。

ただし、2018年5月3日時点では extract-text-webpack-plugin はWebpack4に対応していないので、インストール時は以下のようにしてBeta版を使います。

$ npm install --save-dev extract-text-webpack-plugin@next

webpack.config.js にCSSの設定を追加する

単に extract-text-webpack-plugin の設定を追加すると、既存のJSのビルドにも影響してしまいます。 上記したJSの設定とは別に、CSSをビルドする設定を書きます。

module.exports = [
  { ... },  // 上記したJSのビルドの設定
  {
    mode: 'development',
    output: {
      path: __dirname + '/../',
      filename: '[name]'
    },
    entry: {
      'web/myproject/static/dev/style/main.css': './src/main.scss'
    },
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: [{
              loader: "css-loader"
            }, {
              loader: "sass-loader"
            }]
          })
        }
      ]
    },
    plugins: [
      new ExtractTextPlugin({
        filename: (getPath) => {return getPath('[name]')}
      })
    ]
  }
]

これで、 ./src/main.scss をエントリーポイントにするSCSSファイルが、 ../web/myproject/static/dev/style/main.cssCSSファイルとしてビルドされます。

もちろんJSファイルの設定も渡しているので、 webpack コマンドのみでビルドできます。 両者の設定で重複している部分は共通の設定にしておくと良いでしょう。

まとめ

最近作っているものは PyQ も含めてこの構成で作っています。 SPAではやりたくないなぁ、という人にはオススメしたいです。