Directory:

  1. The basic concept
  2. Loader Development Introduction
  3. Local Loader Debugging
  4. Publish and reference the Loader
  5. Demo: Sprite image loader

1. Basic concepts

As we all know, WebPack is a module packer. But Webpack can only handle JS and JSON files.

Loader enables WebPack to process other types of files and convert them into valid modules for use by applications and to be added to dependency diagrams.

Loader is essentially a JS module that exports functions. The input and output parameters of a function can be interpreted as a file stream (String or Buffer). The function processes the incoming file stream and returns a new file stream after processing.

Loaders can be synchronous:

module.exports = function (content, map, meta) {
  // Content is the content of the file passed in
  // Handle content
  const newContent = doSomething(content);
  return newContent; // Return the contents of the processed file
};
Copy the code

It can also be asynchronous:

module.exports = function (content, map, meta) {
const callback = this.async(); // Get the callback function
// Handle content
const newContent = doSomething(content);
// Callback takes 4 arguments, in order:
// 1. The Error parameter Error or null is mandatory
// 2. Content of type String/Buffer, mandatory
// 3. Optional parameter sourceMap
// 4. Optional parameter meta
callback(null, newContent, map, meta);
};
Copy the code

The official recommendation is to use asynchronous Loaders as much as possible.

There are many third-party loaders in the Webpack community. After installation, you can configure them to use webpack.config.js:

// webpack.config.js configures the loader
module: {
    rules: [{
        test: /\.css$/i,
        use: ['style-loader'.'css-loader']]}},Copy the code

Two common style handling loaders are configured: style-loader and CSS-loader.

Rules The rules array is used to specify which loaders to apply to modules.

As you can see, objects in Rules have two attributes:

  • The value of the test property is a regular expression used for file type matching, in this case with.css or. CSS end file;
  • useProperty is an array of Loaders that specify which loader operations to perform on these CSS files. Here multiple loaders willFrom right to leftforChain callsIn the preceding configuration, csS-loader is executed first and then style-loader is executed. Similar to gulp tasks, but in a different order, gulp tasks are executed from left to right. Loader is more likeComposite functionExecute from right to left.

So far, we have roughly understood what loader is, what it is used for, and how to configure and use it.

2. Loader Development Introduction

NPM init -y initialize the project named yzz-sprite-loader, CD enter the project, create the index.js file, the content is as follows:

// yzz-sprite-loader/index.js
module.exports = function (content, map, meta) {
    const callback = this.async();
    callback(null, content, map, meta);
}
Copy the code

At this point, we have written an asynchronous loader that does nothing.

The official provides some reference criteria for loader development:

  • Keep it simple, a loader only does one thing
  • Use chain calls
  • modular
  • Stateless, each run is independent of the previous run results
  • Using the loader – utils package
  • Identify external files to use with addDependency
  • Need to solve the problem of module dependency in the code, such as CSS @import, can be converted to require mode, etc
  • Extract common code
  • Avoid absolute paths
  • Using peerDependency

Webpack.docschina.org/contribute/…

3. Debug the local Loader

After writing loader, how to reference debug in project?

Build a simple webpack project test-webpack:

  1. CD test-webpack, enter the project
  2. NPM init-y, initializes the project
  3. NPM install webpack webpack-cli –save-dev, install webpack dependency
  4. New files: webpack. Config. Js, index. HTML, SRC/index, js, SRC/style.css. CSS
  5. intest-webpack/webpack.config.jsTo import our loader:
// test-webpack/webpack.config.js
const path = require("path");


module.exports = {
    entry: "./src/index.js",
    mode: "development",
    output: {
        filename: "main.js",
        path: path.resolve(__dirname, "dist"),
    },
    module: {
        rules: [{
            test: /\.css$/i,
            use: [{
                loader: path.resolve("../yzz-sprite-loader/index.js"),
            },
            ],
        },
        ],
    },
};
Copy the code

Here the local loader is imported using a relative path.

  1. intest-webpack/index.jsStyle. CSS:
import './style.css'; 
Copy the code

Yzz-sprite-loader /index.js console: yzz-sprite-loader/index.js

module.exports = function (content, map, meta) {
    const callback = this.async();
    console.log('my loader is running');
    callback(null, content, map, meta);
}
Copy the code

Run yarn Run webpack in the test-webpack directory and you can see the console print my loader is running:

Success! βœ…

4. Publish and reference the Loader

Just three steps 🚢🚢🚢 :

  1. cd yzz-sprite-loaderEnter loader project
  2. npm loginLog in to the NPM account
  3. performnpm publish

The reference method is as follows:

NPM I yzz-sprite-loader -d and modify webpack.config.js in the test-webpack project:

rules: [{
    test: /\.css$/i,
    use: ['yzz-sprite-loader'],}],Copy the code

So far, our loader is basically online, except for doing nothing

5. Demo: Sprite image Loader

It’s time to add some utility!

I believe most people have used or heard of Sprite CSS Sprite. In fact, it is to merge multiple background images into one image to reduce the number of HTTP requests, and then use CSS background-position to accurately position the synthesized image.

Here I directly use an open source toolkit: github.com/twolfson/sp…

Spritesmith is used as follows:

var Spritesmith = require('spritesmith');

// Generate Sprite image
Spritesmith.run({
  src: [].// The array of images to be synthesized. The value is the image path
}, function handleResult (err, result) {
  // If there was an error, throw it
  if (err) {
    throw err;
  }

  // Output Sprite result.image
  // result.coordinates is a map object with an image path and its value is an object containing information about the Sprite map, including horizontal x, vertical y, width and height
  
});
Copy the code

As you can see, this plugin requires us to upload all the image paths we want to compose. Therefore, the implementation idea is as follows:

  1. With re matching, collect statements in the original content that set the background image, such asBackgrount: url (...). ;;
  2. Save the matched image path to an array for Spritesmith to synthesize Sprite image;
  3. Save the full matching statement for subsequent CSS code replacement;
  4. Save the Sprite image to a specified directory, then traverse the image path array, and replace the corresponding background image setting code in the content with Sprite image positioning mode;
  5. Finally, the replaced content is returned.

Code implementation of the test of regular ability, here will not expand the details (mainly my regular is also very general, can barely use ~), at the same time webpack on CSS processing also need to match style-loader and CSS-loader use, interested friends can directly look at the demo: Github.com/youzouzou/w…

After following the README instructions in the project, you can see the fish I caught this week 🐟 :

Two small ICONS have been combined into a single image sprites.png, and when run you can see that the CSS background code has also been replaced:

⚠️ Important note: Yzz-sprite-loader is only for learning the implementation of custom loader. It is not universal. Do not use it in the production environment!!