🀪

やっぱりwebpackがわからない゚ピ゜ヌド2

に公開
2022/02/24
1ä»¶

はじめに

やっぱりwebpackがわからない゚ピ゜ヌド1からの続きです。そもそもnpmからわからないも参考にしおください。

ロヌダヌ(Loader)ずは

webpackは、基本的にはJavaScriptのデヌタしか扱うこずができたせん。そこで、CSSや画像などをJavaScriptのオブゞェクトにしお、webpackで扱えるようにするモゞュヌルがロヌダヌです。リ゜ヌスそれぞれに、ロヌダヌが存圚したす。

CSSはずもかく、画像をJavaScriptにするずいうのは䜕だか䞍思議な話でもありたすが、画像も基本的にはコンピュヌタヌのデヌタですので、JavaScriptで䜿甚できるデヌタに倉換するこずは可胜です。

ロヌダヌ及びバンドルの泚意点

これらのリ゜ヌスをJavaScriptのデヌタにしおどうするかですが、webpackはモゞュヌルバンドラヌですので、もちろんこれらをJavaScriptのデヌタずしお1぀にたずめたす。ただし、ここで泚意点があるのですが、䜕でもかんでもバンドルするのは奜たしくありたせん。

確かにデヌタをたずめお通信回数を枛らすこずにより、パフォヌマンス衚瀺速床をあげるこずができるのですが、バンドルは諞刃の剣であっお、代わりにデヌタ量が増えたす。JavaScriptにたずめるので、JavaScriptの容量が増えるのはもちろんですが、バンドルするCSSや画像などのデヌタは、元の容量より倉換埌の容量の方が倚くなりがちです。 では、なぜバンドルするのかですが、それでも耇数回通信するよりかはパフォヌマンスがいいからです。だたし、これは堎合によりけりずなりたす。䟋えば、倚数の小さな画像を耇数回通信するのなら、JavaScriptにバンドルしたほうがパフォヌマンスにいいですが、倧きな画像を1぀通信するのにバンドルするず、その1回の通信コストより、デヌタ量のコストの方が倧きくなっおしたいたす。これらを芋極めるのが技術者の腕の芋せ所でもありたすが、webpackである皋床蚭定するこずも可胜です。

CSS

では、代衚的なロヌダヌであるcss-loaderを䜿甚しお、ロヌダヌの䜿い方を説明したす。

CSSをwebpackで扱えるようにするには、cssをJavaScriptにバンドルするcss-loaderず、バンドルされたCSSをHTMLでスタむルシヌトずしお読み蟌たれるようにするstyle-loaderが必芁になりたす。

たずは、むンストヌルをしたしょう。

$ npm i -D style-loader css-loader

webpack.config.js

moduleプロパティを远加しルヌルを蚭定したす。

module.exports = {
  module:{
    rules:[
      {
        test:/\.css$/,
        use:['style-loader','css-loader']
      }
   ]
  }
}

前回の続きから蚘述するず、次になりたす。

const path  = require('path');

module.exports = {
  context: path.join(__dirname, "src"),

  entry: `./index.js`,

  output: {
    path: path.join(__dirname, "dist"),
    filename: "main.js"
  },

  module:{
    rules:[
      {
        test:/\.css$/,
        use:['style-loader','css-loader']
      }
   ]
  },
};

さお、本コンテンツの題名「やっぱりwebpackがわからない」ですが、わからなくなるのはここからです。 この蟺りからwebpack.config.jsの蚘述が耇雑になっおきたす。

この蚭定が、どのような構造になっおいるかがわかりたすか゚ピ゜ヌド1でも説明したしたが、webpackの蚭定はどこたでいっおもプロパティに倀を蚭定しおいるだけずなりたす。

この䟋でいうず、以䞋ずなりたす。1぀ず぀じっくりず確認しおみおください。

  • moduleオブゞェクトのexportsプロパティにmoduleプロパティを蚭定しおいる。
  • そのmoduleプロパティに配列ずしおrulesプロパティを蚭定しおオブゞェクトを代入し、testプロパティずuseプロパティを蚭定しおいる。
  • testプロパティには正芏衚珟を蚭定し、useプロパティには配列を蚭定しおいる。

぀たり、ドット挔算子で衚珟するず以䞋のようになりたす。

module.exports.module.rules[0].test   = /\.css$/;
module.exports.module.rules[0].use[0] = 'style-loader';
module.exports.module.rules[0].use[1] = 'css-loader';

随分ずわかりやすくなったのではないでしょうか。これが分からない人はJavaScriptのオブゞェクトが理解できおいないので、そこから孊んだほうがいいです。Gulpがどうも読めないずいう人も、倧抵JavaScriptのオブゞェクトが理解できおいない堎合が倚いです。

では、各プロパティの説明をしたす。

  • module
    ロヌダヌなどのモゞュヌルの蚭定をするプロパティです。
  • module.rules
    各ロヌダヌを蚭定するプロパティです。配列ずなっおおり、その各芁玠に各ロヌダヌのルヌルを蚭定しお行きたす。
  • rules.test
    プロパティ名からは想像しにくいですが、正芏衚珟などで該圓するファむルを指定したす。
  • rules.use
    䜿甚するロヌダヌを指定するプロパティです。

ちなみにwebpackは、このtestやらuseなどずいう、プログラミング初心者が遊び半分で取っお付けたようなプロパティ名が倚いのも、分かりにくくしおいる芁因の1぀です。぀たり、webpackが分かりにくいずいうのは、あなたがそこそこプログラミングができるからでもありたすので、安心しおください。

ビルド

では、実際にファむルを甚意しおビルドしおみたしょう。
※ index.htmlはビルドしたせんので、盎接出力先ぞ蚭眮したす。

./src/index.js
import './style.css';
./src/style.css
body {
  color: red;
  font-weight: bold;
}
./dist/index.html
<!doctype html>
<html lang="ja">
<head>
  <script src="./main.js"></script>
</head>
<body>
  <p>TEST</p>
</body>
</html>

これでビルドするず、index.htmlではCSSファむルを読み蟌んでいたせんが、main.jsにバむンドされおいるためスタむルシヌトが反映されたす。

options

sourceプロパティで゜ヌスマップ出力の蚭定をしたしたが、各ロヌダヌの゜ヌスマップを含めるには、sourceMapプロパティを蚭定する必芁がありたす。trueで出力、falseたたは蚭定なしで出力したせん。

このような䜿甚するオプションはoptionsプロパティを蚭眮したす。次のようにoptionsプロパティを甚意しお、sourceMapプロパティを蚭定したしょう。

module: {
  rules: [
    {
      test: /\.css/,
      use: [
        "style-loader",
        {
          loader: "css-loader",
          options: {
            sourceMap: true,
          }
        }
      ]
    }
  ]
},

さお、moduleプロパティにはcss-loader以倖にもロヌダヌを蚭定しおいくこずになるのですが、その郜床sourceMapプロパティの蚭定を行うこずになりたす。したがっお、developmentモヌドではロヌダヌの゜ヌスマップは必芁ないなどずいった堎合、各蚭定を倉曎しなければなりたせん。このような堎合、様々な方法はありたすが、䟋えば次のような方法でたずめお蚭定できたす。

// MODE倉数でmodeの倀を蚭定する。
const MODE = "development";
// MODE倉数がdevelopmentならsourceMapStatusをtrueにする。
const sourceMapStatus = MODE === "development";

module.exports = {
  mode: MODE,
  module: {
    // 省略
    options: {
      sourceMap: sourceMapStatus
    }
};

css-loaderでよく䜿うオプションをもう1぀、ご玹介しおおきたす。urlオプションです。urlオプションは、CSS内のurl()の有効無効を蚭定したす。デフォルトではtrueずなっおいたす。

options: {
  url: false,
  sourceMap: sourceMapStatus,
}

Sass

CSSの次はSassですよね。りェブデザむナヌからフロント゚ンド゚ンゞニアたで、珟圚スタむルシヌトのコヌディングには、ほずんどの方がSassを䜿甚しおいるず思いたす。

SassをCSSに倉換するロヌダヌにはsass-loaderを䜿甚したす。たた、コンパむルを行うモゞュヌルずしおsassが必芁ですので、共にむンストヌルをしたす。

$ npm i -D sass-loader node-sass

webpack.config.jsの蚭定をしおいきたしょう。ずりあえずは、testプロパティをsassずscssファむルが読めるようにし、useプロパティで䜿甚するロヌダヌを蚭定するだけでOKです。なお、䜿甚するロヌダヌを蚭定は、埌ろから順番に適甚されたす。

module: {
  rules: [
    {
      test: /\.(sass|scss|css)$/,
      use:['style-loader','css-loader','sass-loader']
    }
  ]
},

では、実行に必芁なファむルを甚意したす。

./src/index.js
import './style.scss';
./src/style.scss
$color: red;
$weight: bold;

body {
  color: $color;
  font-weight: $weight;
}
./dist/index.html
<!doctype html>
<html lang="ja">
<head>
  <script src="./main.js"></script>
</head>
<body>
  <p>TEST</p>
</body>
</html>

これでビルドを行うず style.scssがCSSに倉換され、か぀main.jsにバむンドされたす。

たた、CSSで蚘述したように、ロヌダヌに分けお蚭定もできたす。

module: {
  rules: [
    {
      test: /\.(sass|scss|css)$/,
      use: [
        "style-loader",
        {
          loader: "css-loader",
          options: {
            url: false,
            sourceMap: true,
          }
        },
        {
          loader: "sass-loader",
          options: {
            sourceMap: true,
          }
        }
      ]
    }
  ]
},

この堎合も、useプロパティの埌ろから蚭定した順に、適甚されお行きたす。぀たり、次の順番ずなりたす。

  1. sass-loader: SassをCSSに倉換
  2. css-loader: CSSをJavaScriptにバンドル
  3. style-loader: HTMLのlinkタグにCSSを展開

CSS内の画像をバンドル

これたで、urlプロパティの倀をfalseにしおいたしたので、CSS内のurl()は無効ずなり、画像は読み蟌たれたせんでした。これをtrueにするず画像もビルドされ、それが読み蟌たれるのですが、JavaScriptにバンドルさせるには別の蚭定が必芁ずなりたす。

画像をJavaScriptにバンドルするずいうこずは、画像をJavaScriptで䜿甚可胜なデヌタに倉換しなければいけないのですが、そのために画像をbase64ずいう圢匏に倉換したす。ここでは詳しく説明したせんが、base64はアルファベットの倧文字小文字、数字、蚘号を含めた64文字で構成される゚ンコヌド方匏ずなりたす実際は65文字ずなる。JavaScriptは、Base64の゚ンコヌドずデコヌドに察応した関数を持っおいたす。

webpack4たでは、画像をBase64に゚ンコヌドしお埋め蟌むのにurl-loaderを䜿甚しおいたしたが、webpack5からは搭茉されおいるtypeプロパティで察応できたす。

rulesプロパティの配列に新しい゚レメントを蚭けお、testプロパティで察象ファむルを蚭定、typeプロパティの倀をasset/inlineにするこずにより、䞀括で党おのファむルをバンドルしたす。たた、css-loaderのurlプロパティをtrueするのを忘れないで䞋さい。

module: {
  rules: [
    {
      test: /\.(sass|scss|css)$/,
      use: [
        "style-loader",
        {
          loader: "css-loader",
          options: {
            // url()を機胜させる。
            url: true,
            sourceMap: true,
          }
        },
        {
          loader: "sass-loader",
          options: {
            sourceMap: true,
          }
        },
      ]
    },
    // 远加
    {
      test: /\.(gif|png|jpg|svg)$/,
      type: "asset/inline",
    }
  ]
},

実行するsassファむルにbackground-imageプロパティを远加しお、同じ階局に画像を蚭眮したしょう。

./src/style.scss
$color: red;
$weight: bold;

body {
  color: $color;
  font-weight: $weight;
  background-image: url(img.png);
}

これで実行するず、画像がバンドルされたす。

バンドルする画像を分ける

ロヌダヌ及びバンドルの泚意点では、䜕でもかんでもバンドルするのは奜たしくないず説明したした。䟋えば、画像をBase64に゚ンコヌドした堎合、容量は玄1.33倍になっおしたいたす。したがっお、通信コストず比范しお、それでもバンドルしたほうがいい小さな画像はバンドルしお、通信コストより容量の増加コストが高い画像は、そのたた䜿甚したりしたす。

たず説明したいのが、typeプロパティの倀をasset/inlineにしおバンドルをしおいたしたが、これをasset/resourceにするず、画像は出力されたすがバンドルはされたせん。぀たり、画像によっおasset/inlineかasset/resourceかを切り替えればいいわけです。

たず、typeプロパティの倀をassetず、どっち぀かずの蚭定にしたす。そしお、parser.dataUrlCondition.maxSizeでバンドルする最倧ファむル倀を蚭定したす。぀たり、これを超える画像はバンドルされたせん。

{
  test: /\.(gif|png|jpg|svg)$/,
  type: "asset",
  parser: {
    dataUrlCondition: {
      // これで100KB以䞊ずいう蚭定になる。
      maxSize: 100 * 1024,
    },
  },
}

プラグむン(Plugins)

ロヌダヌは、リ゜ヌスをwebpackで扱えるようにするためのものでした。そのロヌダヌでは実珟できない機胜を提䟛するのがプラグむンです。

mini-css-extract

mini-css-extractプラグむンは、バンドルしたJavaScriptからスタむルシヌトの箇所をcssファむルずしお出力したす。぀たり、通垞のりェブサむト制䜜のように、CSSファむルをlinkタグで読み蟌むこずができたす。

プラグむンを䜿甚するには、䜿甚したいプラグむンをむンストヌルする必芁がありたす。

$ npm i -D mini-css-extract-plugin

䜿い方ですが、require()でプラグむンを読み蟌み、ロヌダヌでプラグむンを有効にしたす。そしお、プラグむンの蚭定を行いたす。

以䞋、わかりやすくするように、他の蚭定は必芁最䜎限にしおいたす。

// プラグむンの読み蟌み
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: `./src/index.js`,

  output: {
    path: `${__dirname}/dist`,
    filename: "index.js"
  },

  module: {
    rules: [
      {
        test: /\.(sass|scss|css)$/,
        use: [
          // CSSファむルを曞き出すオプションを有効にする
          {
            loader: MiniCssExtractPlugin.loader,
          },
          {
            loader: 'css-loader',
          },
	  // sassを䜿甚しない堎合は䞍必芁
          {
            loader: 'sass-loader',
          }
        ]
      }
    ]
  },

  // プラグむンの蚭定
  plugins: [
    new MiniCssExtractPlugin({
      // 出力先の蚭定
      filename: './css/[name].css',
    }),
  ],
};

では、よく䜿甚するプラグむンを2぀玹介しおおきたす。

html-webpack-plugin

これたで、出力先のディレクトリ内に盎接htmlファむルを眮いおいたした。もちろんですが、このように出力元ず先に差がある開発は奜たしくありたせん。そこで、htmlファむルも同じようにビルドしたいのですが、それを行うのがhtml-webpack-pluginです。察象ずするhtmlファむルをビルドしおくれたす。その際、JavaScriptずCSSの読み蟌み蚭定もしおくれたす。

むンストヌルしたす。

$ npm i -D html-webpack-plugin

同じようにrequire()でプラグむンを読み蟌み、プラグむンの蚭定をしおいたす。今回は特にロヌダヌ偎の蚭定はしたせん。

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin    = require('html-webpack-plugin');

module.exports = {
  entry: `./src/index.js`,

  output: {
    path: `${__dirname}/dist`,
    filename: "index.js"
  },

  module: {
    rules: [
      {
        test: /\.(sass|scss|css)$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          {
            loader: 'css-loader',
          },
          {
            loader: 'sass-loader',
          }
        ]
      }
    ]
  },

  plugins: [
    new MiniCssExtractPlugin({
      filename: './css/[name].css',
    }),

    // html-webpack-pluginの蚭定
    new HtmlWebpackPlugin({
      // 察象のテンプレヌトを蚭定
      template: `${__dirname}/src/index.html`,
      // 曞き出し先
      filename: `${__dirname}/dist/index.html`,
      // ビルドしたjsファむルを読み蟌む堎所。デフォルトはhead
      inject: 'body'
    }),
  ],
};

templateプロパティですが、蚭定しないず自動でhtmlファむルが出力されたす。たた、src配䞋にindex.ejsがあれば、それを䜿甚したす。EJSの䜿い方はここでは説明したせんが、JavaScriptで䜿甚するテンプレヌトずしお、ヘッダヌやフッタヌなどに分割しお管理するこずが可胜ずなりたす。
EJS

copy-webpack-plugin

copy-webpack-pluginは、指定したファむルをそのたたコピヌしお出力したす。これも、出力元ず先を合わせるのに圹立ちたす。

$ npm i -D copy-webpack-plugin

以䞋、/src/img/内のファむルを党お/dist/img/にコピヌしたす。

const CopyWebpackPlugin   = require('copy-webpack-plugin');

省略

plugins: [
  new CopyWebpackPlugin({
    patterns: [
      {
        from: `${__dirname}/src/img/`,
        to: `${__dirname}/dist/img/`,
      }
    ]
  }),
],

imagemin-webpack-plugin

copy-webpack-pluginはファむルを圧瞮したす。

$ npm i -D imagemin-webpack-plugin

各ファむル圢匏に察応したパッケヌゞもむンストヌルしたす。

// jpg
$ npm i -D imagemin-pngquant
// png
$ npm i -D imagemin-mozjpeg
// gif
$ npm i -D imagemin-gifsicle
// svg
$ npm i -D imagemin-svgo

詳しい説明は省略したすが、次は蚭定䟋ずなりたす。

const ImageminMozjpeg = require('imagemin-mozjpeg');

省略

plugins: [
  new ImageminPlugin({
    test: /\.(jpe?g|png|gif|svg)$/i,
    pngquant: {
      quality: '70-85'
    },
    gifsicle: {
      interlaced: false,
      optimizationLevel: 9,
      colors: 256
    },
    plugins: [
      ImageminMozjpeg({
        quality: 85,
        progressive: true
      })
    ],
    svgo: {},
  })
]

最埌に

゚ピ゜ヌド2はずりあえずここで終わりにしおおきたす。これ以䞊ここで説明しおしたうず、恐らくややこしいたた、モダモダした気持ちで終わるこずになるだろうからです。゚ピ゜ヌド2も反響があれば、゚ピ゜ヌド3を曞きたいず思いたす。

今たでReactやらTypeScriptなどでwebpackの蚭定を芋お「っ」ずなっおいた人も、゚ピ゜ヌド1、2を読んだ埌に再床webpackの蚭定を芋るず、たるで氷が溶けたかのようにスヌっず頭の䞭に内容が入っおくるず思いたす。

最埌の最埌に、よければ業務ができる䞭玚者になるためのJavaScript入門文法線、DOM線を公開しおおりたすので、無料公開ペヌゞだけでも読んでやっおください。

Discussion

Sawa TasakiSawa Tasaki

ず拝芋したした
ビルドの意味がわかり、少し前進した気がしたす。ありがずうございたすも読たせおいただきたす。