LoginSignup
16
22

More than 3 years have passed since last update.

【Webpack】Webpackについてまとめてみた

Last updated at Posted at 2020-08-30

はじめに

0. 感想

  • Webpackは簡単にいうとフロントエンドのソースコード管理ツールで、CSSやJS等のコードを圧縮または変換する。(SASS → CSS, ECMAScript2015 → JavaScriptなど)

    • Railsエンジニアからすると、Asset Pipelineとやっていることは近い。
  • ↑を行うために、様々な ローダープラグイン というものを使用する。

概要

1. webpackとは?

  • JS, CSS, 画像などを一つにまとめるためのツール。
    • モジュールバンドラーと呼ぶ。
      • バンドル ≒ ビルド

webpack以前

  • 各.htmlファイルで <script> 要素を列挙していた。
    • 以下のような問題点があった。
      • <script> 要素は順番に実行されるので、並び順に注意を払う必要がある。
      • ライブラリ同士やアプリ本体のコードが互いに依存関係にあるような状況が発生してしまう。
<script src='lib.js'></script>
<script src='app.js'></script>

webpack以降

  • モジュールバンドラーの利用によって、以下のようなメリットがあった
    1. 自動的に依存性を解決する
      • 一つのファイルにバンドルしてくれるので、HTML側でコードの依存関係を意識することがなく、まとめられたファイルをインポートさえすれば良くなった。
    2. リクエストの回数を抑える
      • 複数ファイルを一つにまとめることで、ブラウザ/サーバー間のリクエスト数を減らすことができた。
    3. 大規模な開発に向いている
      • コードをクラス/関数の単位でモジュール(ファイル)として細かく分割できるので、ここのファイルの見通しが改善され、名前空間を明確に分離できるようになった。

2. webpackの仕様

2-1. さまざまなモジュール形式を解釈できる。

  • CommonJS
    • module.exports.add = require('hoge') みたいなやつ。
  • AMD
  • ES Modules

2-2. ローダー/プラグインが豊富。

  • ローダー
    • リソースを読み込むためのライブラリ。
      • 画像やスタイルシートなどをバンドルすることが可能。
      • TypeScriptなどのaltJSコンパイルした上でバンドルすることが可能。
  • プラグイン
    • webpackそのものの拡張。
      • コードの圧縮(minify)。
      • バンドルしたファイルを実行するためのページの生成。

タスクランナー・ビルドツール

  • Grunt, gulpなどがある。

2-3. フレームワークでの採用実績が増えている。

  • Angular, React, Vue.js などのJavaScriptフレームワークのコマンドラインツールでは、内部的にwebpackが利用されている。

3. モジュールバンドラーの基本

  • 「モジュールを束ねる」という性質上、モジュールの理解が必須。

    • JavaScriptにおけるモジュールとは、即ちファイルのこと。
      • ファイル名がそのままモジュール名を意味する。
  • export が指定されていないメンバー(変数/関数/クラス)は、モジュールの外からは参照できない

    • これによって名前の競合を防げる。
  • import/export を全てのブラウザーで認識できるわけではないため、モジュール間の依存関係を解釈し、一つに束ねるのがモジュールバンドラーwebpack。

4. webpackを利用する

4-1. Node.jsのインストール

  • webpackは、Node.js上で動作するコマンドラインツール。
    • webpackを利用した開発では、アプリをNode.jsプロジェクトで管理するのが一般的。

4-2. package.jsonの作成

  • package.jsonはNode.jsの設定ファイル。
    • アプリの基本情報、プロジェクト固有のコマンド、利用しているパッケージ(ライブラリ)などを管理する。
  • npm init -y というコマンドによって生成される。

4-3. webpackのインストール

Node.jsプロジェクトにwebpackをインストールする。

  • npm install --save-dev webpack webpack-cli
    • --save-dev オプションは、インストールするパッケージの情報をpackage.jsonに記録しなさい、という意味。 --save オプションでインストールされたパッケージは、 package.json内の dependencies ブロックに記録される。
      • package.jsonでパッケージ情報をまとめておくことで、あとから別の環境で必要なライブラリを準備したい場合にも npm install コマンド一つで再現できる。
        • --save-dev オプションは、アプリ開発で利用するツールをインストールする場合に利用する。 --save オプションはアプリそのものの実行で利用する。
    • インストールに成功すると、プロジェクトルートに /node_modules フォルダーが生成され、配下にパッケージ本体(ライブラリ)が保存される。

5. webpackの基本

  • /dist/index.html

    • JavaScriptファイルを呼び出すためのページ
  • /src/index.js

    • 各モジュールを呼び出し、実行するコード。エントリーポイント。
      • index.htmlがindex.jsを参照する。
  • npx webpack

    • プロジェクトローカルにインストールされたパッケージのコマンドを実行。
      • webpacの既定では、/src/index.jsがエントリーポイントとなり、バンドルの結果は/dist/main.jsに出力される。
        • 生成されたmain.jsには
          • モジュールを解決するためのコード
          • エントリーポイント
          • エントリーポイントが依存するコード
            • が一式含まれており、ページからは最終的な出力ファイル(main.js)をインポートするだけでアプリを実行できる。
              • <script src='./main.js'></script>

6. 設定ファイルの基本

  • 実際の開発では、#5 で述べたような規定の動作だけでは不足で、「入出力先を変更したい」「ビルドにあたって任意の処理を追加したい」「そもそも処理対象のファイルを限定したい」など、細やかな挙動を指示する必要が出てくる。
    • これらの挙動は npx webpack コマンドのオプションとして指定することもできるが、あとで繰り返し実行することを考えれば、設定ファイルとしてまとめておくのが便利かつ一般的。

6-1. 設定ファイルの骨組み

  • エントリーポイントと出力先ファイルを設定ファイルで指定し、ビルドする。
// webpack.config.js

// 設定ファイルの外枠
module.exports = {
  // エントリーポイント
  entry: './src/index.js',
  output: {
    // 出力先のフォルダ
    path: `${__dirname}/dist`,
    // 出力先のファイル名
    filename: 'main.js'
  },
};
> npx webapck --config webpack.config.js

コマンドを実行後、dist/main.jsにエントリーポイントをビルドした内容が出力されていれば、ビルドは成功。

ビルドコマンドのショートカット

  • package.json内で設定できる。
...
'script': {
  'build': 'webpack --config webpack.config.js'
}
...
// 以下は同じ
> npm run build
> npx webpack --config webpack.config.js

6-2. 開発サーバーの導入

  • コードを修正する度にビルドコマンドを再実行するのは面倒。
    • webpack-dev-serverを使って自動で再ビルド、ブラウザーのリロードを実行できる。

webpack-dev-serverのインストール

> npm install --save-dev webpack-dev-server
// webpack.config.js

module.exports = {
  entry: './src/index.js',
  output: {
    ...
  },
  devSerevr: {
    contentBase: './dist' // コンテンツの基底パス(検索先)の宣言
  },
};
// package.json

'script': {
  'start': 'webpack-dev-server --open', // --open: サーバー起動時にブラウザを開く
  'build': 'webpack --config webpack.config.js'
},
> npm start // npm run startとどちらでも良い。
開発サーバーによるビルドについて
  • 開発サーバーは、ビルドの結果をメモリー上で管理している。
    • よって、元からある/dist/main.jsには再ビルドの結果は反映されない。ビルドの結果をファイルに保存したい場合には、 npm run build コマンドを利用する。
watchモードによるファイルの監視

コードの編集時に再コンパイルするだけならば、webpack-dev-serverではなく、webpack本体のwatchモードを利用してもよい。


// package.json
{
  'name': 'basic',
  ...
    'build': 'webpack --watch --config webpack.config.js',
  ...
}
  • npm run build コマンドを実行し、適当なコードを変更してみると、確かに自動的に再ビルドが実施されることが確認できる。
    • 一般的には、開発サーバーを利用した方がブラウザーまで制御できるため便利。
      • ビルド結果をファイルできちんと確認したいなどの状況では、watchモードは重宝される。
本番/開発モードの選択
  • webpack.config.jsで mode パラメータを指定する。

    • webpack4では必須。
  • 開発モード

    • よりデバッグに適したコードを高速に生成する
  • 本番モード

    • 不要なコードを削除し、できるだけサイズが小さく(minificationされる)、実行効率の良いコードを生成する。
ソースマップの生成
  • ビルド前後のコードをマッピングするためのファイル。

    • ソースマップを利用することで、デバッグ時にも、エラー箇所を(バンドル前の)オリジナルのソースコード によって参照できるようになるので、問題の特定がしやすくなる。
  • devtoolパラメーターで 'eval-source-map' を使用すると、オリジナルのソースを得ることができる。

7. ローダー

  • webpackを学ぶということは、ローダーを学ぶことである、と言い換えても良い。

  • ローダーはリソースをモジュールに変換する。

    • ローダーを利用することで、JavaScript以外のコード(スタイルシート、画像ファイル)でもバンドルできるように、モジュール(JavaScriptで処理できる形式)に変換してくれる。

スタイルシートのバンドル - css-loader/style-loader

  • css-loader
    • スタイルシートを読み込むためのローダー。
  • style-loader
    • スタイルを <style> 要素としてページに反映させるためのローダー。
> npm install --save-dev webpack webpack-cli css-loader style-loader

ローダーの有効化

  • 設定ファイルに対して module - rules パラメータを追加する。
// webpack.config.js
module.exports = {
  ...
  modules: {
    rules: [
      {
        test: /.\css$/,  // ローダーを適用するファイル
        use: [  // 適用するローダー
          'style-loader',  // 2. モジュールをページに組み込む
          'css-loader'  // 1. *.cssファイルがモジュール化
        ]
      }
    ]
  }
}

スタイルシートを要素で出力する - ExtractTextPlugin

  • style-loader/css-loaderの組み合わせでは、バンドルされたスタイルは <style> 要素としてページに埋め込まれる。
    • 一般的には、スタイルシートはページとは別ファイルとし、 <link> 要素で埋め込むのが普通。
      • ExtractTextPluginによって、バンドルしたリソースをファイルとして切り出す。
> npm install --save-dev webpack webpack-cli css-loader style-loader extract-text-webpack-plugin@next
// webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  ...
  modules: {
    rules: [
      {
        test: /.\css$/, 
        use: ExtractTextPlugin.extract({ use: 'css-loader' })  // 2. プラグインを割り当てる。
        ]
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('style.css'),  // 1. スタイルシートの出力ファイル名を指定。
  ]
}
  • プラグインを有効化するには、require関数でインポートした後、pluginsパラメーター配下でプロジェクトに登録する。
  • 出力ファイル名には [name].css のようにプレイスホルダーを含めることもできる。
  • ExtractTextPluginそのものはスタイルシートをモジュール化する機能は持たないので、extractメソッドの引数(useパラメーター)に、そのためのローダーを指定する。

その他のローダー

url-loader

  • 画像をバンドルする。

    • 無条件に全ての画像を束ねてしまうのは望ましくない。
      • 理由1: オリジナルファイルよりもサイズが大きくなる
      • 理由2: 解析のためのオーバーヘッドが発生する
  • リソースをファイルとして出力し、そのパスを管理する。

    • url-loaderの optins - limit パラメーターで、画像サイズが閾値を超えたらファイル出力する、というような設定ができる。
  • 本番環境で画像ファイルをCDNに配置する場合、 output - publicPath パラメーターを設定する。

    • これによって、ビルド時にurl関数の値をリライトできる。

file-loader

  • フォントファイルをバンドルする
    • ネット経由でフォントを取得し利用する、Webフォントをバンドルする。

babel-loader

  • ES2015以降のコードを、バンドル前にBabelによってトランスコンパイルする。
    • ブラウザのサポート率が低いES2015以降の構文を、より低いバージョンのJavaScriptに変換する。

ts-loader

  • TypeScriptのコードをコンパイルし、JavaScriptコード(既定ではES5のコード)に変換する。

sass-loader

  • Sass(Syntactically Awesome Stylesheets。制御構文、関数、ミックスインなど、スタイルシートをよりコンパクトにまとめるための言語機能を備えた言語)をコンパイルし、標準的なCSSスタイルシートに変換するためのローダー。
    • css-loader , style-loader , node-sass(Node.js上でSassをコンパイルするためのライブラリ)とのセットで利用する。

es-lint-loader

  • ESLint(静的コード解析ツール)をwebpack上で実行するためのローダー。
    • いろいろ設定があるらしい。

参考

16
22
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
16
22