vuecli3项目中webpack4配置(六)自己编写一个loader

1,077 阅读2分钟

我们在配置webpack时,loader是必不可少了,我们可以借助babel-loader将es6的语法转义成浏览器能识别的es5的代码,借助sass-loader将scss转成css。那么我们自己是否可以自定义一些loader来包装代码呢,答案是肯定的,下面通过两个小例子使大家了解loader的基本用法。

1. 同步的loader

项目结构:

webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- /src
  |- index.js
+ |- diyLoader.js
|- /node_modules

index.js

console.log("Hello Webpack")

diyLoader.js

module.exports = function(source) {
    return source.replace(/Webpack/g, "Loader");
}

这就是一个最简单的loader,导出的是一个函数,函数的参数为源文件的内容或前一个loader的处理结果,函数的this包含了许多由Webpack和loader运行程序填充的方法或属性。函数的返回值应该是处理之后的字符串或缓冲区。

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
	mode: 'development',
	entry: {
		index: './src/index.js'
	},
	output: {
	    filename: 'bundle.js',
	    chunkFilename: '[name].bundle.js',
	    path: path.resolve(__dirname, 'dist')
	},
	plugins: [
		new CleanWebpackPlugin(),
		new HtmlWebpackPlugin()
	],
	module: {
		rules: [
		    {
		    	test: /\.js$/,
		    	use: path.resolve(__dirname, './src/diyLoader.js')
		    }
		]
	}
}

module.rules的配置说明当匹配到一个js文件时,就用src目录下的diyLoader.js的函数对该js文件做处理。

一个同步的loader就完成了,打包发现在控制台输出的内容为 "Hello Loader",而非 "Hello Webpack"。说明loader生效了。

还可以在loader中传递参数:

module: {
    rules: [{
        test: /\.js$/,
        use: [{
            loader: path.resolve(__dirname, './src/diyLoader.js'),
            options: {
                name: 'Loader'
            }
        }]
    }]
}

diyLoader.js做相应的修改:

module.exports = function(source) {
    return source.replace(/Webpack/g, this.query.name);
}

this.query包含了options对象的内容。this下包含了许多属性和方法,上面的return只返回了单个结果,当我们需要返回多个结果的时候,可以用this.callback

this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);

2. 异步的loader

一个loader一定要有返回值的,假如loader中是一个异步函数,那么返回值需要等异步方法执行完才能返回。所以就需要借助this.async来告诉webpack应等待异步结果,它返回this.callback()。具体实现修改diyLoader.js:

module.exports = function(source) {
    const callback = this.async()
    setTimeout(() => {
        const result = source.replace(/webpack/g, this.query.name);
        callback(null, result);
    }, 1000)
}

这里的callback和this.callback是一样的。

不管是同步和异步的loader,它的作用都是在不修改源代码的情况下,对源代码进行包装,并返回包装之后的结果。如果你觉得看明白了,那么来看个更高级的用法吧 嘿,不要给async函数写那么多try/catch了