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), useasset/resourceIs packaged into the output folder. (Similar to file-loader)
  • Otherwise, useasset/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 optionimportLoaders allows you to configure how many loaders before css-loader should be applied to @imported 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.