webpackでjavascriptにcssをまとめないほうがいいという話

朝起きて仕事したら1日終わってる社畜と変わらない日々になってきているなおキーヌです。

会社員と違って頑張れば頑張るほど自分のお金になるので 同じ忙しいならフリーランスのほうが性に合ってるなと感じてます。

さて今回はnode.jsで開発している案件の改修を行っていて webpackからcssを分離するということをやっています。

基本的にWeb制作側の人間はjsとcssは分けるのですが、 システム開発側の人は全部jsにまとめがちなので、 jsにcssを梱包してしまうと一般公開するときに色々弊害が出てきてしまいます。

jsにcssを梱包してしまうと起こる一番の問題は、 最初にローディング用の画面で直スタイル打ち込みをしたり凝った対策をしないと CSSが適用されていない状態のページが一瞬見えてしまうというものですね。

というのもjsにCSSが梱包されてしまっているので先にjsが読み込まれて そこでcssを解析して適用すると行った流れになるので当然っちゃ当然です。

かといって読み込み完了まで待たせるのはユーザビリティによろしくないので javascriptは基本deferを付けて遅延読み込みをさせるのが基本なためです。

仕事が忙しくなってきて備忘録的なのばっかになっていますが、 意外とこうやって仕事でやったことを書き出しておくのは知識と技術の固着になるのでいいなぁって感じてきてます。

webpackからjsとcssを切り分ける方法

正直1から組み直したほうが早いのですが、今回はすでに開発第一段階を終えようとしているので とりあえず現状のwebpackからcssを切り離そうと思います。

express.jsを使ってnode側でサーバーを建てて、 同じくしてフロントも一緒くたに開発しているので切り分けたいのですが ちょっとそれは後回しということになっていてとりあえず読み込み順の問題を解決するために切り分けます。

postcss-loaderを使ってルールを作って吐き出し先を個別に設定することができるので これでSASSをコンパイルすると個別にCSSが出力されJavaScriptに内包されなくなります。

一応シンプルな設定を載せておくので環境に合わせて変更して使ってみてください。

yarn add などは必要に応じてやってください。

// プラグインを読みこむ
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin') // htmlを生成するのに必要
const autoprefixer = require('autoprefixer');

module.exports = {
  optimization: {
    minimize: false
  },
  // モード値を production に設定すると最適化された状態で、
  // development に設定するとソースマップ有効でJSファイルが出力される
  mode: 'development',

  // メインとなるJavaScriptファイル(エントリーポイント)
  entry: `${__dirname}/src/main.js`,

  output: {
    //  出力ファイルのディレクトリ名
    path: `${__dirname}/dist`,
    // 出力ファイル名
    filename: 'main.js'
  },

  module: {
    rules: [
      {
        // 拡張子 .js の場合
        test: /\.js$/,
        use: [
          {
            // Babel を利用する
            loader: 'babel-loader',
            // Babel のオプションを指定する
            options: {
              presets: [
                // プリセットを指定することで、ES2020  ES5 に変換
                [
                  '@babel/preset-env',
                  // 20210202追記(async/await使用のための設定)
                  {
                    "targets": {
                      "node": "current"
                    }
                  }
                ]
              ],
            }
          }
        ]
      },
      // pugファイルの読み込みとコンパイル
      {
        test: /\.pug$/,
        use:[
          {
            loader: 'pug-loader',
            options: {
              pretty: true,
            },
          }
        ]
      },

      // Sassファイルの読み込みとコンパイル
      {
        test: /\.scss$/i,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          {
            loader: 'css-loader',
            options: {url: false}
          },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  autoprefixer({
                    grid: true,
                    flexbox: true,
                  })
                ]
              }
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sassOptions: {
                outputStyle: 'expanded',
              },
            },
          },
        ]
      },
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
        template: "./src/pug/index.pug", // 入力ファイル名
        // inject: false, //バンドルしたjsファイルを読み込むscriptタグを自動出力しない
        minify: false, //minifyしない
        hash: true,
        scriptLoading:"defer",
    }),

    new MiniCssExtractPlugin({
      filename: 'css/style.css',
      ignoreOrder: true,
    })
  ],
  // ローカル開発用環境を立ち上げる
  // 実行時にブラウザが自動的に localhost を開く
  devServer: {
    open: true,
    host: "127.0.0.1",
    port: 3000,
  },
};