Written in the beginning
10
During the interview in January, an interviewer was talking to meWebpack
I mentioned it when I talked about itLoader
“And asked if he had implemented any of them himselfLoader
. From the useWebpack
Each project starts with a lot of configurationLoader
We all know thatLoader
The function is to process some resource files. For example,sass-loader
Is tosass
File compiled intocss
Files, so the browser can recognize them, andfile-loader
Is to deal with different file resources, such as images, fonts, and so on.- So many different
Loader
, whether to write aLoader
Is it difficult? I wonder if we can make one of our ownLoader
? Just do it.
To understandLoader
Single responsibility
- each
Loader
Both do one thing, and when multiple transformations are required, multiple transformations are requiredLoader
, e.g.sass
File conversion is neededsass-loader
,css-loader
及style-loader
;
// webpack.config.js module Configuration module: {rules: [{test: /\.sass$/, use: ['style-loader',{loader: 'css-loader', options: {...} }, { loader: 'sass-loader', options: {...} }] }, ... ] }Copy the code
Call to order
- We can see from the above example that transformation
sass
The file needs threeLoader
But we are writingLoader
Pay attention to the order in which you write,Loader
The order of execution is fromuse
From the end of the arraysass-loader
到css-loader
And then tostyle-loader
)
Chain calls
- Now that the parsing
sass
The file will use threeLoader
So the next oneLoader
The accepted value is the previous oneLoader
The processed value, executed firstLoader
The acceptance istest
Matching the source file, the whole thing is a chain call process, similar tojQuery
.
modular
- Because we are in
node
To be used in the environmentLoader
So ourLoader
Modular design principles should also be used.
stateless
- Between multiple module conversions, we should not be in
Loader
Is in the reserved state. eachLoader
The runtime should be kept separate from other compiled modules, as well as from the previous onesLoader
Compile results for the same module are kept independent.
in-depthloader
utility
loader-utils
: provides many useful tools that the careful reader should have noticed inLoader
There is one in the configuration ofoptions
Object, and the value of this object can pass throughloader-utils
In the packagegetOptions
To obtain.schema-utils
: you can useschema-utils
Provided tools to obtain for validationoptions
的JSON Schema
Constant to verifyloader options
.
import { getOptions } from 'loader-utils'; import { validateOptions } from 'schema-utils'; const optionSchema = { type: object, properties: { test: { type: string } } } export default function(source) { const options = getOptions(this); validateOptions(optionSchema, options, 'Example Loader'); // Write the logic to convert source... source = source return `export default ${ JSON.stringify(source) }`; };Copy the code
Other results return
-
If we want to add additional content to the result, we can add it through this.callback. There are other apis (Loader API). These are injected by Webpack for easy communication with Loader.
-
This. callback A function that can be called synchronously or asynchronously and can return multiple results. The expected parameters are:
this.callback( err: Error | null, content: string | Buffer, sourceMap? : SourceMap, meta? : any );Copy the code
asynchronousLoader
- In some common cases, your project may need to request some data to process some of your files, for example, if you need to request some dynamic resources to replace some tagged resources, if asynchronous is not suitable, the build will block and increase the build time of the entire project. That’s where we need to use it
Webpack
The injectedAPI
In thethis.async. Example:
module.exports = function(source) { var callback = this.async(); , someAsyncOperation(source, function(err, result, sourceMaps, ast) { callback(err, result, sourceMaps, ast); }); }Copy the code
Other features
- Processing binary
Module. exports = function(source) {// exports.raw === true, Source instanceof Buffer === true; // Loader can also return the type of Buffer // in exports.raw! If == true, the Loader can return a result of type Buffer. }; // The exports.raw property tells Webpack whether the Loader needs binary data module.exports.raw = trueCopy the code
- Get the
target
module.exports = function(source) {
const target = this.target; // 'web', 'node'...
return source;
};
Copy the code
- To obtain
Loader
Configuration of theoptions
- In addition to passing above
loader-utils
getOptions
In addition to the method,Webpack
The injectedthis.query
You can also get the correspondingoptions
, but if not configuredoptions
ifthis.query
It’s just a?
String at the beginning.
- In addition to passing above
- More built-in
API
Please asynchronousWebpack Loader APIView official documents.
Development principles
Common code
- When you have multiple customizations
Loader
If there are two or moreLoader
If you use a piece of the same code, you should separate it out to avoid duplication.
Company relies on
- If you develop
Loader
Simply pack another bag, then you should be inpackage.json
Set this package to peer dependency (peerDependency
). This lets the application developer know which specific version to specify. - For example,
sass-loader
将node-sass
Designated as peer dependency:
"PeerDependencies ": {"node-sass": "^4.10.0"}Copy the code
An absolute path
- Don’t in
Loader
Write absolute paths in the module, because these paths interfere when the project root path changesWebpack
To calculatehash
(themodule
The path of is converted tomodule
A reference to theid
).loader-utils
There is astringifyRequest
Method, which converts an absolute path to a relative path.
Realize the loader
- Through the above introduction, we have a good understanding of
Loader
We have a certain understanding of the following simple implementation of their ownLoader
.
The preparatory work
- In the implementation
Loader
To start, we need to prepare a simple project to test the later implementationLoader
So I useWebpack
A simple project is configured. Note that I added a comment to the file. The configuration is as follows:
- Install content
"Clean-webpack-plugin ": "^3.0.0", // html-webpack-plugin": "^4.5.0", // HTML template, used to insert packed JS files, manual import also ok "path": "^ 0.12.7", / / handle file path "webpack - cli" : "^ 4.2.0", / / also need global installation "webpack" : "^ 5.4.0" / / global installation is neededCopy the code
webpack.config.js
// webpack.config.js const webpack = require('webpack'); const path = require('path'); const htmlWebpackPlugin = require('html-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); Module. exports = {entry: './index.js', mode: 'development', // exports = {entry: './index.js', mode: 'development', // Exports = {entry: './index.js', mode: 'development', // Exports: {publicPath: Path: path.resolve(__dirname, 'dist'), filename: }, module: {rules: [{test: /\.js$/, use: {rules: [{test: /\.js$/, use: ['nodeal-loader'] } ] }, resolveLoader: { modules: [ 'node_modules', path.resolve(__dirname, 'loader'),] }, plugins: [ new CleanWebpackPlugin(), new htmlWebpackPlugin({ template: './index.html', inject: "body" }) ] }Copy the code
- File directory
- This directory is I conveniently built, you can build according to their own habits, different directories remember to modify the corresponding configuration can be.
The simplest loader
- First let’s implement the simplest one
Loader
, since do not do any processing, directly get the content back out.
// nodeal-loader.js
module.exports = function(source) {
return source;
};
Copy the code
- We execute the package command if the following error occurs:
Module not found: Error: Can't resolve 'nodeal-loader' in 'XXX'Copy the code
- You can check what you have written first
Loader
Are the names of the - Look at your
webpack.config.js
Whether the following configuration is available and whether the road strength is correct
ResolveLoader: {modules: ['node_modules', path.resolve(__dirname, 'loader')]Copy the code
- Will you write
Loader
Release toNpm
On, and then like anything elseLoader
Download it from the package management tool.Publish your own NPM package - use
Npm link
-
Npm link is used to develop and debug local Npm modules. It can link the source code of a local module under development to the node_modules directory of the project without releasing the module, so that the project can directly use the local Npm module.
-
Because it is implemented by soft link, the Npm module code is edited locally, and the edited code can be used in the project.
-
The steps to complete Npm Link are as follows:
- Make sure you are developing locally
Npm
Module (that is, under developmentLoader
)package.json
The configuration is correct. - Execute in the root directory of the local Npm module
npm link
To register local modules globally. - Execute in the project root directory
npm link loader-name
The first2
Step registration to the global localNpm
The module links to the project’snode_moduels
Below, among themloader-name
Refers to the first1
In the steppackage.json
The module name configured in the file.
- Make sure you are developing locally
-
After linking the Loader to the project you can use the local Loader as if it were a real Npm module.
-
To get rid ofconsole
的 loader
- what
Loader
Without doing anything, let’s implement a deletejs
In the fileconsole
Many plug-ins already do this in daily development (for example:uglifyjs-webpack-plugin
), this is just an example. - Modify the
Loader
As follows:
Module. exports = function(source) {source = source.replace(/console\.log (.*? \); ? /, '') this.callback(null, source) return source; };Copy the code
- in
index.js
Add the following code to the
Alert (' test '); console.log('detanx');Copy the code
- We execute the package command if the following error occurs:
- Check to see if there are
Loader
The other is added to the configuration ofLoader
This could be something elseLoader
The returnedsource
Type noreplace
Method. You can remove other loaders first. - Open it in a browser
dist
The followinghtml
Documents, we seealert
The content is already displayed, but nothing is printed on the console, and we haven’t added any other plug-ins orloader
This proves that what we wroteLoader
To take effect.
- Let’s look at the packaged files,
alert
Was preserved,console
It’s removed.
Loader
extension
- Dispose of the above implementation
console
In addition, we can also implement other functions, such as removealert
, replace implicit conversions with strict equality or inequality (! =
,= =
Replace with! = =
,= = =
), replace the resource link withrequire
The way of introduction and so on.
conclusion
- For modular,
Loader
Have a better understanding of; - Resources that require special processing are not readily available
Loader
We can try to do it ourselves; - right
Webpack
Have a further understanding of the configuration and packaging process; - Review how to publish
Npm
Package flow.