Skip to content

loader的配置,执行顺序,和loader中的pitch

这一节看一下loader的配置

  1. loader的调用顺序
  2. 前置loader、 pre
  3. 后置loader、post
  4. 正常loader、normal
  5. 行内loader、直接写在代码里
  6. loader的阻断,pich

loader的执行顺序

前置工作,新建loader1、loader2、loader3

新建loader1

js
// webpack\webpack-loader\loaders\loader1.js
// loader其实就是一个构造函数

function loader(source) { //loader的参数就是源代码
    console.log('loader1 执行了');
    return source
}

module.exports = loader

新建loader2

js
// webpack\webpack-loader\loaders\loader2.js
// loader其实就是一个构造函数

function loader(source) { //loader的参数就是源代码
    console.log('loader2 执行了');
    return source
}

module.exports = loader

新建loader3

js
// webpack\webpack-loader\loaders\loader3.js
// loader其实就是一个构造函数

function loader(source) { //loader的参数就是源代码
    console.log('loader3 执行了');
    return source
}

module.exports = loader

默认的顺序

从下到上,从右到左

从右向左

修改配置文件

js
// webpack\webpack-loader\webpack.config.js

let path = require('path')

module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                use: ['loader3', 'loader2', 'loader1'] // loader从右向左执行
            },
        ]
    },

    resolveLoader: {
        // 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
        modules: ['node_modules', path.resolve(__dirname, 'loaders')]
        /* alias: { // loader的别名
            loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
        } */
    }
}

这时候运行一下,发现是从右向左执行loader,npx webpack

image-20220205171253588

从下向上

修改配置文件

js
// webpack\webpack-loader\webpack.config.js

let path = require('path')

module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },

    module: {
        rules: [
            // 从下向上执行 所以 应该是 loader3 loader2 loader1
            {
                test: /\.js$/,
                use: {
                    loader: 'loader1'
                }
            },
            {
                test: /\.js$/,
                use: {
                    loader: 'loader2'
                }
            },
            {
                test: /\.js$/,
                use: {
                    loader: 'loader3'
                }
            },
        ]
    },

    resolveLoader: {
        // 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
        modules: ['node_modules', path.resolve(__dirname, 'loaders')]
        /* alias: { // loader的别名
            loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
        } */
    }
}

执行看下结果

image-20220205174519162

改变执行顺序,enforce

pre、post

js
// webpack\webpack-loader\webpack.config.js

let path = require('path')

module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },

    module: {
        rules: [
            // 从下向上执行 所以 应该是 3 2 1
            // 但是可以强制改变执行顺序 pre normal post
            // 改变之后就变成了 1 2 3
            {
                test: /\.js$/,
                use: {
                    loader: 'loader1'
                },
                enforce: 'pre', // 最先执行
            },
            {
                test: /\.js$/,
                use: {
                    loader: 'loader2'
                },
            },
            {
                test: /\.js$/,
                use: {
                    loader: 'loader3'
                },
                enforce: 'post', // 最后执行
            },
        ]
    },

    resolveLoader: {
        // 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
        modules: ['node_modules', path.resolve(__dirname, 'loaders')]
        /* alias: { // loader的别名
            loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
        } */
    }
}

执行一下看下结果 npx webpack

image-20220205175112269

另一种loader,行内loader,inline

新建一个loader

js
// webpack\webpack-loader\loaders\inline-loader.js
// loader其实就是一个构造函数

function loader(source) { //loader的参数就是源代码
    console.log('inline-loader 执行了');
    return source
}

module.exports = loader

新建一个模块

js
// webpack\webpack-loader\src\a.js

module.exports = 'aaa'

行内loader的几种写法

index.js中引入这个模块,使用行内loader的方式加载这个模块

使用inline-loader加载这个a.js这个模块
js
// webpack\webpack-loader\src\index.js

console.log('cheny && xzz');

// 使用! 表示将 a.js 这个模块 导给前面的loader
// 加载loader时的顺序 pre、normal、inline、post
require('inline-loader!./a.js')

这时候看一下结果

image-20220205175958588

所以loader的执行顺序为,pre、normal、inline、post

-! 会排除掉pre和normal,只执行inline和post
js
// webpack\webpack-loader\src\index.js

console.log('cheny && xzz');

// 使用! 表示将 a.js 这个模块 导给前面的loader
// 加载loader时的顺序 pre、normal、inline、post
// require('inline-loader!./a.js')

// -! 会排除掉 pre和normal 只执行 inline、post
require('-!inline-loader!./a.js')

image-20220205180423958

! 会排除掉normal,只执行 pre、inline、post
js
// webpack\webpack-loader\src\index.js

console.log('cheny && xzz');

// 使用! 表示将 a.js 这个模块 导给前面的loader
// 加载loader时的顺序 pre、normal、inline、post
// require('inline-loader!./a.js')

// -! 会排除掉 pre和normal 只执行 inline、post
// require('-!inline-loader!./a.js')

// ! 会排除掉 normal 只执行 pre inline、post
require('!inline-loader!./a.js')

image-20220205180619346

!! 会排除掉 pre、normal、post,只执行inline
js
// webpack\webpack-loader\src\index.js

console.log('cheny && xzz');

// 使用! 表示将 a.js 这个模块 导给前面的loader
// 加载loader时的顺序 pre、normal、inline、post
// require('inline-loader!./a.js')

// -! 会排除掉 pre和normal 只执行 inline、post
// require('-!inline-loader!./a.js')

// ! 会排除掉 normal 只执行 pre inline、post
// require('!inline-loader!./a.js')

// !! 会排除掉 pre、normal和post 只执行 inline
require('!!inline-loader!./a.js')

image-20220205180920376

loader的Pitch,有一个阻断的作用

假设loader是 ['loader3','loader2','loader1']

image-20220205181250537

如果Loader的Pitch方法没有返回值时,会先按顺序执行,3,2,1,加载到资源后,再将资源一次传入1,2,3

但是当loader的Pitch有返回值时,就不一样了,比如

image-20220205181459546

loader2有返回值,然后就直接执行前一个loader3,不再继续向下执行了。

例子

其实看一下上面的图就知道结果了,就是当有PItch方法时,loader的返回值就直接是Pitch中的返回值,并不继续向下执行了

修改配置文件

js
// webpack\webpack-loader\webpack.config.js

let path = require('path')

module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                use: ['loader3', 'loader2', 'loader1']
            }
        ]
    },

    resolveLoader: {
        // 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
        modules: ['node_modules', path.resolve(__dirname, 'loaders')]
        /* alias: { // loader的别名
            loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
        } */
    }
}

修改三个loader

loader1

js
// webpack\webpack-loader\loaders\loader1.js
// loader其实就是一个构造函数

function loader(source) { //loader的参数就是源代码
    console.log('loader1 执行了');
    return source
}

loader.pitch = function () {
    return '111'
}

module.exports = loader

loader2

js
// webpack\webpack-loader\loaders\loader2.js
// loader其实就是一个构造函数

function loader(source) { //loader的参数就是源代码
    console.log('loader2 执行了');
    return source
}

loader.pitch = function () {
    return '222'
}

module.exports = loader

loader3

js
// webpack\webpack-loader\loaders\loader3.js
// loader其实就是一个构造函数

function loader(source) { //loader的参数就是源代码
    console.log('loader3 执行了');
    return source
}

loader.pitch = function () {
    return '333'
}

module.exports = loader

修改index.js

js
// webpack\webpack-loader\src\index.js

console.log('cheny && xzz');

配置文件中我们配置的use: ['loader3', 'loader2', 'loader1'],按照正常顺序,会从右向左执行,但是因为loader3的pitch有返回值,所有直接就返回了结果。

image-20220205183408370

最后打包的结果就是loader3中pitch的返回值

image-20220205183446274

假如把loader3的pitch注释掉,loader2和loader2的pitch有返回值,我们看下效果

js
// webpack\webpack-loader\loaders\loader3.js
// loader其实就是一个构造函数

function loader(source) { //loader的参数就是源代码
    console.log('loader3 执行了');
    return source
}

/* loader.pitch = function () {
    return '333'
} */

module.exports = loader

image-20220205183613773

看到loader3是正常执行了,但是因为loader2的pitch有返回值,所有代码最终的打包结果是loader2中的返回值

image-20220205183655492

所以,loader的pitch方法实际就是一个阻断的作用,可以让loader提前返回结果,不再向下执行。

总结

webpack中可以自定义loader来实现解析其他后缀的文件,比如css、less等。

  1. 自己写一个最简单的loader

    js
    // webpack\webpack-loader\loaders\loader1.js
    // loader其实就是一个构造函数
    
    function loader(source) { //loader的参数就是源代码
        console.log('loader1 执行了');
        return source
    }
    module.exports = loader
  2. 在webpack的配置文件中,想要加载自定义loader有三种方式(上一节的内容)

    1. 写loader的时候直接写全局路径
    2. 给loader起别名
    3. 告诉webpack加载loader的时候,如果node_modules没有,就去自己定义loader的目录下找
  3. webpack中的loader执行顺序,默认是从下向上,从右向左,不过可以通过配置enforce来改变执行顺序

    1. 默认啥也不配的loader执行顺序就是默认顺序(从下向上,从右向左),normal
    2. enforce: 'pre',最先执行的loader
    3. enforce: 'post',最后执行的loader
  4. 还有一种loader叫做内联loader,是在代码内部嵌套着

    1. 代码中加载某个模块的时候,直接指定使用某个loader加载

      js
      // 使用! 表示将 a.js 这个模块 导给前面的loader
      // 加载loader时的顺序 pre、normal、inline、post
      require('inline-loader!./a.js')

      如果引入了内联loader,那么loader的执行顺序就变成了

      pre、normal、inline、post

    2. 屏蔽pre和normal,只执行inline和post的内联loader

      js
      // -! 会排除掉 pre和normal 只执行 inline、post
      require('-!inline-loader!./a.js')
    3. 屏蔽normal,只执行pre、inline和post的内联loader

      js
      // ! 会排除掉 normal 只执行 pre inline、post
      require('!inline-loader!./a.js')
    4. 屏蔽所有,只执行inline的内联loader

      js
      // !! 会排除掉 pre、normal和post 只执行 inline
      require('!!inline-loader!./a.js')
  5. webpack中自定义的loader还可以在构造方法中,挂载一个pitch方法,起到一个阻断的作用

    1. 如果配置文件中loader的配置顺序为 use: ['loader3','loader2','loader1']
    2. 默认上面的配置,会从右向左执行loader
    3. 假如loader3中有pitch方法,并且有返回值,所有的loader都不会再执行,直接返回这个返回值
    4. 如果loader3的pitch没有返回值,loader2有返回值,那么会只执行loader3,loader3接收的代码是loader2中pitch的返回值
    5. 其他同理

    image-20220205181250537

    image-20220205181459546

参考

https://www.bilibili.com/video/BV1a4411e7Bz?p=41&spm_id_from=pageDriver