Analysis of the core mechanism of webpack from loader, plugin to egg

Meet the prophecy 2021-05-04 11:05:21
analysis core mechanism webpack loader


Preface

Go deep together Wepcak , Even though Vite Very hot It's really delicious , however Webpack Still dominating the business I don't know later , It is necessary to study deeply , This paper mainly introduces loader / plugin And principle analysis , And those configurations only introduce some common ones , I hope you can learn to read the documents , chinese or english I couldn't understand , I will learn in the future

therefore

A programmer's career is about ten years , Only one tenth of a person's life span . Front end projects are just part of your life and work , And you are all of it , You are his soul . Please put down the long game 、 Fishing at work . Learn more to accompany your project in the most perfect state !

Text

Little egg at the bottom of the article , Please look at it step by step !!

Knowledge point

  • Webpack Pre base
  • Loader Mechanism ( Writing a )
  • Plugin Mechanism
  • Little egg ( Introduction part Webpack Principle analysis )

Webpack Pre base ( To configure )

const path = require('path');
module.exports = {
mode: "production", // "production" | "development" | "none"
// Chosen mode tells webpack to use its built-in optimizations accordingly.
entry: "./app/entry", // string | object | array
// Here the application starts executing 
// webpack Start packing 
output: {
// webpack How to output the results of the relevant options 
path: path.resolve(__dirname, "dist"), // string
// Target path for all output files 
// It has to be an absolute path ( Use Node.js Of path modular )
filename: "bundle.js", // string
// 「 The entrance is divided into blocks (entry chunk)」 File name template for ( The exit is divided into blocks ?)
publicPath: "/assets/", // string
// Output the directory of the parsing file ,url be relative to HTML page 
library: "MyLibrary", // string,
// Export Library (exported library) The name of 
libraryTarget: "umd", // General module definition 
// Export Library (exported library) The type of 
/* Advanced output configuration ( Click to display ) */
},
module: {
// About module configuration 
rules: [
// Module rules ( To configure loader、 Options such as parser )
{
test: /\.jsx?$/,
include: [
path.resolve(__dirname, "app")
],
exclude: [
path.resolve(__dirname, "app/demo-files")
],
// Here's the matching condition , Each option receives a regular expression or string 
// test and include Have the same effect , All must match options 
// exclude It's a must not match option ( Prior to the test and include)
// Best practices :
// - Only in test and File name match Using regular expressions 
// - stay include and exclude Absolute path array is used in 
// - Try to avoid exclude, Prefer to use include
issuer: { test, include, exclude },
// issuer Conditions ( Import source )
enforce: "pre",
enforce: "post",
// Identification applies these rules , Even if the rules cover ( Advanced options )
loader: "babel-loader",
// What should be applied loader, It's relative to context resolution 
// For clarity ,`-loader` Suffix in webpack 2 Is no longer optional 
// see webpack 1 Upgrade guide .
options: {
presets: ["es2015"]
},
// loader Options for 
},
{
test: /\.html$/,
test: "\.html$"
use: [
// Apply multiple loader And options 
"htmllint-loader",
{
loader: "html-loader",
options: {
/* ... */
}
}
]
},
{ oneOf: [ /* rules */ ] },
// Use only one of these nesting rules 
{ rules: [ /* rules */ ] },
// Use all these nesting rules ( Merge available conditions )
{ resource: { and: [ /* Conditions */ ] } },
// Match only if all conditions match 
{ resource: { or: [ /* Conditions */ ] } },
{ resource: [ /* Conditions */ ] },
// Match when any condition matches ( The default is array )
{ resource: { not: /* Conditions */ } }
// Match when conditions don't match 
],
/* Advanced module configuration ( Click to show ) */
},
resolve: {
// Resolve the options requested by the module 
// ( Not applicable to loader analysis )
modules: [
"node_modules",
path.resolve(__dirname, "app")
],
// Directory for finding modules 
extensions: [".js", ".json", ".jsx", ".css"],
// The extension used 
alias: {
// Module alias list 
"module": "new-module",
// names :"module" -> "new-module" and "module/path/file" -> "new-module/path/file"
"only-module$": "new-module",
// names "only-module" -> "new-module", But don't match "only-module/path/file" -> "new-module/path/file"
"module": path.resolve(__dirname, "app/third/module.js"),
// names "module" -> "./app/third/module.js" and "module/file" Can cause errors 
// Module aliases are imported relative to the current context 
},
},
devtool: "source-map", // enum
// By debugging tools in the browser (browser devtools) Add to the message (meta info) Enhanced debugging 
// At the expense of building speed `source-map' It's the most detailed .
devServer: {
proxy: { // proxy URLs to backend development server
'/api': 'http://localhost:3000'
},
contentBase: path.join(__dirname, 'public'), // boolean | string | array, static file location
compress: true, // enable gzip compression
historyApiFallback: true, // true for index.html upon 404, object for multiple paths
hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
https: false, // true for self-signed, object for cert authority
noInfo: true, // only errors & warns on hot reload
// ...
},
plugins: [
// ...
],
// Additional plug-in list 
/* Advanced configuration ( Click to show ) */
}
 Copy code 

It's advanced CV The operation comes from Webpack Official website Just post common configurations ! This is not the subject , Let's go to the writing section

  • entry: entrance ,Webpack The first step in executing the build will be from entry Start , It can be abstracted as input .
  • module: modular , stay Webpack Everything is modular , A module corresponds to a file .Webpack Will be configured from entry Start recursively finding all dependent modules .
  • chunk: Code block , One chunk It is composed of multiple modules , For code merging and splitting .
  • loader: Module converter , It is used to convert the original content of the module into new content as required .
  • plugin: Extension plug-in , stay Webpack A specific time opportunity in the build process broadcasts the corresponding event , Plugins can listen for these events , Do the right thing at the right time .

You have to understand the basic information above , To get to the next step

Loader Mechanism ( Writing a )

Simply speaking loader It's a A function that can get the source code of your entry file , The function itself is the source code .

Implementation of a read picture of loader It's not as hard as you think

  1. Get the buffer
  2. turn base64 / write in buffer Generate pictures

Try it

// webpack.config.js
module: {
rules: [
{
test: /\.(png)|(jpg)|(gif)$/, use: [{
loader: "./loaders/img-loader.js",
options: {
limit: 3000, //3000 Bytes above use picture ,3000 Use within bytes base64
filename: "img-[contenthash:5].[ext]"
}
}]
}
]
}
 Copy code 

Get module configuration items

stay Loader To get the options, adopt loader-utils Of getOptions Method to get :

var loaderUtil = require("loader-utils")
function loader(buffer) { // For buffer
console.log(" File data size :( byte )", buffer.byteLength);
var { limit = 1000, filename = "[contenthash].[ext]" } = loaderUtil.getOptions(this);
if (buffer.byteLength >= limit) {
var content = getFilePath.call(this, buffer, filename);
}
else{
var content = getBase64(buffer)
}
return `module.exports = \`${content}\``;
}
loader.raw = true;
// adopt exports.raw Properties tell Webpack The Loader Do you need binary data 
module.exports = loader;
// obtain base 64 Format 
function getBase64(buffer) {
return "data:image/png;base64," + buffer.toString("base64");
}
// Building pictures Path is generated 
function getFilePath(buffer, name) {
var filename = loaderUtil.interpolateName(this, name, {
content: buffer
});
this.emitFile(filename, buffer);
return filename;
}
 Copy code 

Through the top this.emitFile Write files

Synchronous and asynchronous

Loader There are synchronous and asynchronous , above Loader It's all synchronous Loader, Because their transformation processes are synchronous , Return the result after the conversion . But in some scenarios, the steps of transformation can only be done asynchronously , For example, you need to request through the network to get results , If you use synchronous mode Network request It blocks the entire build , The result is a very slow build .

module.exports = function(source) {
// tell Webpack This transformation is asynchronous ,Loader Will be in callback Call back the result 
var callback = this.async();
someAsyncOperation(source, function(err, result, sourceMaps, ast) {
// adopt callback Returns the result of asynchronous execution 
callback(err, result, sourceMaps, ast);
});
};
 Copy code 

Cache acceleration

In some cases , Some conversion operations require a lot of computation and are very time-consuming , If repeated transformations are performed every time you build , The build will be very slow . So ,Webpack Will cache all by default Loader Processing results of , That is to say, when the files to be processed or other dependent files do not change , It doesn't call the corresponding Loader To perform a transformation operation .

If you want to make Webpack It's not supposed to Loader Processing results of , It can be like this :

module.exports = function(source) {
// Close the Loader Cache function of 
this.cacheable(false);
return source;
};
 Copy code 

got it Webpack The core loader Let's talk about it plugin

Plugin Mechanism

Plugin There's more work to do than Loader more , More complicated , Its essence is a Class class

The basic structure of the plug-in plugins You can use your own prototype method apply To instantiate .apply Only when the plug-in is installed Webpack Of compiler Do it once .apply Method passes in a webpck compiler References to , To access the compiler callback .

class HelloPlugin {
// Get the configuration passed in by the user to the plug-in in in the constructor 
constructor(options) {
// ...
}
// Webpack Would call HelloPlugin Example of apply Method to pass in compiler object 
apply(compiler) {
// stay emit Stage insert hook function , Used to process additional logic at a specific time 
compiler.hooks.emit.tap('HelloPlugin', compilation => {
// After the function flow is completed, you can call Webpack The callback function provided 
});
// If the event is asynchronous , It takes two parameters , The second parameter is the callback function , When the plug-in processes the completion task, it needs to call the callback function to notify Webpack, It's the next process 
compiler.plugin('emit', function(compilation, callback) {
// Support processing logic 
// Execute after processing callback To inform Webpack
// If not implemented callback, The running process will be stuck here without further execution 
callback();
});
}
}
module.exports = HelloPlugin;
 Copy code 

When using plug-ins , Just put an instance of it in Webpack Of Plugins In array configuration :

const HelloPlugin = require('./hello-plugin.js');
module.exports = {
plugins: [new HelloPlugin({ options: true })],
};
 Copy code 

Let's first analyze the following Webpack Plugin How it works :

  1. In the process of reading the configuration, it will be executed first new HelloPlugin(options) Initialize a HelloPlugin Get an example
  2. initialization compiler Call after object HelloPlugin.apply(compiler) Pass in... To the plug-in instance compiler object
  3. The plug-in instance is getting compiler After the object , You can go through compiler.plugin( Event name , Callback function ) Listen to the Webpack Events broadcast , And through compiler Object to operate Webpack

stay apply You can call compiler hook

webpack Of hoosk The hook actually uses tapable Direct registration at different stages of , So let's take the next step

Little egg ( Introduction part Webpack Principle analysis )

Webpack It's essentially a packaged build tool , Let's think about it , What it does for us .

  1. Read webpack.config.js The configuration file , Find the entrance
  2. Get the source code in the entry file Analyze the abstract syntax tree (babel Realization )
  3. The analysis process Static analysis of code execution context and usage , Mark Yes No Tree Shaking
  4. The core loader and plugin Executing functions during read configuration ,tapable Injects hook functions
  5. The final output is in the exit directory in the configuration file

In fact, let's make a brief analysis , It's also very easy to understand

// First define Compiler
class Compiler {
constructor(options) {
// Webpack To configure
const { entry, output } = options;
// entrance
this.entry = entry;
// exit
this.output = output;
// modular
this.modules = [];
}
// Build launch
run() {
// ...
}
// rewrite require function , Output bundle
generate() {
// ...
}
}
 Copy code 

Use @babel/parser and @babel/traverse Two libraries analyze source code abstract syntax tree , Find out the template dependencies used

and tapable The essence is a javascript Small library , Internally, it's a publish subscribe model . similar Node Of EventEmitter.

Webpack In essence, it is a mechanism of event flow , Its workflow is to connect plug-ins in series , And the core of all this is Tapable,Webpack The core of the Compiler And responsible for creating bundles Of Compilation All are Tapable Subclasses of , And the internal life cycle of the instance is also through Tapable The hook class provided by the library implements .

summary

Webpack It is essentially a packaging and building tool of event flow mechanism , A process from reading configuration to parsing syntax tree to registering event stream output file . At its core loader The essence is also a function that can get the source code ,plugin It is a class that can get the whole life cycle of an event ~ At this point you should be right webpack With a deeper understanding , This article skips over many details , Introduce the core knowledge , So you still have to look at the configuration documentation !

The articles

【 Picking up the fallen leaves 】Javascript Execution context 、 precompile

【 Picking up the fallen leaves 】 How does the browser get a complete page ?( Loading )

版权声明
本文为[Meet the prophecy]所创,转载请带上原文链接,感谢
https://qdmana.com/2021/05/20210504110147878n.html

  1. JS: event flow
  2. Front end performance optimization: rearrangement and redrawing
  3. JS - deep and shallow copy
  4. JavaScript异步编程3——Promise的链式使用
  5. JavaScript asynchronous programming 3 -- chain use of promise
  6. Vue.js组件的使用
  7. The use of vue.js component
  8. How to judge whether a linked list has links
  9. Element UI custom theme configuration
  10. Text image parallax effect HTML + CSS + JS
  11. Spring的nohttp宣言:消灭http://
  12. Vue3 intermediate guide - composition API
  13. Analysis of URL
  14. These 10 widgets that every developer must know
  15. Spring's nohttp Manifesto: eliminate http://
  16. Learn more about JS prototypes
  17. Refer to await to JS to write an await error handling
  18. A short article will directly let you understand what the event loop mechanism is
  19. Vue3 uses mitt for component communication
  20. Characteristics and thinking of ES6 symbol
  21. Two way linked list: I'm no longer one-way driving
  22. Vue event and form processing
  23. Reactive TraderCloud实时外汇开源交易平台
  24. Reactive tradercloud real time foreign exchange open source trading platform
  25. Node.js REST API的10个最佳实践
  26. Ten best practices of node.js rest API
  27. Fiddler advanced usage
  28. Process from Vue template to render
  29. Promise up (asynchronous or synchronous)
  30. Principle and implementation of promise
  31. Vs code plug in sharing - run code
  32. Vue practical notes (1) introduction of Ant Design
  33. Vue actual combat notes (2) introduction of element plus
  34. Introduction to webpack
  35. Webpack construction process
  36. Vue notes
  37. The experience and lessons of moving from ruby megalith architecture to go microservice
  38. Using leancloud to add artitalk module to hexo blog
  39. Implementation of chrome request filtering extension
  40. Detailed introduction of beer import declaration elements and label quarantine [import knowledge]
  41. Gallop workflow engine design series 01 process element design
  42. VUE移动端音乐APP学习【十六】:播放器歌词显示开发
  43. Vue Mobile Music App learning [16]: player lyrics display development
  44. jquery cookie
  45. jquery cookie
  46. 体面编码之JavaScript
  47. JavaScript for decent coding
  48. React17 系统精讲 结合TS打造旅游电商平台
  49. React17 system combined with TS to build tourism e-commerce platform
  50. 2021-05-04 hot news
  51. HttpSession对象与Cooike的关系 以及 Cookie对象构造函数问题
  52. gRPC-Web:替代REST的gRPC的Javascript库包
  53. The relationship between httpsession object and cooike and the construction of cookie object
  54. Grpc Web: a JavaScript library package to replace rest grpc
  55. Building reactive rest API with Java - kalpa Senanayake
  56. PDF转HTML工具——用springboot包装pdf2htmlEX命令行工具
  57. Pdf to HTML tool -- Wrapping pdf2htmlex command line tool with springboot
  58. PDF转HTML工具——用springboot包装pdf2htmlEX命令行工具
  59. Pdf to HTML tool -- Wrapping pdf2htmlex command line tool with springboot
  60. Vue.js比jQuery更容易学习