最初からガイドに従っている場合は、「Hello webpack」と表示される小さなプロジェクトが完成しているはずです。では、画像などの他のアセットを組み込んで、どのように処理されるかを見てみましょう。
webpack以前は、フロントエンド開発者はgruntやgulpなどのツールを使用して、これらのアセットを処理し、/src
フォルダから/dist
または/build
ディレクトリに移動していました。JavaScriptモジュールにも同じ考え方が使用されていましたが、webpackなどのツールはすべての依存関係を**動的にバンドル**します(依存関係グラフと呼ばれるものを作成します)。これは、すべてのモジュールが**明示的に依存関係を宣言**するようになり、使用されていないモジュールをバンドルしなくなるため、素晴らしいことです。
webpackの最もクールな機能の1つは、ローダーまたは組み込みのアセットモジュールのサポートがあれば、JavaScript以外にも**あらゆる種類のファイルを含めることができる**ことです。つまり、JavaScriptについて上記で挙げた利点(明示的な依存関係など)は、WebサイトまたはWebアプリの構築に使用されるすべてに適用できます。すでに設定に精通している可能性のあるCSSから始めましょう。
始める前に、プロジェクトに少し変更を加えましょう。
dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
- <title>Getting Started</title>
+ <title>Asset Management</title>
</head>
<body>
- <script src="main.js"></script>
+ <script src="bundle.js"></script>
</body>
</html>
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
- filename: 'main.js',
+ filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
JavaScriptモジュール内からCSSファイルをimport
するには、style-loaderとcss-loaderをインストールしてmodule
設定に追加する必要があります。
npm install --save-dev style-loader css-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: ['style-loader', 'css-loader'],
+ },
+ ],
+ },
};
モジュールローダーはチェーン化できます。チェーン内の各ローダーは、処理されたリソースに変換を適用します。チェーンは逆順に実行されます。最初のローダーは、その結果(変換が適用されたリソース)を次のローダーに渡し、以降も同様です。最終的に、webpackはチェーンの最後のローダーによってJavaScriptが返されることを期待します。
上記のローダーの順序は維持する必要があります。'style-loader'
が最初に来て、'css-loader'
が続きます。この規則に従わないと、webpackはエラーをスローする可能性があります。
これにより、そのスタイリングに依存するファイルにimport './style.css'
を記述できます。これで、そのモジュールが実行されると、文字列化されたCSSを含む<style>
タグがhtmlファイルの<head>
に挿入されます。
プロジェクトに新しいstyle.css
ファイルを追加し、index.js
にインポートして試してみましょう。
プロジェクト
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- style.css
|- index.js
|- /node_modules
src/style.css
.hello {
color: red;
}
src/index.js
import _ from 'lodash';
+import './style.css';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ element.classList.add('hello');
return element;
}
document.body.appendChild(component());
ビルドコマンドを実行します。
$ npm run build
...
[webpack-cli] Compilation finished
asset bundle.js 72.6 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
orphan modules 326 bytes [orphan] 1 module
cacheable modules 539 KiB
modules by path ./node_modules/ 538 KiB
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] [code generated]
./node_modules/css-loader/dist/runtime/api.js 1.57 KiB [built] [code generated]
modules by path ./src/ 965 bytes
./src/index.js + 1 modules 639 bytes [built] [code generated]
./node_modules/css-loader/dist/cjs.js!./src/style.css 326 bytes [built] [code generated]
webpack 5.4.0 compiled successfully in 2231 ms
ブラウザで再びdist/index.html
を開くと、Hello webpack
が赤色でスタイルされていることがわかります。webpack が何をしたかを確認するには、ページを検査します(ページソースを表示しても、<style>
タグは JavaScript によって動的に作成されるため、結果は表示されません)。ページの head タグを見てください。 index.js
でインポートしたスタイルブロックが含まれているはずです。
本番環境では、より高速な読み込み時間を実現するために、CSS を最小化することができます。ほとんどの場合、そうするべきです。その上で、思いつく限りのほぼすべての種類の CSS に対応するローダーが存在します。たとえば、postcss、sass、lessなどです。
これで CSS を取り込むことができましたが、背景やアイコンなどの画像はどうでしょうか? webpack 5 以降では、組み込みのアセットモジュールを使用して、それらをシステムに簡単に組み込むことができます。
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
+ {
+ test: /\.(png|svg|jpg|jpeg|gif)$/i,
+ type: 'asset/resource',
+ },
],
},
};
import MyImage from './my-image.png'
を実行すると、その画像は処理されてoutput
ディレクトリに追加され、MyImage
変数には処理後の画像の最終 URL が含まれます。上記のようにcss-loaderを使用する場合、CSS 内のurl('./my-image.png')
に対して同様の処理が行われます。ローダーはこれがローカルファイルであることを認識し、'./my-image.png'
パスをoutput
ディレクトリ内の画像への最終パスに置き換えます。html-loaderは、<img src="./my-image.png" />
を同じ方法で処理します。
プロジェクトに画像を追加して、これがどのように機能するかを見てみましょう。好きな画像を使用できます。
プロジェクト
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- icon.png
|- style.css
|- index.js
|- /node_modules
src/index.js
import _ from 'lodash';
import './style.css';
+import Icon from './icon.png';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('hello');
+ // Add the image to our existing div.
+ const myIcon = new Image();
+ myIcon.src = Icon;
+
+ element.appendChild(myIcon);
+
return element;
}
document.body.appendChild(component());
src/style.css
.hello {
color: red;
+ background: url('./icon.png');
}
新しいビルドを作成し、index.html
ファイルを再び開いてみましょう。
$ npm run build
...
[webpack-cli] Compilation finished
assets by status 9.88 KiB [cached] 1 asset
asset bundle.js 73.4 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1.82 KiB 6 modules
orphan modules 326 bytes [orphan] 1 module
cacheable modules 540 KiB (javascript) 9.88 KiB (asset)
modules by path ./node_modules/ 539 KiB
modules by path ./node_modules/css-loader/dist/runtime/*.js 2.38 KiB
./node_modules/css-loader/dist/runtime/api.js 1.57 KiB [built] [code generated]
./node_modules/css-loader/dist/runtime/getUrl.js 830 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] [code generated]
modules by path ./src/ 1.45 KiB (javascript) 9.88 KiB (asset)
./src/index.js + 1 modules 794 bytes [built] [code generated]
./src/icon.png 42 bytes (javascript) 9.88 KiB (asset) [built] [code generated]
./node_modules/css-loader/dist/cjs.js!./src/style.css 648 bytes [built] [code generated]
webpack 5.4.0 compiled successfully in 1972 ms
すべてがうまくいけば、アイコンが繰り返し背景として、またHello webpack
テキストの横にimg
要素として表示されるはずです。この要素を検査すると、実際のファイル名が29822eaa871e8eadeaa4.png
のようなものに変更されていることがわかります。これは、webpack がsrc
フォルダ内のファイルを見つけて処理したことを意味します!
それでは、フォントなどの他のアセットはどうでしょうか?アセットモジュールは、それらを介してロードするすべてのファイルを受け取り、ビルドディレクトリに出力します。これは、フォントを含むあらゆる種類のファイルに使用できることを意味します。フォントファイルを処理するようにwebpack.config.js
を更新してみましょう。
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
+ {
+ test: /\.(woff|woff2|eot|ttf|otf)$/i,
+ type: 'asset/resource',
+ },
],
},
};
プロジェクトにフォントファイルをいくつか追加します。
プロジェクト
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- my-font.woff
+ |- my-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules
ローダーが設定され、フォントが配置されたら、@font-face
宣言を介してそれらを組み込むことができます。画像の場合と同様に、ローカルのurl(...)
ディレクティブは webpack によって取得されます。
src/style.css
+@font-face {
+ font-family: 'MyFont';
+ src: url('./my-font.woff2') format('woff2'),
+ url('./my-font.woff') format('woff');
+ font-weight: 600;
+ font-style: normal;
+}
+
.hello {
color: red;
+ font-family: 'MyFont';
background: url('./icon.png');
}
新しいビルドを実行して、webpack がフォントを処理したかどうかを確認しましょう。
$ npm run build
...
[webpack-cli] Compilation finished
assets by status 9.88 KiB [cached] 1 asset
assets by info 33.2 KiB [immutable]
asset 55055dbfc7c6a83f60ba.woff 18.8 KiB [emitted] [immutable] [from: src/my-font.woff] (auxiliary name: main)
asset 8f717b802eaab4d7fb94.woff2 14.5 KiB [emitted] [immutable] [from: src/my-font.woff2] (auxiliary name: main)
asset bundle.js 73.7 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1.82 KiB 6 modules
orphan modules 326 bytes [orphan] 1 module
cacheable modules 541 KiB (javascript) 43.1 KiB (asset)
javascript modules 541 KiB
modules by path ./node_modules/ 539 KiB
modules by path ./node_modules/css-loader/dist/runtime/*.js 2.38 KiB 2 modules
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] [code generated]
modules by path ./src/ 1.98 KiB
./src/index.js + 1 modules 794 bytes [built] [code generated]
./node_modules/css-loader/dist/cjs.js!./src/style.css 1.21 KiB [built] [code generated]
asset modules 126 bytes (javascript) 43.1 KiB (asset)
./src/icon.png 42 bytes (javascript) 9.88 KiB (asset) [built] [code generated]
./src/my-font.woff2 42 bytes (javascript) 14.5 KiB (asset) [built] [code generated]
./src/my-font.woff 42 bytes (javascript) 18.8 KiB (asset) [built] [code generated]
webpack 5.4.0 compiled successfully in 2142 ms
dist/index.html
を再び開き、Hello webpack
テキストが新しいフォントに変更されているかどうかを確認します。すべてうまくいけば、変更が表示されるはずです。
ロードできるもう1つの便利なアセットは、JSONファイル、CSV、TSV、XMLなどのデータです。JSONのサポートは、NodeJSと同様に実際に組み込まれています。つまり、import Data from './data.json'
はデフォルトで機能します。CSV、TSV、XMLをインポートするには、csv-loaderとxml-loaderを使用できます。3つすべての読み込みを処理してみましょう。
npm install --save-dev csv-loader xml-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
+ {
+ test: /\.(csv|tsv)$/i,
+ use: ['csv-loader'],
+ },
+ {
+ test: /\.xml$/i,
+ use: ['xml-loader'],
+ },
],
},
};
プロジェクトにデータファイルをいくつか追加します。
プロジェクト
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- data.xml
+ |- data.csv
|- my-font.woff
|- my-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules
src/data.xml
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Mary</to>
<from>John</from>
<heading>Reminder</heading>
<body>Call Cindy on Tuesday</body>
</note>
src/data.csv
to,from,heading,body
Mary,John,Reminder,Call Cindy on Tuesday
Zoe,Bill,Reminder,Buy orange juice
Autumn,Lindsey,Letter,I miss you
これで、4種類のデータ(JSON、CSV、TSV、XML)のいずれかをimport
できます。インポートするData
変数には、消費用に解析されたJSONが含まれます。
src/index.js
import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
+import Data from './data.xml';
+import Notes from './data.csv';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('hello');
// Add the image to our existing div.
const myIcon = new Image();
myIcon.src = Icon;
element.appendChild(myIcon);
+ console.log(Data);
+ console.log(Notes);
+
return element;
}
document.body.appendChild(component());
npm run build
コマンドを再実行し、dist/index.html
を開きます。開発者ツールのコンソールを見ると、インポートされたデータがコンソールにログされていることがわかります。
// No warning
import data from './data.json';
// Warning shown, this is not allowed by the spec.
import { foo } from './data.json';
特定のwebpackローダーの代わりにカスタムパーサーを使用することにより、toml
、yaml
、またはjson5
ファイルをJSONモジュールとしてインポートできます。
src
フォルダの下にdata.toml
、data.yaml
、およびdata.json5
ファイルがあるとします。
src/data.toml
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
organization = "GitHub"
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
dob = 1979-05-27T07:32:00Z
src/data.yaml
title: YAML Example
owner:
name: Tom Preston-Werner
organization: GitHub
bio: |-
GitHub Cofounder & CEO
Likes tater tots and beer.
dob: 1979-05-27T07:32:00.000Z
src/data.json5
{
// comment
title: 'JSON5 Example',
owner: {
name: 'Tom Preston-Werner',
organization: 'GitHub',
bio: 'GitHub Cofounder & CEO\n\
Likes tater tots and beer.',
dob: '1979-05-27T07:32:00.000Z',
},
}
最初にtoml
、yamljs
、およびjson5
パッケージをインストールします。
npm install toml yamljs json5 --save-dev
そして、webpack設定でそれらを設定します。
webpack.config.js
const path = require('path');
+const toml = require('toml');
+const yaml = require('yamljs');
+const json5 = require('json5');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
{
test: /\.(csv|tsv)$/i,
use: ['csv-loader'],
},
{
test: /\.xml$/i,
use: ['xml-loader'],
},
+ {
+ test: /\.toml$/i,
+ type: 'json',
+ parser: {
+ parse: toml.parse,
+ },
+ },
+ {
+ test: /\.yaml$/i,
+ type: 'json',
+ parser: {
+ parse: yaml.parse,
+ },
+ },
+ {
+ test: /\.json5$/i,
+ type: 'json',
+ parser: {
+ parse: json5.parse,
+ },
+ },
],
},
};
src/index.js
import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
import Data from './data.xml';
import Notes from './data.csv';
+import toml from './data.toml';
+import yaml from './data.yaml';
+import json from './data.json5';
+
+console.log(toml.title); // output `TOML Example`
+console.log(toml.owner.name); // output `Tom Preston-Werner`
+
+console.log(yaml.title); // output `YAML Example`
+console.log(yaml.owner.name); // output `Tom Preston-Werner`
+
+console.log(json.title); // output `JSON5 Example`
+console.log(json.owner.name); // output `Tom Preston-Werner`
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('hello');
// Add the image to our existing div.
const myIcon = new Image();
myIcon.src = Icon;
element.appendChild(myIcon);
console.log(Data);
console.log(Notes);
return element;
}
document.body.appendChild(component());
npm run build
コマンドを再実行し、dist/index.html
を開きます。インポートされたデータがコンソールに記録されていることがわかります。
上記で述べたすべてのことの最もクールな部分は、このようにアセットを読み込むことで、モジュールとアセットをより直感的な方法でグループ化できることです。すべてを含むグローバルな/assets
ディレクトリに依存する代わりに、アセットを使用するコードでアセットをグループ化できます。たとえば、このような構造が役立ちます。
- |- /assets
+ |– /components
+ | |– /my-component
+ | | |– index.jsx
+ | | |– index.css
+ | | |– icon.svg
+ | | |– img.png
この設定により、密接に結合されたすべてが一緒に存在するため、コードの移植性が大幅に向上します。たとえば、/my-component
を別のプロジェクトで使用する場合、それをそこの/components
ディレクトリにコピーまたは移動します。_外部依存関係_がインストールされていて、_設定で同じローダーが定義されていれば_、準備完了です。
ただし、古い方法に縛られている場合や、複数のコンポーネント(ビュー、テンプレート、モジュールなど)で共有されるアセットがある場合は、これらのアセットをベースディレクトリに保存し、エイリアシングを使用してimport
しやすくすることもできます。
次のガイドでは、このガイドで使用したすべてのアセットを使用するわけではないため、ガイドの次の部分である出力管理に備えてクリーンアップを行いましょう。
プロジェクト
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
- |- data.csv
- |- data.json5
- |- data.toml
- |- data.xml
- |- data.yaml
- |- icon.png
- |- my-font.woff
- |- my-font.woff2
- |- style.css
|- index.js
|- /node_modules
webpack.config.js
const path = require('path');
-const toml = require('toml');
-const yaml = require('yamljs');
-const json5 = require('json5');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
- module: {
- rules: [
- {
- test: /\.css$/i,
- use: ['style-loader', 'css-loader'],
- },
- {
- test: /\.(png|svg|jpg|jpeg|gif)$/i,
- type: 'asset/resource',
- },
- {
- test: /\.(woff|woff2|eot|ttf|otf)$/i,
- type: 'asset/resource',
- },
- {
- test: /\.(csv|tsv)$/i,
- use: ['csv-loader'],
- },
- {
- test: /\.xml$/i,
- use: ['xml-loader'],
- },
- {
- test: /\.toml$/i,
- type: 'json',
- parser: {
- parse: toml.parse,
- },
- },
- {
- test: /\.yaml$/i,
- type: 'json',
- parser: {
- parse: yaml.parse,
- },
- },
- {
- test: /\.json5$/i,
- type: 'json',
- parser: {
- parse: json5.parse,
- },
- },
- ],
- },
};
src/index.js
import _ from 'lodash';
-import './style.css';
-import Icon from './icon.png';
-import Data from './data.xml';
-import Notes from './data.csv';
-import toml from './data.toml';
-import yaml from './data.yaml';
-import json from './data.json5';
-
-console.log(toml.title); // output `TOML Example`
-console.log(toml.owner.name); // output `Tom Preston-Werner`
-
-console.log(yaml.title); // output `YAML Example`
-console.log(yaml.owner.name); // output `Tom Preston-Werner`
-
-console.log(json.title); // output `JSON5 Example`
-console.log(json.owner.name); // output `Tom Preston-Werner`
function component() {
const element = document.createElement('div');
- // Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
- element.classList.add('hello');
-
- // Add the image to our existing div.
- const myIcon = new Image();
- myIcon.src = Icon;
-
- element.appendChild(myIcon);
-
- console.log(Data);
- console.log(Notes);
return element;
}
document.body.appendChild(component());
そして、前に追加した依存関係を削除します。
npm uninstall css-loader csv-loader json5 style-loader toml xml-loader yamljs
出力管理に進みましょう。