1. Loader development scenario

When we need to process our files in the project, but the existing loader cannot meet the requirements, it is more important to develop a loader by ourselves. For example, when we are developing a component library, we want to use Markdown to compose the feature description pages of the website. In our markdown file, we need to create a new custom tag for internationalization. For example, we must use a < CHN > tag, but this tag is not supported by the existing Markdown loader, so we need to add a new loader to parse the tag.

2. Depth of discussion in this paper

This article is not an introduction to the source code implementation of WebPack Loader, but focuses on how we develop a working loader. So let’s start with some analysis of the Loader.

3. Classification of Loaders in Webpack

Loaders in Webpack are classified into the following categories:

  • The pre command is executed preferentially
  • Post is postpended, and is executed last
  • Normal ordinary
  • The inline inline

The execution sequence of the Loader is involved. Such as:

module: {
    rules: [{test: /.less$/,
        use: 'style-loader'
      },
     {
        test: /.less$/,
        use: 'css-loader'
      },
     {
        test: /.less$/,
        use: 'less-loader'}},Copy the code

This is the loader we use most often, and the order of execution is actually from bottom up (or right to left). So the order of execution is:

less-loader -> css-loader -> style-loader

If we set Enforce, the custom execution order is clear, for example:

module: {
    rules: [{test: /.less$/,
        use: 'less-loader'.enforce: 'pre'
      },
     {
        test: /.less$/,
        use: 'css-loader'
      },
     {
        test: /.less$/,
        use: 'style-loader'.enforce: 'post'}},Copy the code

To manually determine the order of execution, write as above:

less-loader -> css-loader -> style-loader

normalWe refer to Loader in rules normally

Inline is another way to write it:

style-loader! css-loader! stylus-loaderCopy the code

Of course, the current use of inline is limited because many times you pass various parameters to the Loader.

Good, basic usage and not commonly used enforce finished, below, with normal, to focus on

4. Normal Loader and Pitching Loader

4.1 General Execution structure of Loader

The overall structure of the Loader is to export a function to the WebPack runtime(which I abstract myself).

4.2 Development mode and Execution of Normal Loader

Let’s start with the basics:

// vue-pre-loader.js

const vuePreLoader = (content, map, meta) = > {
    console.log('Obtained by vue PreLoader')
    console.log('Vue PreLoader logic execution');
    return content;
}
module.exports = vuePreLoader;
Copy the code

Use in Webpack:

const {resolve} = require('path');
/ /...
rules: [
    {
        test: /\.vue$/,
        use: [
                {
                    loader: 'vue-loader'
                },
                {
                    loader: resolve(__dirname, './loader/vue-pre-loader.js'}]},]Copy the code

When compiling the.vue file, we will execute our own loader first and print out the content. The content is a string, and we can do a second processing of the data.

Ok, now let’s develop another loader for vue-loader after execution.

// vue-after-loader.js

const vueAfterLoader = (content, map, meta) = > {
    // Remove the HTML comment from the content
    const regExp = / <! --((\s|\r|\n)*((? ! -- >).) *\s|\r|\n)*-->/;
    if(regExp.test(content)) {
        content = content.replace(content.match(regExp)[0].' ');
    }
    console.log('vueAfterLoader logic execution ');
    return content;
}

module.exports = vueAfterLoader;

Copy the code

Also, update the configuration in WebPack:

const {resolve} = require('path');
/ /...
rules: [
    {
        test: /\.vue$/,
        use: [
                {
                    loader: resolve(__dirname, './loader/vue-after-loader.js')}, {loader: 'vue-loader'
                },
                {
                    loader: resolve(__dirname, './loader/vue-pre-loader.js'}]},]Copy the code

Note the following two points when reexecuting:

  • The content of the Content can be processed, processed into what we want
  • Execution sequence: Run vue-pre-loader and then vue-arger-loader

4.3 What is a Pitching Loader

This concept is not used in many of the projects I work on, so it needs to be studied. After research, it was discovered that this pitching was actually related to circuit breakers.

Try adding this pitch first

// vue-pre-loader.js

const vuePreLoader = (content, map, meta) = > {
    console.log('Vue PreLoader logic execution');
    return content;
}
vuePreLoader.pitch = function(remainingRequest, precedingRequest, data) {
    console.log('Execute vuePreLoader pitching');
}

module.exports = vuePreLoader;


// vue-after-loader.js

const vueAfterLoader = (content, map, meta) = > {
    // Remove the HTML comment from the content
    const regExp = / <! --((\s|\r|\n)*((? ! -- >).) *\s|\r|\n)*-->/;
    if(regExp.test(content)) {
        content = content.replace(content.match(regExp)[0].' ');
    }
    console.log('vueAfterLoader logic execution ');
    return content;
}

vueAfterLoader.pitch = function(remainingRequest, precedingRequest, data) {
    console.log('Execute vueAfterLoader pitching');
}

module.exports = vueAfterLoader;

Copy the code

Again, we find that the order of execution is as follows:

Execute vueAfterLoader pitching -> Execute vuePreLoader pitching -> Execute Vue PreLoader logic -> execute vueAfterLoader logic

In other words:The execution of pitch is from front to back. After the execution of pitch, the loader is executed from back to front

So what is this pitching application? One important function is the aforementioned circuit breaker. When pitch returns non-undefined, the previous process is blocked. For example, I do a return operation in vue-pre-loader.js

vuePreLoader.pitch = function(remainingRequest, precedingRequest, data) {
    console.log('Execute vuePreLoader pitching');
    return 'Circuit breaker';
}

Copy the code

Then look at the execution result:

Execute vueAfterLoader pitching -> Execute vuePreLoader pitching -> execute vueAfterLoader logic

See? It fuses the following process, so the vue PreLoader logic does not execute and returns to vue-after-loader

The overall process looks like this:

It’s not a very good drawing, but try to show the relationship between them. I hope to inspire you a little bit.

Above is all the content I want to express today, while sharing with you, I also have a deeper understanding of some of the principles, I hope to be useful to you. If you like it, don’t forget to give it a thumbs up