Webpack Loaders is an important tool for WebPack to implement packaging of non-JS files. This article mainly records my study of loaders workflow.

  1. Loaders are used in webpack.config.js

There are two ways to use loaders for a specific ending file. The first way is to configure the use attribute as an array, which contains the required loader, and the second way is to configure the use attribute as an object, which can be configured with options.

If there is no special configuration, loader will check node_modules to see if it is installed. If you need to execute other loaders, you need to configure the resolveLoader attribute in webpack.conf.js:

// <dir_root>/loader/loader1.js
function loader(params) {
  console.log("loader1~~~~~");
  return params;
}
module.exports = loader;

// <dir_root>/loader/loader2.js
function loader(params) {
  console.log("loader1~~~~~"); 
  return params;
}
module.exports = loader;

// <dir_root>/loader/loader3.js
function loader(params) {
  console.log("loader1~~~~~");
  return params;
}
module.exports = loader;

// <dir_root>/webpack.config.js
module.exports = {
  mode: "development".// JavaScript executes the entry file
  entry: "./src/main.js".output: {
    // Merge all dependent modules into a bundle.js file
    filename: "bundle.js".// Put the output files in the dist directory
    path: path.resolve(__dirname, "./dist"),},// Go to node_modules. If you can't find node_modules, go to loader
  resolveLoader: {
    modules: ["node_modules", path.resolve(__dirname, "loader")]},devtool: "source-map".// watch: true,
  module: {
    rules: [
     / / the first
      {
        test: /\.js$/,
        use: ["loader3"."css-loader2"."less-loader1"],},/ / the second
      {
        test: /\.js$/,
        use: {
          loader: "loader3",}}, {test: /\.js$/,
        use: {
          loader: "loader2",}}, {test: /\.js$/,
        use: {
          loader: "loader1",},},],},};Copy the code
  1. Loader execution sequence

The execution sequence of the Loader is summarized as from right to left and from bottom to top. In the preceding example, the output of the two configuration modes are loader1, loader2, and loader3.

To adjust the sequence, use the Enforce attribute of the Loader. If enforce is set to pre, then post is executed last. In the above example, if the second method is changed to:

{
  test: /\.js$/,
  use: {
    loader: "loader3",},enforce: 'pre'
},
{
  test: /\.js$/,
  use: {
    loader: "loader2",}}, {test: /\.js$/,
  use: {
    loader: "loader1",},enforce: 'post'
},
Copy the code

The output will be loader3,loader2,loader1.

Loaders are classified into four types: Pre, Normal, Post, and Iniline. Next, inline

  1. inline-loader

In addition to configuring loaders in webpack.config.js, you can also use inline loaders to specify the loader to work with when referencing a file

// <dir_root>/loader/inline-loader.js
function loader(params) {
  console.log("inline-loader~~~~~");
  return params;
}
module.exports = loader;

// import file 
      
       / SRC /main.js
      
let b = require("inline-loader! ./b");
console.log("b");

// <dir_root>/src/b.js
module.exports = "b";
Copy the code

After adding enforce to the above configuration, the output is

/ / processing main. Js
loader3
loader2
loader1
/ / processing b.j s
loader3
loader2
inline-loader
loader1
Copy the code

** Execution order: pre Normal inline POST **

If you do not want to execute loader before inline-loader, configure let b = require(“-! inline-loader! ./b”); See the official documentation for details. Configured loaders means configured via webpack.config.js.

pitch

If the loader is set to pitch, execute the pitch first and then the loader itself.

//loader1
loader.pitch = function(remainingRequest, precedingRequest, data) {
  console.log('loader1')};/ / loader2 loader3 classes
Copy the code

Modify loader as above to remove the reference to file B, and the output is:

// Output in pitch
loader1
loader2
loader3
// Output of the loader function
loader3
loader2
loader1
Copy the code

The execution sequence is as follows: Loader3. pitch -> loader2.pitch -> Loader1. pitch -> Obtaining Resources -> Loader1 -> Loader2 -> Loader3

If there is a return value of loader2.pitch, the value is directly skipped to the middle of loader3 in normal

If loader3.pitch has a return value, only loader3-pitch is executed

Note that the last loader to execute, or the first loader in line, must return a string or buffer that the eval function can execute

  1. Try handwriting loader

LoaderContext: loaderContext: loaderContext: loaderContext: loaderContext

Handwritten file-loader is used to load files or images

The basic loader format is as follows:

let loaderUtils = require("loader-utils");
function loader(source) {}module.exports = loader;
Copy the code

The loaderUtils library is a very common processing library that can be omitted but is generally used.

File-loader is used to rename the file to the hash value and file extension, and send the file to the output folder. Since the input of files needs to be binary, set loader. Raw = true.

let loaderUtils = require("loader-utils");
function loader(source) {
	
  // interpolateName retrieves the hash value of a file and interpolates the value to generate a unique filename
  let filename = loaderUtils.interpolateName(this."[hash].[ext]", {
    content: source,
  });
  // this.emitFile is a built-in function in loaderContext that sends files to the output folder
  this.emitFile(filename, source);
  return `module.exports = "${filename}"`;
}
loader.raw = true; // The source code is binary

module.exports = loader;
Copy the code

Write urL-loader, this loader can determine the size of the image file, if the file is too large, use file-loader to send, otherwise the image will be base64 encoding

//webpack.config.js
  {
    test: /\.jpg$/,
    use: {
      loader: "url-loader".options: {
        limit: 200 * 1024,}}},// url-loader 
let loaderUtils = require("loader-utils");
let fileLoader = require("./file-loader");
let fs = require("fs");
let mime = require("mime");
let path = require("path");
function loader(source) {
  let { limit } = loaderUtils.getOptions(this);
  // Determine the size
  if (limit && source.length < limit) {
  	// MIME is used to get the file type
    return `module.exports="data:${mime.getType( source )}; base64,${source.toString("base64")}"`;
  } else {
    // Return file-loader processing
    return fileLoader.call(this, source);
  }
}
loader.raw = true;
module.exports = loader;
Copy the code