LoginSignup
5
1

More than 1 year has passed since last update.

今年のうちにwebpackについてハンズオンも交えて理解する

Last updated at Posted at 2022-12-20

webpackとは何か

JavaScript の モジュールバンドラです。
モジュールバンドラとは、
複数のファイルを1つにまとめて出力してくれるツールのことです。
(複数ファイルをまとめることを「バンドル」と呼びます。)

なぜ使うのか

  • たくさんのjsファイルを1ページで読み込もうとすると、リクエストがその数だけ発生し、時間がかかってしまう→1つのファイルにまとめることで、リクエストも1回だけできる

  • 外部モジュールを利用するときにリクエスト数を減らせる

  • モジュールに切り分けた開発可能→開発効率アップ

  • 依存関係を解決してくれる

<!-- app.jsはjQueryに依存しているため、jQueryを読み込んだ後に読み込む必要がある。 -->
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="js/app.js"></script>

上記のような依存関係が増えれば増えるほど依存関係がわからなくなってしまいます。

→webpackを利用すれば依存関係を解決してファイルをバンドルするため、スクリプトの順番を考慮する必要はなくなります!

webpackの設定ファイルの書き方

webpack.config.jsという名前のファイルを作成し設定を書きます

webpack設定の基本はmode, entry, output, loader, pluginの5つです。

webpack.config.js
const path = require('path');

module.exports = {
  mode: "production",
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
  plugins: [
  new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': '"production"',
  }),],
};

Mode

none, development, productionのいずれかを設定できるパラメータです。値別に設定を切り分けたい時に設定します。デフォルトではproductionが設定されています。

Entry

処理の開始となるポイントを記述します。

Output

生成されたバンドルされたファイルの出力先を記述します。

Loader

webpackコアだけではjsファイルしか扱えません。そこでJavaScript以外のファイルでもwebpackでバンドルできるようにするものです。

例:css-loader(CSSファイルを読み込む) file-loader(画像を読み込む)

Plugins

バンドルの仕方に作用するものです。バンドル自体の作成方法も変更できます。プラグインはローダーよりも細かい設定ができます。
例:MiniCssExtractPlugin(CSSを別バンドルで出力する)

webpack ハンズオン

1. webpackの導入

1.webpackのインストール

まずはwebpackをnpmでインストールします。

npm init -y 
npm install webpack
npm install webpack-cli

2. bundleできているか確認しよう

ここからは二つのjsファイルを作成し、片方からもう片方をimportしている時、webpackでbundleするとどうなるのか実践していきます。

1. src/index.jsの作成

まずはsrcディレクトリを作成してそこにindex.jsファイルを作成します。
このファイルでは配下のnameファイルを読み込んでconsole.logで出力するという簡単なものです。

src/index.js
const name = require("./name");

console.log("Hello " + name);

2. src/name.jsの作成

こちらではname.jsで任意の名前をexportsするファイルを作成します。

src/name.js
module.exports = "John";

3. webpack.config.jsの作成

ここで今回の主役となるwebpackの設定ファイルである
webpack.config.jsを次のように定義します。

webpack.config.js
const path = require("path");
module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
};

この設定はdecelopモードで./src/index.jsを起点としてjsファイルをまとめて
dist配下のbundle.jsというファイルに出力してください。
ということを意味しています。

4. webpack build

設定ファイルができたので実際にwebpackを下記コマンドで動作してみましょう

npx webpack build  

dist配下にbundle.jsというファイルができたのを確認できたでしょうか?

5. 動作確認

実際にnodeでbundle.jsを動作させてみると
Hello Johnが出力されて2ファイルを1ファイルにまとめることができたことがわかると思います。

node ./dist/bundle.js

// Hello John

3. loaderを作成してみよう

ここからはtxtファイル作成した後index.jsで呼び出し

txtファイルはloaderなしではbundleされないことを確認した後

loaderを作成してtxtファイルをbundleできるようにしたいと思います。

1.src/hello.txtの作成

hello.txt
こんにちは

2. src/index.jsで呼び出す

// src/index.js
const name = require("./name");

const hello = require("./hello.txt");
console.log("Hello" + name + hello);

3. webpack build

npx webpack build  

4.動作確認

node ./dist/bundle.js
// ReferenceError: こんにちは is not defined

エラーが出てうまくバンドルできていないことが
確認できると思います。
webpackではjsファイルしかbundleすることができず
js以外のファイルをbundleするためにはloaderが必要になります。

5. loaders/textLoader.jsの作成

textファイルをwebpackでbundleできるようにするために
loadersディレクトリを作りその配下にtextLoader.js
を作成します。

loaders/textLoader.js
module.exports = function (contents) {
    return `module.exports = ${JSON.stringify(contents)};`; // Node.js で扱えるようにテキストファイルを変換
}

6. webpack.config.jsの修正

webpack.config.jsを修正して.txtで終わるファイルには先ほど作成した
textLoader.jsを適応するようにします。

webpack.config.js
const path = require("path");
module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  // 以下を追加
  module: {
    rules: [
      {
        // 正規表現で適応したいファイル名を書く
        test: /\.txt$/,
        // 正規表現に合致したファイルに対して適応するloaderを書く
        use: [{ loader: path.resolve(__dirname, "loaders/textLoader.js") }],
      },
    ],
  },
};

7. webpack build

npx webpack build  

8. 動作確認

node ./dist/bundle.js
// Hello John こんにちは

loaderによってtxtファイルをbundleすることができ
先ほどのエラーは消えていることがわかります。

4. pluginを作ってみよう

ここからはpluginを作成しhello.txtの代わりに新しく作成するoverwrite.txtを上書きするpluginを作成したいと思います。

plugin/overwrite.txtの作成

plugin/overwrite.txt
上書きしたよ

2. plugin/textplugin.jsの作成

ここではtxtファイルが読み込まれるときに作用してoverwrite.txtに置換してしまうというpluginを作成します。

plugin/textplugin.js
const path = require("path");

module.exports = class MessagePlugin {
  apply(compiler) {
    compiler.hooks.normalModuleFactory.tap("messagePlugin", (factory) => {
      // ファイルのインポートのための名前解決の手前でフック
      factory.hooks.beforeResolve.tapAsync(
        "messagePlugin",
        (resolve, callback) => {
          // 特定のファイル名のとき読み込むファイルを変える
          if (/\.txt$/.test(resolve.request)) {
            resolve.request = path.resolve(__dirname, "overwrite.txt");
          }
          callback();
        }
      );
    });
  }
};

3. webpack.config.jsの修正

webpack.config.jsを修正して先ほど作成した
textplugin.jsを読み込むようにします。

webpack.config.js
const path = require("path");
//下記を追加
const MessagePlugin = require("./plugin/textplugin")
module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  //下記を追加
  plugins: [
    new MessagePlugin()
  ],

  module: {
    rules: [
      {
        test: /\.txt$/i,
        use: [{ loader: path.resolve(__dirname, "loaders/textLoader.js") }],
      },
    ],
  },
};

4. webpack build

npx webpack build  

5. 動作確認

node ./dist/bundle.js
// Hello John 上書きしたよ

pluginによってファイルの読み込み時に置換されて
「こんにちは」が「上書きしたよ」になっていることが確認できたと思います。

5
1
0

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
1