Webpack Loader API
Loader is an important concept in Webpack that can help us do what we want when loading certain types of files, such as automatically adding try catch to all JavaScript functions.
The so-called loader is just a JavaScript module exported as a function.loader runner The function will be called, and then the result of the previous loader or resource file will be passed in. The’this’ context of the function will be filled by webpack, and loader runner There are some useful methods to change the loader to be called asynchronously, or to obtain query parameters.
The first loader has only one input parameter: the content of the resource file. The compiler needs to get the processing result produced by the last loader. This processing result should be’String ‘or’Buffer’ (converted to a string), representing the JavaScript source code of the module. In addition, an optional SourceMap result (formatted as a JSON object) can be passed.
If it is a single processing result, it can be returned directly in ** Synchronization Mode **. If there are multiple processing results, 'this.callback () ’ must be called. In ** Asynchronous Mode **, 'this.async () ’ must be called to indicate loader runner Waiting for the asynchronous result, it will return’this.callback () ‘callback function, and then the loader must return’undefined’ and call the callback function.
The simplest loader
Synchronization
Either’return ‘or’this.callback’ can return the converted’content 'content synchronously:
sync-loader.js
1 | module.exports = function(content, map, meta) { |
The this.callback method is more flexible because it allows multiple parameters to be passed, not just content.
The content here is the incoming source code. someSyncOperation is our custom method for processing the source code, and finally returns the processing result through return.
sync-loader-with-multiple-results.js
1 | module.exports = function(content, map, meta) { |
The map here is actually scourceMap.
Asynchronous
For asynchronous loaders, use this.async
To get the callback function:
async-loader.js
1 | module.exports = function(content, map, meta) { |
async-loader-with-multiple-results.js
1 | module.exports = function(content, map, meta) { |
This. aysnc told loader-runner The loader will call back asynchronously. Returns’this.callback '. So its parameters are the same as this.callback.
Loader
Here only the commonly used methods and parameters are listed, explained and added some notes. More configuration can be seen directly文档
The loader context represents some method or property that can be accessed within the loader using’this’.
Suppose we request to load another module like this: In ‘/abc/file.js’:
1 | require('./loader1?xyz!loader2!./resource?rrr'); |
The above import method is a method provided by webpack. This import method specifies which loader is used to load the final file. The loader is specified before the exclamation mark. This method can override the configuration in webpack.config.
You can see the specifics.loader 概念文档
this.query`
- If this loader is configured
options
Object, ‘this.query’ points to this option object. - If there is no’options’ in the loader and it is called with query string as an argument, ‘this.query’ is a string starting with ‘?’.
In the official doc, we are prompted to use the getOptions method provided by loader-utils to get options, because if the value in options is not a simple string, there will occasionally be some problems. The specific usage method is:
1 | //webpack config |
1 | // loader.js |
this.callback
A function that returns multiple results and can be called synchronously or asynchronously. The expected parameters are:
1 | this.callback( |
- The first argument must be’Error ‘or’null’
- The second parameter is a’string 'or
Buffer
。
Optional: The third parameter must be one that can be used by这个模块Parsed source map. - Optional: The fourth option, which will be ignored by webpack, can be anything (such as some metadata).
Syntax Tree (abstract)
If this function is called, you should return undefined to avoid ambiguous loader results.
this.async
Tell loader-runner The loader will call back asynchronously. Returns’this.callback '.
this.version
** The version number of the loader API. ** Currently ‘2’. This has some use for backward compatibility. With this version number, you can write different logic for breaking changes between different versions, or downgrade.
this.context
** Directory where the module is located. ** Can be used as a context for resolving paths to other modules.
In our example: this attribute is’/abc ‘because’resource.js’ is in this directory
this.rootContext
Starting from webpack 4, the original’this.options.context ‘has been improved to’this.rootContext’.
this.request
The parsed request string.
In our example:
"/abc/loader1.js?xyz!/abc/node_modules/loader2/index.js!/abc/resource.js?rrr"
How did this result come about?
First of all, because our resource.js, loader1, loader2 root directory abc directory, so the front will add “abc/”, and loader2 in front of no relative path, so it is considered to be node_modules module, will add a “node_modules/”
Advanced Loader
“Raw”
By default, the resource file will be converted to a UTF-8 string and then passed to the loader. By setting’raw ‘, the loader can receive the original’Buffer’. Each loader can pass its processing results as’String ‘or’Buffer’. Complier will convert them to and from loaders.
raw-loader.js
1 | module.exports = function(content) { |
Crossed
The loader ** is always ** called from right to left. In some cases, the loader only cares about the ** Metadata (metadata) ** after the request and ignores the result of the previous loader. ** The’pitch 'method on the loader is called from left to right before the actual (right-to-left) execution of the loader **. For the following use
Configuration:
1 | module.exports = { |
These steps will occur:
1 | |- a-loader `pitch` |
So why can loaders take advantage of the “pitching” phase?
First, the’data ‘passed to the’pitch’ method is also exposed under the 'this.data 'during execution and can be used to capture and share previous information during looping.
1 | module.exports = function(content) { |
Second, if a loader gives a result in the’pitch ‘method, then the process will turn around and skip the remaining loaders. In our example above, if the’pitch’ method of’b-loader 'returned something:
1 | module.exports = function(content) { |
The above steps will be shortened to:
1 | |- a-loader `pitch` |