Movatterモバイル変換


[0]ホーム

URL:


webpack logo
ag grid
ag charts

Asset Management

If you've been following the guides from the start, you will now have a small project that shows "Hello webpack". Now let's try to incorporate some other assets, like images, to see how they can be handled.

Prior to webpack, front-end developers would use tools likegrunt andgulp to process these assets and move them from their/src folder into their/dist or/build directory. The same idea was used for JavaScript modules, but tools like webpack willdynamically bundle all dependencies (creating what's known as adependency graph). This is great because every module nowexplicitly states its dependencies and we'll avoid bundling modules that aren't in use.

One of the coolest webpack features is that you can alsoinclude any other type of file, besides JavaScript, for which there is a loader or built-inAsset Modules support. This means that the same benefits listed above for JavaScript (e.g. explicit dependencies) can be applied to everything used in building a website or web app. Let's start with CSS, as you may already be familiar with that setup.

Setup

Let's make a minor change to our project before we get started:

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'),  },};

Loading CSS

In order toimport a CSS file from within a JavaScript module, you need to install and add thestyle-loader andcss-loader to yourmodule configuration:

npminstall --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'],+      },+    ],+  },};

Module loaders can be chained. Each loader in the chain applies transformations to the processed resource. A chain is executed in reverse order. The first loader passes its result (resource with applied transformations) to the next one, and so forth. Finally, webpack expects JavaScript to be returned by the last loader in the chain.

The above order of loaders should be maintained:'style-loader' comes first and followed by'css-loader'. If this convention is not followed, webpack is likely to throw errors.

tip

webpack uses a regular expression to determine which files it should look for and serve to a specific loader. In this case, any file that ends with.css will be served to thestyle-loader and thecss-loader.

This enables you toimport './style.css' into the file that depends on that styling. Now, when that module is run, a<style> tag with the stringified css will be inserted into the<head> of your html file.

Let's try it out by adding a newstyle.css file to our project and import it in ourindex.js:

project

 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());

Now run your build command:

$npm run build...[webpack-cli] Compilation finishedasset bundle.js72.6 KiB[emitted][minimized](name: main)1 related assetruntime modules1000 bytes5 modulesorphan modules326 bytes[orphan]1 modulecacheable modules539 KiB  modules by path ./node_modules/538 KiB    ./node_modules/lodash/lodash.js530 KiB[built][code generated]    ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js6.67 KiB[built][code generated]    ./node_modules/css-loader/dist/runtime/api.js1.57 KiB[built][code generated]  modules by path ./src/965 bytes    ./src/index.js +1 modules639 bytes[built][code generated]    ./node_modules/css-loader/dist/cjs.js!./src/style.css326 bytes[built][code generated]webpack5.4.0 compiled successfullyin2231 ms

Open updist/index.html in your browser again and you should see thatHello webpack is now styled in red. To see what webpack did, inspect the page (don't view the page source, as it won't show you the result, because the<style> tag is dynamically created by JavaScript) and look at the page's head tags. It should contain the style block that we imported inindex.js.

Note that you can, and in most cases should,minimize css for better load times in production. On top of that, loaders exist for pretty much any flavor of CSS you can think of –postcss,sass, andless to name a few.

Loading Images

So now we're pulling in our CSS, but what about our images like backgrounds and icons? As of webpack 5, using the built-inAsset Modules we can easily incorporate those in our system as well:

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',+      },    ],  },};

Now, when youimport MyImage from './my-image.png', that image will be processed and added to youroutput directoryand theMyImage variable will contain the final url of that image after processing. When using thecss-loader, as shown above, a similar process will occur forurl('./my-image.png') within your CSS. The loader will recognize this is a local file, and replace the'./my-image.png' path with the final path to the image in youroutput directory. Thehtml-loader handles<img src="./my-image.png" /> in the same manner.

Let's add an image to our project and see how this works, you can use any image you like:

project

 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');}

Let's create a new build and open up theindex.html file again:

$npm run build...[webpack-cli] Compilation finishedassets by status9.88 KiB[cached]1 assetasset bundle.js73.4 KiB[emitted][minimized](name: main)1 related assetruntime modules1.82 KiB6 modulesorphan modules326 bytes[orphan]1 modulecacheable modules540 KiB(javascript)9.88 KiB(asset)  modules by path ./node_modules/539 KiB    modules by path ./node_modules/css-loader/dist/runtime/*.js2.38 KiB      ./node_modules/css-loader/dist/runtime/api.js1.57 KiB[built][code generated]      ./node_modules/css-loader/dist/runtime/getUrl.js830 bytes[built][code generated]    ./node_modules/lodash/lodash.js530 KiB[built][code generated]    ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js6.67 KiB[built][code generated]  modules by path ./src/1.45 KiB(javascript)9.88 KiB(asset)    ./src/index.js +1 modules794 bytes[built][code generated]    ./src/icon.png42 bytes(javascript)9.88 KiB(asset)[built][code generated]    ./node_modules/css-loader/dist/cjs.js!./src/style.css648 bytes[built][code generated]webpack5.4.0 compiled successfullyin1972 ms

If all went well, you should now see your icon as a repeating background, as well as animg element beside ourHello webpack text. If you inspect this element, you'll see that the actual filename has changed to something like29822eaa871e8eadeaa4.png. This means webpack found our file in thesrc folder and processed it!

Loading Fonts

So what about other assets like fonts? The Asset Modules will take any file you load through them and output it to your build directory. This means we can use them for any kind of file, including fonts. Let's update ourwebpack.config.js to handle font files:

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',+      },    ],  },};

Add some font files to your project:

project

 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

With the loader configured and fonts in place, you can incorporate them via an@font-face declaration. The localurl(...) directive will be picked up by webpack, as it was with the image:

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');}

Now run a new build and let's see if webpack handled our fonts:

$npm run build...[webpack-cli] Compilation finishedassets by status9.88 KiB[cached]1 assetassets by info33.2 KiB[immutable]  asset 55055dbfc7c6a83f60ba.woff18.8 KiB[emitted][immutable][from: src/my-font.woff](auxiliary name: main)  asset 8f717b802eaab4d7fb94.woff214.5 KiB[emitted][immutable][from: src/my-font.woff2](auxiliary name: main)asset bundle.js73.7 KiB[emitted][minimized](name: main)1 related assetruntime modules1.82 KiB6 modulesorphan modules326 bytes[orphan]1 modulecacheable modules541 KiB(javascript)43.1 KiB(asset)  javascript modules541 KiB    modules by path ./node_modules/539 KiB      modules by path ./node_modules/css-loader/dist/runtime/*.js2.38 KiB2 modules      ./node_modules/lodash/lodash.js530 KiB[built][code generated]      ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js6.67 KiB[built][code generated]    modules by path ./src/1.98 KiB      ./src/index.js +1 modules794 bytes[built][code generated]      ./node_modules/css-loader/dist/cjs.js!./src/style.css1.21 KiB[built][code generated]  asset modules126 bytes(javascript)43.1 KiB(asset)    ./src/icon.png42 bytes(javascript)9.88 KiB(asset)[built][code generated]    ./src/my-font.woff242 bytes(javascript)14.5 KiB(asset)[built][code generated]    ./src/my-font.woff42 bytes(javascript)18.8 KiB(asset)[built][code generated]webpack5.4.0 compiled successfullyin2142 ms

Open updist/index.html again and see if ourHello webpack text has changed to the new font. If all is well, you should see the changes.

Loading Data

Another useful asset that can be loaded is data, like JSON files, CSVs, TSVs, and XML. Support for JSON is actually built-in, similar to NodeJS, meaningimport Data from './data.json' will work by default. To import CSVs, TSVs, and XML you could use thecsv-loader andxml-loader. Let's handle loading all three:

npminstall --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'],+      },    ],  },};

Add some data files to your project:

project

 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,bodyMary,John,Reminder,Call Cindy on TuesdayZoe,Bill,Reminder,Buy orange juiceAutumn,Lindsey,Letter,I miss you

Now you canimport any one of those four types of data (JSON, CSV, TSV, XML) and theData variable you import, will contain parsed JSON for consumption:

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());

Re-run thenpm run build command and opendist/index.html. If you look at the console in your developer tools, you should be able to see your imported data being logged to the console!

tip

This can be especially helpful when implementing some sort of data visualization using a tool liked3. Instead of making an ajax request and parsing the data at runtime you can load it into your module during the build process so that the parsed data is ready to go as soon as the module hits the browser.

warning

Only the default export of JSON modules can be used without warning.

// No warningimport datafrom'./data.json';// Warning shown, this is not allowed by the spec.import{ foo}from'./data.json';

Customize parser of JSON modules

It's possible to import anytoml,yaml orjson5 files as a JSON module by using acustom parser instead of a specific webpack loader.

Let's say you have adata.toml, adata.yaml and adata.json5 files undersrc folder:

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 Exampleowner:name: Tom Preston-Wernerorganization: GitHubbio:|-    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',  },}

Installtoml,yamljs andjson5 packages first:

npminstall toml yamljs json5 --save-dev

And configure them in your webpack configuration:

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());

Re-run thenpm run build command and opendist/index.html. You should be able to see your imported data being logged to the console!

Global Assets

The coolest part of everything mentioned above, is that loading assets this way allows you to group modules and assets in a more intuitive way. Instead of relying on a global/assets directory that contains everything, you can group assets with the code that uses them. For example, a structure like this can be useful:

- |- /assets+ |– /components+ |  |– /my-component+ |  |  |– index.jsx+ |  |  |– index.css+ |  |  |– icon.svg+ |  |  |– img.png

This setup makes your code a lot more portable as everything that is closely coupled now lives together. Let's say you want to use/my-component in another project, copy or move it into the/components directory over there. As long as you've installed anyexternal dependencies and yourconfiguration has the same loaders defined, you should be good to go.

However, let's say you're locked into your old ways or you have some assets that are shared between multiple components (views, templates, modules, etc.). It's still possible to store these assets in a base directory and even usealiasing to make them easier toimport.

Wrapping up

For the next guides we won't be using all the different assets we've used in this guide, so let's do some cleanup so we're prepared for the next piece of the guidesOutput Management:

project

 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());

And remove those dependencies we added before:

npm uninstall css-loader csv-loader json5 style-loader toml xml-loader yamljs

Next guide

Let's move on toOutput Management

Further Reading

10 Contributors

skipjackmichael-ciniawskyTheDutchCodersudarsangpchenxsanEugeneHlushkoAnayaDesignwizardofhogwartsastonizersnitin315

[8]ページ先頭

©2009-2025 Movatter.jp