Before we begin, let’s take a look at loader. The following is a description of Loader from WebPack Chinese
A loader is simply a JavaScript module exported as a function. The Loader Runner calls this function and passes in the result or resource file generated by the previous loader. The function’s this context will be populated by Webpack, and the Loader Runner has some useful methods to change the Loader to make asynchronous calls, or to get query parameters.
Loader parameters and return values (also extracted fromWebpack Chinese website
)
The first loader passes in only one argument: the contents of the resource file. Compiler needs to get the processing results generated by the last loader. The result should be a String or Buffer (converted to a String) that represents the JavaScript source code for the module. An optional SourceMap result (formatted as a JSON object) can also be passed.
The classification of the loader
Loaders are classified into synchronous and asynchronous loaders. Loader is essentially a function. Therefore, the difference between the two loaders can be understood as only the return value is different (just for easy analogy). The actual operation is not simply two return values.
Synchronous loader
Synchronizing the Loader is relatively simple. Either a return or a call to this.callback can return the converted content synchronously.
- use
return
It’s kind of intuitive, just a normal function that returns a value when it’s done. Such as:
function loader(source) {
// do anything
return source;
}
Copy the code
- use
this.callback
this.callback
The function argument type of
// The last two parameters are non-mandatory
this.callback(
err: Error | null.content: string | Buffer, sourceMap? : SourceMap, meta? : any );Copy the code
This is more flexible than the return method and can return multiple values. Such as:
function loader(source) {
// do anything
this.callback(null, source, map, meta);
}
Copy the code
Note: After a callback is called in a function, the return value of the return is ignored.
Asynchronous loader
There is only one processing method for an asynchronous loader. For asynchronous loaders, use this.async to get the callback function. The callback function is the same as the callback function in the sync loader.
function loader (source) {
console.log('--- loader begin ----');
console.log(source);
console.log('--- loader end ----\n');
const callback = this.async();
// do anything
callback(null, source);
}
module.exports = loader;
Copy the code
Note some special cases:
- Call from a function
this.async
Later,return
Is ignored. - Call from a function
this.async
After, call againthis.callback
, will be the currentloader
As aSynchronous loader
To deal with. - Call from a function
this.async
After, call againthis.callback
And immediately callCallback returned by this.async
. The program will report an error.
At this point, we are ready to start writing a simple Loader. Let’s start by writing a few loaders
banner-loader
The loader adds a line comment to each file header, identifying the author. Such as:
/**
** @author laibao101
** @time 2019-06-04 19:57:20
**/
// source code
Copy the code
Function analysis: This loader does not have any asynchronous operation, so we can use the synchronous loader. Note, for the moment write dead, through the parameter configuration, and then do.
function loader (source) {
const time = new Date().toLocaleString()
return `
/**
** @author laibao101
** @time ${time}* * /${source}
`
}
Copy the code
Using the template string, write the comment code and return it. This completes a simple loader.
Asynchronous banner – loader
This loader is written to write an asynchronous loader. The function reads a template from a file and adds a banner to the file
// banner-loader
const path = require('path');
const fs = require('fs');
const baseUrl = process.cwd();
const configTextPath = "bannerConfig.txt";
// Concatenate the complete configuration file path
const fullConfigPath = path.resolve(baseUrl, configTextPath);
// Get the data according to the placeholder in the template
const configItemMap = {
author: "laibao101".time: new Date().toLocaleString()
};
// Matches placeholders
const reg = /{(\w+)}/gi;
function loader (source) {
const callback = this.async();
fs.readFile(fullConfigPath, (err, data) => {
if (err) {
// If reading the file fails, an error is returned
callback(err);
}
// Get the file contents
const template = data.toString();
// According to the template, modify the placeholder data to complete the banner
const banner = template.replace(reg, (match, key) => {
return configItemMap[key] || key;
});
// Concatenate the return value
const ret = `
${banner}
${source}
`
callback(null, ret);
});
}
module.exports = loader;
// bannerConfig.txt
/**
** @author {author}
** @time {time}
**/
Copy the code
The synchronization banner-loader parameter can be configured
The banner-loader parameters are set internally by loader. If you need to get parameters from webpack.config.js, you can use the this.query parameter provided by webpack to get the options parameter in the Loader configuration. This is used frequently in Loaders.
For example: Babel – loader
module: {
rules: [{test: /\.m? js$/.exclude: /(node_modules|bower_components)/.use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env'}}}]}Copy the code
url-loader
module.exports = {
module: {
rules: [{test: /\.(png|jpg|gif)$/i.use: [{loader: 'url-loader'.options: {
limit: 8192}}]}}Copy the code
So, we modify the banner-loader above to get the parameter from the Loader configuration
// banner-loader
function loader (source) {
const time = new Date().toLocaleTimeString();
const { author = ' ' } = this.query || {}
return `
/**
** @author ${author}
** @time ${time}* * /${source}
`
}
module.exports = loader;
// webpack.config.js{... options: {author: "laibao101"}}Copy the code
Thus, we can implement the Loader whose parameters are retrieved from the configuration file.
The next article
This section describes raw-loader and PITch-loader. And write a demo