preface

Webpack is written by Node, so it can only recognize JS files. So today we will explore how loader in Webpack implements file recognition and conversion

To understand

Through a simple configuration, to understand, the most classic is csS-loader because Webpack can only recognize JS files, what about CSS files?

// A simple WebPack configuration
const path = require('path');

module.exports = {
  entry: './main.js'.output: {
    filename: 'bundle[hash:6].js'.path: path.resolve(__dirname, './dist'),},module: { // Where the loader is mainly used
    rules: [
        // To configure the loader for packing CSS files, use defines the loader to be used, and pay attention to the sequence
        // style-loader must be placed before CSS-loader because loader is executed from right to left
        { 
            test: /\.css$/.// Matches files with a.css suffix
            use: ['style-loader'.'css-loader'}]}};Copy the code

Responsibility and Logic

Loader has a single responsibility and only needs to complete one identification and transformation. If a source file needs to be converted for many times to achieve the desired effect, it will take a long time to convert it through multiple Loaders. When multiple Loaders are called to convert a file, each Loader will execute it in chained order from right to left. The results processed by the previous Loader are passed to the next Loader for further processing, and the last Loader returns the processed results to Webpack

basis

Loader is a file processing module written by Node. In essence, Loader is a function

function LoadrFunc (source) {
  // Source is the parameter, which is the content of the file entity to process
  
  // do something 
  
  // The 'Loader' does not perform any conversion
  return source;
};
module.exports = LoadrFunc

Copy the code

Take a parameter source, which is the source of the file to be converted, convert it, and return it to Webpack

The advanced

After looking at how loader is implemented, we also know that in everyday use, we might write es6 to ES5

{
    test:/\.js$/.// Matches files with the.js suffix
    use:{ // This is written as an object
        loader: 'babel-loader'.options: {
          presets: ['@babel/preset-env'].// Convert es6 to ES5}}}Copy the code

Here use ES6 conversion ES5 example to demonstrate, loader options is how to implement? Loader-utils is a class package for loader, which contains some commonly used methods of Loader

// Import the loader-utils package
const loaderUtils = require('loader-utils');

function LoadrFunc (source) {
  // Source is the parameter, which is the content of the file entity to process
  
  // Get the options passed by the user to the current Loader
  const options = loaderUtils.getOptions(this);
  
  // do something 
  
  // The 'Loader' does not perform any conversion
  return source;
};

module.exports = LoadrFunc

Copy the code

How to implement a Loader

ES6 conversion ES5 loader to example evolution, see how to implement a similar loader

First, install the Loader-utils toolkit

npm install loader-utils -D
Copy the code

Using the relevant Configuration

// A simple WebPack configuration
const path = require('path');

module.exports = {
  entry: './main.js'.output: {
    filename: 'bundle[hash:6].js'.path: path.resolve(__dirname, './dist'),},resolveLoader: {// The default is node_modules. If you can't find it, go to customLoaderDir
   modules: ["node_modules",path.resolve(__dirname,"customLoaderDir")].// Alias mode, absolute path
   / / alias: {
       // "es6ToEs5-loader":path.resolve(__dirname,"customLoaderDir","es6ToEs5-loader.js")
   // }
   
  },
  module: { // Where the loader is mainly used
    rules: [{test:/\.js$/.// Matches files with the.js suffix
            use:{ // This is written as an object
                loader: 'babel-loader'.options: {
                  presets: ['@babel/preset-env'].// Convert es6 to ES5}}}]}};Copy the code

Here I will write es6 conversion ES5 loader, named es6toES5-loader, using the structure of the conventional loader

Node_modules (customLoaderDir, customLoaderDir, customLoaderDir, customLoaderDir); The loader name is the name of the custom Loader JS file

// create es6toes5-loader.js in customLoaderDir

// Import the loader-utils package
let loaderUtils = require('loader-utils');
// Introduce the core of Babel
let babel = require("@babel/core")

function LoadrFunc (source) {
  // Source is the parameter, which is the content of the file entity to process
  
  // Get the options passed by the user to the current Loader
  const options = loaderUtils.getOptions(this);
  
  // This is asynchronous, so we need to call the asynchronous API async. Here we can print this to see what other methods and properties are available
  let callback = this.async()
  
  // Through the Babel core quasi - substitution syntaxbabel.transform(source,{ ... options,sourceMap:true.// This can also be done in loader configuration options
      fileNmae: this.resourcePath.split("/").pop() // Give the map file a nickname
  },function (err,result) {
         The callback function takes two arguments, a failure cause and a result
         // result.code Specifies the converted code
         // result.map is the source of the mapping
         callback(err,result.code,result.map)
  })
  
  // In this case, the return function has no use, because the above is a callback function, obviously asynchronous processing, so the core of the callback function
  // return source;
};

module.exports = LoadrFunc

Copy the code

Ok, through a simple example, we can clearly understand how loader is implemented in Webpack. In the next chapter, I will share the principle of Plugin plug-in in Webpack

Small encouragement, great growth, welcome to praise