LoginSignup
5
7

More than 3 years have passed since last update.

webpackのみでビルドする環境を作る(pug, sass, babel)

Last updated at Posted at 2020-03-04

はじめに

はじめまして。qiita初投稿になります。主にツイッターとかで活動してます、itomiseと申します。
去年、SEとして新卒入社した会社を3か月でやめて、未経験でしたがweb系の会社に転職しました。
初めてhtmlを触ってから半年すぎたくらいなので、区切りとしてqiita投稿してみたいな、と思った次第です。

※2020/03/20 追記
最後にsassらへんをいじったせいでバグが起きてました。。。修正しました。
jsのchunkも追加しました。

概要

この記事は@wintyoさんの
webpackだけでpugをビルドする環境を作る
を少し改変したものになってます。(@wintyoさん、勝手にすみません)

実際に案件等で使用してみて困ったことが多少起こったのですが、だんだん解決して形になってきたので記事としてまとめたいと思います。
開発環境を作っているだれかのためになれば幸いです。

git はこちら

環境

  • windows 10 pro
  • Node v12.14.1

cssを外部出力に

cssをjsにバンドルしてしまうと、jsが読まれるまでhtmlにスタイルが当たっていない状態で表示されてしまうため、cssファイルとして生成するようにしました。
しかし、developmentの時にjsにバンドルしていないファイルはhot module replacementされません。
developmentの時はjsにバンドルし、cssファイルとして出力しないという方法もあるのですが、これはcss-hot-loaderで解決できました。

webpack.dev.js
 module: {
    rules: [
      {
        test: /\.(sass|scss)$/,
        use: [
          'css-hot-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: true,
              importLoaders: 2,
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              plugins: [
                autoprefixer(),
              ]
            }
          },
          {
            loader: 'sass-loader',
          },
        ],
      },
    ]
  }

webpack configのuse: [] は後ろから適用されていくので、先頭に'css-hot-loader'を追加するだけです。これで、HMRがきくようになります。

pugファイルをディレクトリ構造を保ったまま出力

pugのディレクトリ構造のままhtmlを生成できたら便利なので、jsとwebpack configを多少変えました。

※2020/03/20 追記
wintyoさんよりコメントでよりスマートな方法を教えていただいたので修正しました。

pugファイルを読み込むときに、下層のファイルもすべて読み込むようにして、

importPug.js
// pugをインポートする
const req = require.context('../../pages/', true, /\.pug/) // 第二引数を true に
req.keys().forEach((fileName) => {
  req(fileName)
})

結構強引ですが、pugファイルをfile-loaderで出力するときにディレクトリも含んだ文字列にして出力するようにします。
名前の出力を[path][name].htmlの形にすることでディレクトリ情報をもったまま出力できます。
しかし、そのままだとpages/からのパスになってしまうのですが、outputPathで変更することにより解決できました。

webpack.common.js
{
  loader: 'file-loader',
  options: {
    name: '[path][name].html',
    outputPath: (url) => {
      return path.relative('src/pages', url)
    },
    url: false
  }
},

これで、ディレクトリ構造を保ったままhtmlファイルを吐き出せるようになりました。

pugにjsから値を渡せるようにする

pug-html-loaderでdataにオブジェクトを渡すと、pugファイル内で値を使用できるようになります。
現在はルートディレクトリからのパスをpugファイルで使用できるようにしています。
はじめは、ルートディレクトリを変更するたびにpugのほうも手動で書き換えていたのですが、webpack.common.jsの1か所だけ変更で済むようになったので便利ですね。
metaなどの情報もpug.config.json等で管理するようにしたほうがいいかなと思うので、あとあと変えていこうかなと思います。

webpack.common.js
{
  loader: 'pug-html-loader',
  options: {
    pretty: true,
    data: {
      PUBLIC_URL: PUBLIC_URL
    }
  },
}

jsのchunkを有効にする

共通で使うモジュールがある場合、そのまま複数ファイルでそれを読み込んで出力してしまうと、
同じ処理が複数ファイルに重複してしまうことになります。
同じ処理がある場合、vendor.jsなどにまとまっていたほうがキャッシュもされてより効率的な読み込みができるので、
chunkを追加しました。
また、chunkすると、ファイルを更新してもページで更新されなくなってしまったので、
productionで実行したときにのみchunkするようにしました。
(怠惰なのでまだ検証しておらず、いけるっぽい!って感じでいれてしまったのでダメそうだったら消してください。。)

参考:webpack 4 の optimization.splitChunks の使い方、使い所 〜廃止された CommonsChunkPlugin から移行する〜

webpack.prod.js
optimization: {

  splitChunks: {
    cacheGroups: {
      vendor: {
        test: /node_modules/,
        name: 'vendor',
        chunks: 'initial',
        enforce: true
      }
    }
  }
}

また、納品ファイル生成時のみvendor.jsを読み込むように変更しました。
各ページで使用するjsもページごとに設定できるようにpage_jsブロックを追加しました。

layout.pug
body
  block content

  if (env === 'production')
    script(src= PUBLIC_URL + '/js/vendor.js')
  block page_js

その他細かい変更

  • ルートディレクトリを簡単に変えられるように整理
  • 画像圧縮
  • javascriptディレクトリ直下のjsを自動でエントリーポイントに
  • publicフォルダは静的に出力したいファイルをそのままコピーするフォルダに

さいごに

簡単なLPとかを作る用に使っていた本環境ですが、中規模等でも使えるようにもろもろ最適化していければと思います。
あと個人的に、scss記法よりsass記法(mixinとかfunctionはscssでかくけど)、ejsよりpugのほうが使いやすいと思ってるんですがどうでしょうか。

5
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7