One, foreword
This article will show you how to use WebPack Loaders, one of the core concepts of WebPack, to process static resources.
Static resources include the following contents:
- Style Files (CSS)
- Image (Images)
- Fonts
- Data files
- .
File structure:
webpack
|- /dist
|- index.html
|- /src
|- /assets
|- /fonts
|- font-a.otf
|- font-b.ttf
|- font-c.woff
|- font-d.woff2
|- font-e.svg
|- /icons
|- icon-a.png
|- incon-b.svg
|- /images
|- img-a.png
|- img-b.jpg
|- img-gif.jpg
|- /js
|- js-a.js
|- /others
|- o-a.txt
|- o-b.xml
|- /styles
|- global.scss
|- reset.css
|- /components
|- content.js
|- header.js
|- sidebar.js
|- index.js
|- package.json
|- webpack.config.js
Copy the code
The assets folder contains several static files (such as fonts, ICONS, images, text, styles, and JS files), and there are several folders in the middle according to different files. The file names have been simplified here for convenience.
index.js
/ / js module
const Header = require("./components/header");
const Sidebar = require("./components/sidebar");
const Content = require("./components/content");
// Image module (these 5 are small images)
const icon1 = require("./assets/icons/mac-os.png");
const icon2 = require("./assets/icons/apple-tv.png");
const icon3 = require("./assets/icons/apple-contacts.png");
const iconSvg1 = require("./assets/icons/arrow-up.svg");
const iconSvg2 = require("./assets/icons/arrow-down.svg");
// Image module (these 3 are big images)
const dog1 = require("./assets/images/animal-dog-1.png");
const avatar1 = require("./assets/images/avatar-1.jpg");
const cat1 = require("./assets/images/express-cat-1.gif");
// Data module
const fileTxt = require("./assets/data/notes.txt");
const fileXml = require("./assets/data/hello.xml");
// Font module
const font = require("./assets/fonts/Calibre-Regular.otf");
const iconFont1 = require("./assets/fonts/iconfont.ttf");
const iconFont2 = require("./assets/fonts/iconfont.woff");
const iconFont3 = require("./assets/fonts/iconfont.woff2");
// Style module
// const reset = require('./assets/styles/reset.css');
// const global = require('./assets/styles/global.scss');
const dom = document.getElementById("root");
// header
new Header(dom);
// side-bar
new Sidebar(dom);
// content
new Content(dom);
Copy the code
Various file modules are introduced and put into variables. Each module has a value after packaging and is usable.
2. Loaders
webpack enables use of loaders to preprocess files. This allows you to bundle any static resource way beyond JavaScript. You can easily write your own loaders using Node.js.
Simply put, loaders preprocesses and packages any static file.
For example: image files, style files, HTML files, and even some data files: TXT files, XML files…
So, how do you configure it?
Asset Modules — Static resource Modules
According to Webpack5’s documentation, it simplifies the configuration of files in previous versions and provides Asset Modules (static resource Modules) instead of raw-Loader, URl-loader, and file-loader.
Type: ‘asset’ = ‘asset’; (Note the type setting in the Module!)
// WebPack configuration file
const path = require("path");
module.exports = {
mode: "production".entry: {
main: "./src/index.js",},output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",},// *** The matching file in the module option will be converted by loaders!
module: {
rules: [
// Image file
{
test: /\.(jpe? g|png|gif|svg)$/i,
type: "asset".// This is usually converted to "asset/resource"
},
// Font file
{
test: /\.(otf|eot|woff2? |ttf|svg)$/i,
type: "asset".// This is normally converted to "asset/inline"
},
// Data file
{
test: /\.(txt|xml)$/i,
type: "asset".// This is usually converted to "asset/source"},],}};Copy the code
After each package, the file is put into the output folder according to the output configuration, but the compressed file is not packaged into the folder, and only exists in the source code of bundle.js in base64 encoding or URI encoding.
- Base64 in source code
- Uris in source code
By default, files smaller than 8 KB are base64 encoded, so how is the URI encoding shown above set?
1. Special treatment
Some files require special handling. For example, an SVG file converted to URI encoding is smaller than base64;
TXT, XML file type: ‘asset/source’ is better, it will export the source of the resource, so you can see the full picture, not base64 encoded strings.
Minimizing SVG files requires the installation of a third-party library: Mini-SVG-data-URI.
npm i -D mini-svg-data-uri
Copy the code
After installation, reconfigure as follows:
// WebPack configuration file
const path = require("path");
const miniSVGDataURI = require("mini-svg-data-uri");
module.exports = {
// ...
module: {
rules: [
// Image file
{
test: /\.(jpe? g|png|gif)$/i,
type: "asset",},/ / SVG files
{
test: /\.svg$/i,
type: "asset/inline".generator: {
dataUrl(content) {
content = content.toString();
returnminiSVGDataURI(content); }},},// Font file
{
test: /\.(otf|eot|woff2? |ttf|svg)$/i,
type: "asset",},// Data file
{
test: /\.(txt|xml)$/i,
type: "asset/source",},],},};Copy the code
At this point, the packaging is complete. Now, to see what data these file modules are packaged into, add the following code to the index.js file:
/ / js module
const Header = require("./components/header");
const Sidebar = require("./components/sidebar");
const Content = require("./components/content");
// Image module (these 5 are small images)
const icon1 = require("./assets/icons/mac-os.png");
const icon2 = require("./assets/icons/apple-tv.png");
const icon3 = require("./assets/icons/apple-contacts.png");
const iconSvg1 = require("./assets/icons/arrow-up.svg");
const iconSvg2 = require("./assets/icons/arrow-down.svg");
// Image module (these 3 are big images)
const dog1 = require("./assets/images/animal-dog-1.png");
const avatar1 = require("./assets/images/avatar-1.jpg");
const cat1 = require("./assets/images/express-cat-1.gif");
// Other file modules
const fileTxt = require("./assets/data/notes.txt");
const fileXml = require("./assets/data/hello.xml");
// Font module
const font = require("./assets/fonts/Calibre-Regular.otf");
const iconFont1 = require("./assets/fonts/iconfont.ttf");
const iconFont2 = require("./assets/fonts/iconfont.woff");
const iconFont3 = require("./assets/fonts/iconfont.woff2");
// Style module
// const reset = require('./assets/styles/reset.css');
// const global = require('./assets/styles/global.scss');
// Print these modules in the console:
console.log("icon-png: ", icon1);
console.log("icon-svg: ", iconSvg1);
console.log("png: ", dog1);
console.log("jpg: ", avatar1);
console.log("gif: ", cat1);
console.log("txt: ", fileTxt);
console.log("xml: ", fileXml);
console.log("font: ", font);
console.log("iconFont: ", iconFont1);
const dom = document.getElementById("root");
// Insert a picture
const img = new Image();
img.src = dog1; // The image module dog1 is used as the SRC attribute of the img variable
img.width = 200;
root.append(img);
// header
new Header(dom);
// side-bar
new Sidebar(dom);
// content
new Content(dom);
Copy the code
The browser page is displayed as follows:
You can see the SVG file(icon-svg)Is processed as URI encoding!
2. Configure the static file name
By default, the packaged files are scattered in the Dist folder and are difficult to distinguish and maintain.
Now that you need to put them into their respective folders, you need to manage file names uniformly.
webpack.config.js
const path = require("path");
const miniSVGDataURI = require("mini-svg-data-uri");
module.exports = {
mode: "production".entry: {
main: "./src/index.js",},output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js".// The path and file name of the static file after the package (default is global, if there is a separate setting, use its own independent setting).
assetModuleFilename: "assets/[name]_[hash][ext]",},module: {
rules: [
// Image file
{
test: /\.(jpe? g|png|gif)$/i,
type: "asset".generator: {
filename: "images/[name]_[hash][ext]".// Independent configuration}},/ / SVG files
{
test: /\.svg$/i,
type: "asset".generator: {
dataUrl(content) {
content = content.toString();
returnminiSVGDataURI(content); }},},// Font file
{
test: /\.(otf|eot|woff2? |ttf|svg)$/i,
type: "asset".generator: {
filename: "fonts/[name]_[hash][ext]",}},// Data file
{
test: /\.(txt|xml)$/i,
type: "asset/source".// exports the source code of the asset},],}};Copy the code
Lines 23-25, for configuring the static file name separately;
generator: {
filename: 'images/[name]_[hash][ext]' // Configure the package path and file name separately
},
Copy the code
Line 12, assetModuleFilename: ‘assets/[name][ext]’, which sets the global static file path and filename. If the file module is not configured separately, the file name is set accordingly.
[name] indicates the original file name, [hash] indicates the hash value, and [ext] indicates the file suffix. These all belong to a placeholder (placeholders), has mentioned: in webpack4 v4.webpack.js.org/loaders/fil…
3. The type of asset
When type is set to ‘asset’, the file is packaged according to the following policy:
- If a module is larger than 8 KB (which is the default), use
asset/resource
Is packaged into the output folder. (Similar to file-loader) - Otherwise, use
asset/inline
, inline to the package file. (Similar to URl-loader)
The difference is that the former is placed in a separate output folder, while the latter is processed as a Base64-encoded string that is introtracted into the JS file that is packaged out.
The latter has the advantage of reducing one HTTP request, but too long strings will also increase the volume of JS and cause slow loading, so it is necessary to determine which way to process files according to the actual situation.
Note that when treated as the latter, it is possible to set the encoding, such as the special handling mentioned above.
Manually by Rule. The parser. DataUrlCondition. MaxSize to set the boundaries between the two:
{
test: /\.(jpe? g|png|gif)$/i,
type: 'asset'.generator: {
filename: 'images/[name]_[hash][ext]',},parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 8KB (anything below 8KB will be compressed into base64)}}}, {test: /\.svg$/i,
type: 'asset'.generator: {
filename: 'icons/[name]_[hash][ext]'.dataUrl(content) {
content = content.toString();
return miniSVGDataURI(content); // Process files through the encoding algorithm provided by the plug-in}},parser: {
dataUrlCondition: {
maxSize: 2 * 1024 // 2kb (< 2KB)}}},Copy the code
In addition to asset/resource and asset/inline, there is an asset/source that handles TXT and XML files as mentioned above, which is equivalent to webPack4’s raw-loader.
Three, style file processing
1. style-loader & css-loader
Style-loader and CSS-Loader complement each other.
- Style – loader: will
<style>
The tag is inserted into the DOM. - Css-loader: Parses style files imported via @import, URL (), import/require().
Install the loaders:
npm install --save-dev css-loader style-loader
Copy the code
webpack.config.js
module.exports = {
module: {
rules: [
// ...
{
test: /\.css$/i,
use: ["style-loader"."css-loader"],},],},};Copy the code
Note the locations of the two loaders and write them in reverse.
index.js
// ...
const reset = require("./assets/styles/reset.css");
console.log("css: ", reset);
import "./assets/styles/reset.css";
const dom = document.getElementById("root");
dom.innerHTML += '<p class="iconfont icon-mianxingshezhi">This a text.</p>';
Copy the code
reset.css
@font-face {
font-family: "iconfont";
/* Project id 1947684 */
src: url(".. /fonts/iconfont.woff2? t=1627306378388") format("woff2"), url(".. /fonts/iconfont.woff? t=1627306378388") format("woff"),
url(".. /fonts/iconfont.ttf? t=1627306378388") format("truetype");
}
.iconfont {
font-family: "iconfont" ! important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-mianxingshezhi:before {
content: "\e6ad";
}
/ *... * /
Copy the code
Reset.css introduces the font icon (from iconfont), index.js imports the CSS file by import, and uses the font icon.
Among them,
The import ‘. / assets/styles/reset. CSS ‘,
onst reset = require('./assets/styles/reset.css');
The CSS code behind these two statements is parsed by csS-Loader.
The console is shown as follows:
In the figure above, after the CSS style has been parsed by the CSS-Loader,<style>
Tags are inserted into the DOM using a style-loader.
2. sass-loader
- Sass-loader: loads a sass /SCSS file and compiles it into the CSS.
Installation:
npm install sass-loader sass webpack --save-dev
Copy the code
webpack.config.js
module.exports = {
module: {
rules: [
// ...
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
"style-loader".// Translates CSS into CommonJS
"css-loader".// Compiles Sass to CSS
"sass-loader",],},],},};Copy the code
index.js
const global = require("./assets/styles/global.scss");
console.log("scss: ".global);
import "./assets/styles/global.scss";
const dom = document.getElementById("root");
// insert an image
const img = new Image();
img.src = dog1;
// img.width = 200;
img.classList.add("avatar");
root.append(img);
Copy the code
global.scss
// Customize variables
$color: #ff4200;
$fs: 14px;
$ls: 1.2;
// Customize mixins
@mixin size($w.$h: $w) {
width: $w;
height: $h;
}
body {
font-size: $fs;
background-color: #eaeaea;
.avatar {
@include size(150px);
transform: translateX(50px); }}Copy the code
The console is shown as follows:
Figure 2<style>
The style code inside the tag is global. SCSS translated into CSS and inserted into the DOM via a style-loader.
3. postcss-loader
PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more.
Postcss repository: github.com/postcss/pos…
Autoprefixer:github.com/postcss/aut…
Postcss-preset-env:github.com/csstools/po…
A) installation
Installation:
npm install --save-dev postcss-loader postcss
Copy the code
webpack.config.js
module.exports = {
module: {
rules: [
// ...
{
test: /\.s? css$/i,
use: ["style-loader"."css-loader"."sass-loader"."postcss-loader"],},],},};Copy the code
Note that postcss-Loader should be placed last.
B) configuration
Autoprefixer
PostCSS plugin to parse CSS and add vendor prefixes to CSS rules using values from Can I Use.
PostCSS Preset Env
PostCSS Preset Env lets you convert modern CSS into something most browsers can understand, determining the polyfills you need based on your targeted browsers or runtime environments.
PostCSS SCSS Syntax
A SCSS parser for PostCSS.
This module does not compile SCSS. It simply parses mixins as custom at-rules & variables as properties, so that PostCSS plugins can then transform SCSS source code alongside CSS.
Plugins need to be installed:
npm install postcss-preset-env autoprefixer postcss-scss --save-dev
Copy the code
In the root directory, create postcss.config.js
module.exports = {
syntax: "postcss-scss".plugins: [require("autoprefixer"), "postcss-preset-env"]};Copy the code
Webpack.config. js does not need to be modified.
Options for CSS – Loader
Different loaders have their own options, csS-loaders have two practical options.
- ImportLoaders: The option
importLoaders
allows you to configure how many loaders beforecss-loader
should be applied to@import
ed resources and CSS modules/ICSS imports. In simple terms, this allows you to make certain resources pass through previous loaders before executing csS-Loader. - Modules: Allows to enable/disable CSS modules or ICSS and setup configuration. Allows you to enable CSS modules.
webpack.config.js
module.exports = {
module: {
rules: [{test: /\.sc? ss$/i,
use: [
"style-loader",
{
loader: "css-loader".options: {
importLoaders: 2.// 0 => no loaders (default);
// 1 => postcss-loader;
// 2 => postcss-loader, sass-loader
modules: true.// Default is false ***}},"sass-loader"."postcss-loader",],},],},};Copy the code
Note that importLoaders is set to 2, which means that the first two loaders, namely ‘sass-loader’ and ‘postcss-loader’, are executed when the style file is matched.
Setting modules to true ensures that style modules are independent and not overwritten by each other. Here’s an example:
A) Not setting the modules option
src/assets/styles/global.scss
// Customize variables
$color: #ff4200;
$fs: 14px;
$ls: 1.2;
// Customize mixins
@mixin size($w.$h: $w) {
width: $w;
height: $h;
}
body {
font-size: $fs;
background-color: #eaeaea;
.avatar {
@include size(150px);
transform: translateX(50px); }}Copy the code
src/assets/js/createImg.js
import avatar from ".. /images/avatar-2.jpg";
import dog1 from ".. /images/animal-dog-1.png";
function createImg(root) {
const img = new Image();
img.src = dog1;
img.classList.add("avatar"); // Add the avatar class name
root.append(img);
}
export default createImg;
Copy the code
src/index.js
import "./assets/styles/reset.css";
import "./assets/styles/global.scss";
import dog1 from "./assets/images/animal-dog-1.png";
import createImg from "./assets/js/createImg.js";
const dom = document.getElementById("root");
// Create the first image
createImg(dom);
// Create the second diagram
// insert an image
const img = new Image();
img.src = dog1;
img.classList.add("avatar"); // // Add the name of the Avatar class
root.append(img);
Copy the code
In this case, the import ‘. / assets/styles/global. SCSS ‘it has effect on the global file, so it’s an import after createImg from’. / assets/js/createImg. Js’; You’re going to be affected. As a result, the style in line 7 of the createimg.js file is added, and the style in line 15 of the selector ‘avatar’ in global.scss is added.
After packaging, the result is as shown in the figure:
B) Set modules to true
After the setting, the code remains unchanged and the packaging is completed, the result is shown in the figure:
The two akita dogs in front and back become oversized because the style is not applied to the image.
When applying a CSS Module, add styles in the following ways:
(Note: only the code in index.js has been changed to restore it, while the code in the createimg.js module remains unchanged for contrast.)
src/index.js
import "./assets/styles/global.scss";
import style from "./assets/styles/global.scss"; // Customize the variable name and import it as a CSS Module
import dog1 from "./assets/images/animal-dog-1.png";
import createImg from "./assets/js/createImg.js";
const dom = document.getElementById("root");
// Create the first image
createImg(dom);
// Create the second diagram
// insert an image
const img = new Image();
img.src = dog1;
// Use the CSS module by customizable variable name style +. To the name of the Avatar class
img.classList.add(style.avatar);
root.append(img);
Copy the code
After packaging, the result is as shown in the figure:
By comparison, it can be found that the pattern of the akita dog set by the module method does exist, while the first one does not.
This method of using CSS Modules to add styles solves the problem of overwriting the same style globally (usually the class name and ID).
Reading reference:
- Github.com/css-modules…
- Github.com/css-modules…
- Webpack.js.org/loaders/css…
- Webpack.js.org/loaders/css…
summary
That’s the end of this article. In Webpack5, for static resource processing, we can simply set type to process files, which is very convenient. However, there are some special cases that need to be handled separately, such as setting the path and file name of the resource output, setting the URI encoding format, and setting the size limit of the file converted to base64. In style files, to prevent global style contamination, you can turn on the CSS Module to avoid it.