Webpack 5 核心機制詳解與打包性能優化實踐

在這里插入圖片描述

🤖 作者簡介:水煮白菜王,一個web開發工程師 👻
👀 文章專欄: 前端專欄 ,記錄一下平時在博客寫作中,總結出的一些開發技巧和知識歸納總結?。
感謝支持💕💕💕

目錄

    • Webpack 5 相較于 Webpack 4 的主要改進
    • 安裝
    • 生命周期
      • Compiler Hooks
      • use hooks
    • webpack中的loader(轉換器)
      • 工作原理
      • 常用loader
      • 自定義loader
    • webpack中的plugins(插件)
      • 工作原理
      • 自定義plugins
    • 打包過程
      • 加速webpack打包速度和減小打包體積的優化
      • webpack配置
      • webpack配置拆分
        • webpack.config.common.js文件公共環境配置
        • webpack.config.dev.js文件開發環境配置 npx webpack -c ./webpack.config.dev.js
        • webpack.config.prod.js文件生產環境配置 npx webpack -c ./webpack.config.prod.js
        • webpack.config.js 運行:webpack -c ./webpack.config.js --env development
      • 封裝webpack自定義插件
    • 如果你覺得這篇文章對你有幫助,請點贊 👍、收藏 👏 并關注我!👀

Webpack 5 相較于 Webpack 4 的主要改進

  1. 性能改進:webpack5在構建速度和打包體積方面進行了一些優化。它引入了持久緩存,可以減少構建時間。
    此外,webpack5還引入了更好的樹搖(tree shaking)算法,可以更好地優化打包體積。
  2. 模塊聯邦(Module Federation)新增特性:這是webpack5中最重要的新功能之一。模塊聯邦允許不同的應用程序共享模塊,從而實現更好的代碼復用和拆分。這對于構建大型的微服務架構非常有用。
new ModuleFederationPlugin({name: 'myApp',filename: 'remoteEntry.js',remotes: {},exposes: {'./Button': './src/Button',},shared: { react: { singleton: true } },
});
  1. 支持WebAssembly:webpack5對WebAssembly提供了更好的支持。它可以直接導入和導出WebAssembly模塊,并且可以通過配置進行優化。
  2. 緩存策略增強:webpack5引入了更好的緩存策略,可以更好地利用瀏覽器緩存。這可以減少用戶在更新應用程序時需要下載的文件數量。
  3. Tree Shaking 改進:webpack5引入了更好的Tree Shaking算法,可以更好地識別和刪除未使用的代碼。這可以進一步減少打包體積。
  4. 改進的持久緩存:webpack5引入了更好的持久緩存策略,可以更好地利用緩存。這可以減少構建時間。
特性Webpack 5 改進
性能改進Webpack 5 在構建速度和打包體積方面進行了優化。引入了持久緩存機制,顯著減少重復構建時間。
模塊聯邦(Module Federation)引入模塊聯邦功能,允許不同應用之間共享模塊,提升代碼復用能力,適用于微服務架構和微前端項目。
WebAssembly 支持增強原生支持 WebAssembly 模塊的導入與導出,無需額外 loader,支持異步加載、Tree Shaking 和 Code Splitting。
緩存策略增強引入更智能的瀏覽器緩存策略(如 deterministic ID 算法),提升長期緩存利用率,減少用戶更新時的資源下載量。
Tree Shaking 改進使用更高級的 Tree Shaking 算法,支持導出級(export-level)和嵌套級的未使用代碼識別與刪除,進一步減小打包體積。
持久緩存改進引入基于文件系統的持久化緩存(cache: { type: 'filesystem' }),大幅提升開發階段的增量構建速度。

其中最顯著的變化是 webpack5 引入了持久化緩存機制,使得構建速度大幅提升。此外,webpack5 改進了長期緩存策略,支持更好的 Tree Shaking 和代碼分割功能

安裝

npm init -y     // 初始化package.json
npm install webpack webpack-cli --save-devnpx webpack --watch     // 監聽文件修改
npx webpack-dev-server  // 以server的方式啟動項目,不會打包物理文件,而是輸出到內存

生命周期

Compiler Hooks

beforeRun:在webpack開始運行之前調用,執行全局初始化邏輯,例如異步加載配置、插件依賴項等。

run:在webpack開始運行時調用,可以在此做一些全局處理 ,一些初始化操作。

beforeCompile:在webpack開始編譯之前調用,修改編譯參數、注入額外上下文。

compile:在webpack開始編譯時調用,初始化與本次編譯相關的狀態。

make:在webpack開始構建編譯器時調用,啟動模塊解析、構建等操作,可在此階段添加自定義入口點或資源。

afterCompile:在webpack完成編譯之后調用,獲取完整的模塊依賴圖,進行最終分析或優化。

emit:在webpack生成最終的資源之前調用,添加、修改或刪除最終輸出的資源(如生成額外文件)。

afterEmit:在webpack生成最終的資源之后調用,做一些清理工作或觸發后續流程。

done:在webpack完成構建之后調用,清理臨時資源、輸出構建信息、發送通知。

Hook 名稱觸發時機使用場景
beforeRun在 Compiler 開始運行前觸發(如執行 webpack()可用于初始化插件或設置運行時配置
run在 Compiler 開始運行時觸發(異步)類似入口點,可以在此做一些全局處理 ,一些初始化操作
beforeCompile在編譯開始前觸發準備編譯所需的數據或資源
compile在編譯開始時觸發初始化編譯過程,執行一些初始化操作,例如創建 Compilation 實例
thisCompilation在 Compilation 創建之前觸發用于監聽后續的 Compilation 生命周期
compilation在 Compilation 被創建后觸發插件可在此接入 Compilation 生命周期
make在模塊解析開始時觸發可以添加/修改模塊依賴關系
afterCompile在編譯完成后觸發對編譯結果做最后調整或校驗
emit在生成最終輸出資源之前觸發可以修改輸出內容,如添加額外文件
afterEmit在輸出資源之后觸發清理 emit 階段使用的臨時數據
done整個構建流程完成之后觸發執行清理工作或輸出構建耗時信息
failed構建失敗時觸發處理異常、記錄錯誤日志

use hooks

module.exports = {// ...plugins: [{apply: (compiler) => {compiler.hooks.beforeRun.tap('MyPlugin', () => {console.log('Before run');});compiler.hooks.done.tap('MyPlugin', () => {console.log('Build done');});}}]
};//在這個示例中,我們定義了一個自定義插件,并利用beforeRun和done兩個生命周期鉤子函數。在這些鉤子函數中,我們可以實現自定義行為,如輸出日志信息。

webpack中的loader(轉換器)

工作原理

webpack loader 在 webpack 構建過程中的生命周期中的工作主要分為以下幾個階段:

  • 解析階段:webpack 會根據配置文件中的入口文件,遞歸解析所有的依賴模塊。在這個階段,webpack 會根據文件的后綴名來確定使用哪個 loader 來處理該文件。

  • 編譯階段:在這個階段,webpack 會將解析后的模塊轉換成 AST(抽象語法樹),并且根據配置文件中的規則,將模塊中的代碼進行轉換和處理。
    這個階段是 loader 的主要工作階段,loader 可以對模塊進行各種處理,例如轉換代碼、添加額外的功能等。

  • 生成階段:在這個階段,webpack 會根據處理后的模塊生成最終的輸出文件。輸出文件的格式和路徑可以通過配置文件進行配置。

在這些階段中,loader 主要在編譯階段發揮作用。loader 可以通過導出一個函數來定義自己的處理邏輯,這個函數接收一個參數,即待處理的模塊的源代碼,然后返回處理后的代碼。

開始編譯階段
獲取模塊源代碼
創建抽象語法樹AST
是否有匹配的loader?
調用loader處理函數
直接使用原始代碼
loader處理轉換
返回處理后的代碼
更新AST
分析模塊依賴
遞歸處理依賴模塊
生成最終代碼
結束編譯階段

常用loader

以下是一些常用的webpack loader:

Loader描述
babel-loader用于將ES6+的JavaScript代碼轉換為ES5代碼,以便在舊版本瀏覽器中運行。
css-loader用于解析CSS文件,并處理其中的import和url()等語法。
style-loader將解析后的CSS代碼以<style>標簽的形式插入到HTML文件中。
file-loader用于處理文件資源(如圖片、字體等),并將其復制到輸出目錄中。
url-loader類似于file-loader,但可以根據文件大小將文件轉換為DataURL,以減少HTTP請求。
sass-loader用于將Sass/SCSS代碼轉換為CSS代碼。
less-loader用于將Less代碼轉換為CSS代碼。
postcss-loader用于對CSS代碼進行后處理,如自動添加瀏覽器前綴等。
vue-loader用于解析和轉換Vue單文件組件。
ts-loader用于將TypeScript代碼轉換為JavaScript代碼。

自定義loader

// 核心代碼:function clearConsoleLoader(source) {// 使用正則表達式匹配并替換console語句const modifiedSource = source.replace(/console\.[a-z]+\(.+\);?/g, '');return modifiedSource;
}module.exports = clearConsoleLoader;//使用
module.exports = {// ...module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: ['babel-loader','./path/to/clearConsoleLoader.js']}]}
};

webpack中的plugins(插件)

工作原理

webpack 插件是用來擴展 webpack 功能的工具,它可以在 webpack 構建過程中的不同階段執行一些額外的操作。

插件的工作原理是通過在 webpack 的構建過程中的不同生命周期中注冊一些鉤子函數,然后在對應的階段執行這些鉤子函數中的邏輯。

webpack 的構建過程中有以下幾個生命周期:

  • 初始化階段:在這個階段,webpack 會初始化配置參數,加載插件,并準備開始編譯。

  • 編譯階段:在這個階段,webpack 會從入口文件開始遞歸解析所有的依賴模塊,并將模塊轉換成 AST(抽象語法樹),然后根據配置文件中的規則進行轉換和處理。

  • 完成編譯階段:在這個階段,webpack 已經完成了所有的模塊的轉換和處理,并且生成了最終的輸出文件。

  • 輸出階段:在這個階段,webpack 會將生成的輸出文件寫入到磁盤上。

插件可以在這些生命周期中的任意階段注冊對應的鉤子函數,并在鉤子函數中執行一些額外的操作。

插件鉤子注冊點
初始化鉤子
初始化階段
編譯鉤子
編譯階段
完成編譯鉤子
完成編譯階段
輸出鉤子
輸出階段

自定義plugins

class MyPlugin {apply(compiler) {// 注冊初始化階段的鉤子函數compiler.hooks.initialize.tap('MyPlugin', () => {console.log('MyPlugin initialized');});// 注冊編譯階段的鉤子函數compiler.hooks.compile.tap('MyPlugin', () => {console.log('MyPlugin compiling');});}
}module.exports = MyPlugin;// 使用const MyPlugin = require('./my-plugin');module.exports = {// ...plugins: [new MyPlugin(),],
};

打包過程

讀取配置文件
解析模塊依賴
加載器處理
插件處理
編譯打包
輸出打包文件
  • 讀取配置文件:Webpack會首先讀取配置文件,根據配置文件中的入口、出口等信息進行打包。

  • 解析模塊依賴:Webpack會從指定的入口文件開始遞歸解析所有的模塊依賴,直到找到所有的模塊。

  • 加載器處理:對于不同類型的模塊,Webpack會使用相應的加載器對其進行處理。例如,對于JavaScript模塊,Webpack會使用Babel加載器將ES6語法轉換為ES5語法;對于CSS模塊,Webpack會使用CSS加載器將CSS代碼打包進JS文件中。

  • 插件處理:在模塊加載完成之后,Webpack會執行一系列插件,用于完成一些額外的任務,例如生成HTML文件、提取CSS文件等。

  • 編譯打包:Webpack將經過處理的模塊和插件生成最終的打包文件。通常情況下,Webpack會生成一個或多個JavaScript文件,同時也可以生成其他類型的文件,例如CSS、圖片等。

  • 輸出打包文件:Webpack將生成的打包文件輸出到指定的目錄中。通常情況下,Webpack會將打包文件輸出到dist目錄下。

加速webpack打包速度和減小打包體積的優化

以下是一些加速Webpack打包和減小打包體積的技巧:

  1. 優化Webpack配置:使用Tree shaking來減小打包體積,設置Webpack的mode為production以啟用UglifyJsPlugin等插件進行代碼壓縮和優化。

  2. 使用Webpack的code splitting功能:將代碼分割成較小的塊,以便在需要時動態加載。

  3. 壓縮圖片和字體文件:使用ImageMinWebpackPlugin和FontminWebpackPlugin等插件來壓縮圖片和字體文件,減小打包體積。

  4. 緩存:啟用Webpack的緩存功能,以便在修改代碼時只重新打包修改的文件,而不是重新打包所有文件。

  5. 使用DLLPlugin和DllReferencePlugin:將一些第三方庫打包成單獨的文件,以便在每次打包應用程序時不必重新打包這些庫。

  6. 使用HappyPack插件:使用多線程來加速Webpack打包,以便同時處理多個任務。

  7. 使用externals選項:將一些不需要打包的庫從打包中排除,以便減小打包體積。

  8. 使用Webpack-bundle-analyzer插件:分析打包后的文件,以便找出冗余的代碼和依賴關系,進行優化。

這些技巧可以幫助優化Webpack的打包速度和打包體積。

優化方法具體實現
優化Webpack配置使用Tree shaking,設置mode: 'production'啟用UglifyJsPlugin等優化插件
使用code splitting動態加載分割后的代碼塊(如import()SplitChunksPlugin
壓縮圖片和字體文件通過ImageMinWebpackPluginFontminWebpackPlugin插件壓縮資源文件
啟用緩存配置cache: true或使用HardSourceWebpackPlugin加速重復構建
使用DLLPlugin預編譯第三方庫為獨立文件(DLL),通過DllReferencePlugin引用
多線程打包(HappyPack)使用HappyPackthread-loader并行處理任務
排除外部庫(externals)配置externals將庫(如jQuery)排除,通過CDN引入
分析打包體積使用webpack-bundle-analyzer可視化分析依賴,優化冗余代碼

webpack配置

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 自動引入資源插件  npm install --save-dev html-webpack-plugin
const MiniCssExtracPlugin = require("mini-css-extrac-plugin"); // css抽離
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");  //css壓縮 npm install css-minimizer-webpack-plugin  --save-dev 
const TerserPlugin = require("terser-webpack-plugin"); // js壓縮  npm install --save-dev terser-webpack-plugin
//加載toml、yarm、json5數據資源 npm install toml yarm json5 -D
const toml = require("toml");
const yarm = require("yarm");
const json5 = require("json5");module.exports = (env) => {return {// 手動分離公共文件,通過配置成對象的方式實現多入口代碼分割// entry: {//  index:{//    import:"./src/index.js",//    dependOn: "shared"  // 抽離公共文件//  },//  shared: "lodash"      // 公共的js文件// },// 多入口// entry: {// 	 pageOne: './src/pageOne/index.js',//  	pageTwo: './src/pageTwo/index.js',//  	pageThree: './src/pageThree/index.js',// },// 單入口entry: {index: "./src/index.js",},output: {filename: "scripts/[name].[contenthash].js", // 將所有的js放入同一個文件夾,并且根據文件名自動命名path: path.resolve(__dirname, "./dist"),clean: true, // 清除上一次的垃圾文件assetModuleFilename: "images/[contenthash][ext]", // 在images目錄下,根據文件內容自動生成hash文件名publicPath: "https://*****.com/", // 公共路徑(cdn域名或者本地localhost)},mode: env.prodection ? "prodection" : "development", // 生產環境或者開發環境 package.json 啟動命令:npx webpack --env prodectiondevtool: "cheap-module-source-map",     // 真實報錯文件指向,生產環境一般不開啟sourcemap// 插件(非必要的,缺少也不影響項目打包)plugins: [new HtmlWebpackPlugin({template: "./index.html", // 模板filename: "app.html",inject: "body", // script 存在的位置hash: true, // 解決緩存minify: {removeAttributeQuotes: true, // 壓縮,去掉引號},}),new MiniCssExtracPlugin({filename: "style/[contenthash].css",}),],devServer: {static: "./dist", // 監聽根目錄文件變化,自動刷新頁面插件 npm install --save-dev webpack-dev-server//反向代理proxy: {"/ajax": {target: "https:**********",ws: true,changeOrigin: true,},},},// 模塊(必要的,缺少影響項目打包)module: {rules: [//資源模塊類型我們稱之為Asset Modules Type,總共有四種,來代替loader,分別是:// asset/resource:發送一個單獨的文件并導出URL,替代file-loader// asset/inline:導出一個資源的data URI(base64),替代url-loader// asset/source:導出資源的源代碼,之前通過使用raw-loader實現// asset:介于asset/resource和asset/inline之間, 之前通過url-loader+limit屬性實現。{test: /\.(png|gif|jp?g|svg|webp|ico)$/, // 正則圖片文件type: "asset",generator: {filename: "images/[contenthash][ext]", // 優先級高于 assetModuleFilename},},{// 支持less// npm install style-loader css-loader less-loader less --save-dev// 抽離 npm install mini-css-extrac-plugin  --save-dev   webpack5環境下構建的插件test: /\.(le|c)ss$/, // .less and .cssuse: [MiniCssExtracPlugin.loader,/* "style-loader", */ "css-loader","less-loader"],},{test: /\.(woff|woff2|eot|ttf|oft)$/, // 正則字體文件type: "asset/resource",},//加載csv、xml數據資源 npm install csv-loader xml-loader -D{test: /\.(csv|tsv)$/,use: "csv-loader",},{test: /\.xml$/,use: "xml-loader",},//加載toml、yarm、json5數據資源{test: /\.toml$/,type: "json",parser: {parse: toml.parse,},},{test: /\.yarm$/,type: "json",parser: {parse: yarm.parse,},},{test: /\.json5$/,type: "json",parser: {parse: json5.parse,},},// loader工具 支持數組方式鏈式調用,數組靠后的元素先執行{// 壓縮圖片//圖片小于一定大小使用base64 否則使用file-loader產生真實圖片 npm install url-loader --save-devtest: /\.(png|gif|jp?g|svg|webp|ico)$/, // 正則use: [{loader: "url-loader",options: {limit: 5000, //小于限定使用base64name: "home/images/[name].[hash:8].[ext]",publicPath: `../../`,esModule: false,},},],},// 使用babel-loader npm install -D babel-loader @babel/core @babel/preset-env// regeneratorRuntime是webpack打包生成的全局輔助函數,由babel生成,用于兼容 async/await 的語法// npm install --save @babel/runtime// npm install --save-dev @babel/plugin-transform-runtime{test: /\.js$/,exclude: /node_modules/, // *業務代碼里面可能會引入node_modules外部js,這些js不需要babel-loader編譯,因此需要排除掉use: {loader: "babel-loader", // *引入babel-loaderoptions: {presets: ["@babel/preset-env"], // *引入預設plugins: [["@babel/plugin-transform-runtime", // *配置插件信息],],},},},],},optimization: {minimizer: [new CssMinimizerPlugin(),new TerserPlugin()],   //代碼壓縮 mode改為 productionsplitChunks: {// 緩存cacheGroups: {vendor: {test: /[\\/]node_modules[\\/]/,name: "vendors",chunks: "all", // 自動重復代碼抽離},},},},};
};

webpack配置拆分

webpack.config.common.js文件公共環境配置

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 自動引入資源插件  npm install --save-dev html-webpack-plugin
const MiniCssExtracPlugin = require("mini-css-extrac-plugin"); // css抽離
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); //css壓縮 npm install css-minimizer-webpack-plugin  --save-dev
const TerserPlugin = require("terser-webpack-plugin"); // js壓縮  npm install --save-dev terser-webpack-plugin
//加載toml、yarm、json5數據資源 npm install toml yarm json5 -D
const toml = require("toml");
const yarm = require("yarm");
const json5 = require("json5");module.exports = {entry: {index: "./src/index.js",},output: {path: path.resolve(__dirname, "./dist"),clean: true, // 清除上一次的垃圾文件assetModuleFilename: "images/[contenthash][ext]", // 在images目錄下,根據文件內容自動生成hash文件名},// 插件(非必要的,缺少也不影響項目打包)plugins: [new HtmlWebpackPlugin({template: "./index.html", // 模板filename: "app.html",inject: "body", // script 存在的位置hash: true, // 解決緩存minify: {removeAttributeQuotes: true, // 壓縮,去掉引號},}),new MiniCssExtracPlugin({filename: "style/[contenthash].css",}),],// 模塊(必要的,缺少影響項目打包)module: {},optimization: {splitChunks: {// 緩存cacheGroups: {vendor: {test: /[\\/]node_modules[\\/]/,name: "vendors",chunks: "all", // 自動重復代碼抽離},},},},
};
webpack.config.dev.js文件開發環境配置 npx webpack -c ./webpack.config.dev.js
module.exports = {output: {filename: "scripts/[name].js", // 將所有的js放入同一個文件夾,并且根據文件名自動命名},mode: "development", // 生產環境或者開發環境 package.json 啟動命令:npx webpack --env prodectiondevtool: "cheap-module-source-map", // 真實報錯文件指向,生產devServer: {static: "./dist", // 監聽根目錄文件變化,自動刷新頁面插件 npm install --save-dev webpack-dev-server//反向代理proxy: {"/ajax": {target: "https:**********",ws: true,changeOrigin: true,},},},
};
webpack.config.prod.js文件生產環境配置 npx webpack -c ./webpack.config.prod.js
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");  //css壓縮 npm install css-minimizer-webpack-plugin  --save-dev 
const TerserPlugin = require("terser-webpack-plugin"); // js壓縮  npm install --save-dev terser-webpack-pluginmodule.exports = {output: {filename: "scripts/[name].[contenthash].js", // 將所有的js放入同一個文件夾,并且根據文件名自動命名publicPath: "https://*****.com/", // 公共路徑(cdn域名或者本地localhost)},mode: "prodection", // 生產環境或者開發環境 package.json 啟動命令:npx webpack --env prodectionoptimization: {minimizer: [new CssMinimizerPlugin(), new TerserPlugin()], //代碼壓縮 mode改為 production},performance: {hints: false, // 關閉性能提示},
};
webpack.config.js 運行:webpack -c ./webpack.config.js --env development
const { merge } = require ('webpack-merge')   // npm install webpack-merge -D
const commonConfig = require ('./webpack.config.common')
const productionConfig = require ('./webpack.config.prod')
const developmentConfig = require ('./webpack.config.dev')module.exports = (env) => {switch (true) {case env.development :return merge(commonConfig,developmentConfig)case env.production :return merge(commonConfig,productionConfig)defult:return new Error()}
}

封裝webpack自定義插件

  1. 創建一個 JavaScript 文件,并導出一個函數。這個函數將作為你的插件的構造函數。

  2. 在函數中定義一個 apply 方法,該方法接收一個 compiler 參數。這個 compiler 對象是 Webpack 的核心,它包含了 Webpack 的所有配置和工作流程。

function MyPlugin() {} // 構造函數// 核心 apply 方法
MyPlugin.prototype.apply = function(compiler) {// 插件邏輯實現
};
  1. 在 apply 方法中,可以通過 compiler.hooks 對象訪問 Webpack 的生命周期鉤子。通過這些鉤子,你可以在 Webpack 運行的不同階段執行自定義代碼。
compiler.hooks.done.tap('PluginName', (stats) => {console.log('編譯完成!');
});
  1. 實現你的插件邏輯,例如在特定的 Webpack 鉤子上注冊回調函數,向編譯器添加自定義插件等。

  2. 將你的插件打包成一個 npm 模塊,并在項目中引入和使用它。

Webpack 插件本質上是一個具有 apply 方法的類或函數對象。通過掛接到 Webpack 編譯器的生命周期鉤子,我們可以實現各種構建時的定制化功能,如資源處理、日志輸出、文件生成等。


const MyPlugin = function() {};MyPlugin.prototype.apply = function(compiler) {compiler.hooks.done.tap('MyPlugin', (stats) => {console.log('Webpack 構建已完成!');if (stats.hasErrors()) {console.error('構建過程中出現錯誤');}});
};
module.exports = MyPlugin;上面示例我們定義了一個 MyPlugin 插件,它在 Webpack 編譯完成后輸出一條信息。
在 apply 方法中,我們使用 compiler.hooks.done 鉤子注冊了一個回調函數,在編譯完成后輸出一條消息。要使用這個插件,你需要將它打包成一個 npm 模塊,并在 Webpack 配置文件中引入和使用它:const MyPlugin = require('my-plugin');module.exports = {// ...plugins: [new MyPlugin()]
};

在這個示例中,我們在 Webpack 配置文件中引入了 MyPlugin 插件,并通過 plugins 選項將其添加到插件數組中。這樣一來,當 Webpack 進行編譯時,MyPlugin 就會被自動啟用并執行相應的邏輯。

如果你覺得這篇文章對你有幫助,請點贊 👍、收藏 👏 并關注我!👀

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/87884.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/87884.shtml
英文地址,請注明出處:http://en.pswp.cn/web/87884.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Manus AI與多語言手寫識別

技術文章大綱&#xff1a;Manus AI與多語言手寫識別 引言 手寫識別技術的發展背景與市場需求Manus AI的定位與核心技術優勢多語言場景下的挑戰與機遇 Manus AI的核心技術架構 基于深度學習的端到端手寫識別模型多模態數據融合&#xff08;筆跡壓力、書寫軌跡等&#xff09;…

Go與Python爬蟲對比及模板實現

go語言和Python語言都可選作用來爬蟲項目&#xff0c;因為python經過十幾年的累積&#xff0c;各種庫是應有盡有&#xff0c;學習也相對比較簡單&#xff0c;相比GO起步較晚還是有很大優勢的&#xff0c;么有對比就沒有傷害&#xff0c;所以我利用一個下午&#xff0c;寫個Go爬…

Vidwall: 支持將 4K 視頻設置為動態桌面壁紙,兼容 MP4 和 MOV 格式

支持將 4K 視頻設置為動態桌面壁紙&#xff0c;兼容 MP4 和 MOV 格式。只需將視頻拖入應用界面&#xff0c;點擊即可立即應用為桌面背景。 為桌面增添生動趣味的動態壁紙效果&#xff01;錄制視頻時設置動態背景&#xff0c;也能讓畫面更吸引人。 &#x1f4e5; https://apps.…

【LeetCode 熱題 100】234. 回文鏈表——快慢指針+反轉鏈表

Problem: 234. 回文鏈表 題目&#xff1a;給你一個單鏈表的頭節點 head &#xff0c;請你判斷該鏈表是否為回文鏈表。如果是&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 文章目錄 整體思路完整代碼時空復雜度時間復雜度&#xff1a;O(N)空間復雜度&#…

【源力覺醒 創作者計劃】開源、易用、強中文:文心一言4.5或是 普通人/非AI程序員 的第一款中文AI?

前言 你有沒有發現&#xff0c;AI 正在悄悄滲透進我們的生活&#xff1a;寫文案、畫插圖、做PPT、答作業&#xff0c;它幾乎無所不能&#x1f60d; &#xff01;但很多人可能會問&#xff1a; AI&#xff0c;我能用嗎&#xff1f;用得起嗎&#xff1f;適合我嗎&#xff1f;特別…

【保姆級喂飯教程】Git圖形化客戶端Sourcetree安裝及使用教程

目錄 前言一、SourceTree簡介二、安裝教程三、使用教程1. 添加倉庫 四、評價總結后記參考文獻 前言 在查找Git Flow實現工具的時候&#xff0c;看到了SourceTree&#xff0c;支持Git Flow、GitHub Flow等多種Git工作流&#xff0c;安裝簡單學習一下。 一、SourceTree簡介 Git的…

【kafka】kafka3.3.2常用命令

查看kafka服務版本 [rootlocalhost eicar]# kafka-server-start.sh --version [2025-06-23 11:10:54,106] INFO Registered kafka:typekafka.Log4jController MBean (kafka.utils.Log4jControllerRegistration$) 3.3.2 (Commit:b66af662e61082cb) [rootlocalhost eicar]#查看消…

LastActivityView -查看電腦上的所有操作記錄

LastActivityView 是一款由 NirSoft 開發的免費工具&#xff0c;適用于 Windows 操作系統。它能夠通過分析系統日志、Prefetch 文件、圖標緩存數據庫、注冊表以及藍屏 Dump 文件等多種來源&#xff0c;綜合展示電腦從安裝系統至今的所有操作記錄。 LastActivityView 的功能 L…

English Practice - Day 3

Hi ChatGPT, I am back. can we start today’s english practice? Welcome back, Kelly! &#x1f60a; Yes — let’s begin today’s English practice! You’re doing great by showing up consistently. &#x1f4aa; Q&#xff1a; What’s the weather like today w…

quickbi看板內嵌入powerbi頁面(含單點登錄解決方法)

quickbi看板內嵌入powerbi頁面&#xff08;含單點登錄解決方法&#xff09; 實現步驟 要實現在quickbi看板中嵌入powerbi頁面&#xff0c;分4步來實現。 1. 新建quickbi看板&#xff0c; 2. 添加內嵌頁面 3. 獲取Powerbi鏈接 4. 將powerbi鏈接粘貼到內嵌頁面中 第一步&am…

CentOS-6如何配置網絡設置IP? 筆記250706

CentOS-6如何配置網絡設置IP? 筆記250706 1?? 參考 1 CentOS 6 網絡配置完全指南 在 CentOS 6 中配置網絡設置主要涉及修改 /etc/sysconfig/network-scripts/ 目錄下的配置文件。以下是詳細配置步驟&#xff1a; 一、配置靜態 IP 地址 1. 編輯網卡配置文件 vi /etc/sys…

WPF學習筆記(24)命令與ICommand接口

命令與ICommand接口一、命令1. ICommandSource2. 示例3. CommandBinding二、ICommand1.ICommand接口2. ICommand用法3. CanExecute總結一、命令 官方文檔&#xff1a;https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/commanding-overview 1. ICommandSource 官…

TCP長連接保持在線狀態

TCP長連接是指在一次TCP連接建立后&#xff0c;保持連接狀態較長時間&#xff0c;用于多次數據傳輸&#xff0c;而不是每次通信后立即斷開。這種機制對于需要頻繁通信的應用非常重要。 保持TCP長連接在線的方法 1. 心跳機制(Heartbeat) 實現原理&#xff1a;定期發送小數據包…

華為OD機試 2025B卷 - 報文響應時間 (C++ Python JAVA JS C語言)

2025B卷目錄點擊查看: 華為OD機試2025B卷真題題庫目錄|機考題庫 + 算法考點詳解 2025B卷 100分題型 題目描述 IGMP 協議中,有一個字段稱作最大響應時間 (Max Response Time) ,HOST收到查詢報文,解折出 MaxResponsetime 字段后,需要在 (0,MaxResponseTime] 時間 (s) 內選…

深入理解微服務中的服務注冊與發現(Consul)

在當今數字化浪潮下&#xff0c;微服務架構憑借其高內聚、低耦合的特性&#xff0c;成為眾多企業構建復雜應用系統的首選方案。然而&#xff0c;隨著服務數量的不斷增加&#xff0c;服務之間的調用與管理變得愈發復雜。這時&#xff0c;服務注冊與發現就如同微服務架構中的 “導…

Zephyr【2】-----內核調度[1]

內核調度 Zephyr 內核的調度器是基于什么原則選擇當前執行線程的&#xff1f; 總是選擇優先級最高的就緒線程作為當前線程。 當多個線程優先級相同時&#xff0c;調度器會如何選擇&#xff1f; 線程的 “就緒狀態” 和 “非就緒狀態” 分別指什么&#xff1f;哪些情況會導致…

LangChain內置工具包和聯網搜索

目錄 一、什么是智能體?工具包又是什么&#xff1f; 二、智能體(Agent)的出現是為了解決哪些問題&#xff1f; 三、LangChain里面創建工具方式 3.1 tool 裝飾器&#xff1a;用來定義一個簡單的工具函數,, 可以直接給函數加上這個裝飾器&#xff0c;讓函數成為可調用的工具…

用c++做游戲開發至少要掌握哪些知識?

成長路上不孤單&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C愛好者&#x1f60a;///持續分享所學&#x1f60a;///如有需要歡迎收藏轉發///&#x1f60a;】 今日分享關于用C做游戲開發的相關內容&#xff01; 關…

vue3使用summernote

一、安裝 npm install summernote-vue jquery summernote bootstrap popperjs/core二、summernoteEditor.vue <template><div ref"editorRef"></div> </template><script setup> import {ref, onMounted, onBeforeUnmount, watch} f…

低代碼平臺的性能測試實踐與挑戰

一、引言 近年來&#xff0c;低代碼平臺&#xff08;Low-Code Platform&#xff09;正在快速改變企業軟件開發方式。Gartner 預測&#xff0c;到 2025 年&#xff0c;超過 70% 的應用開發將基于低代碼或無代碼技術。通過“拖拉拽建模 圖形化邏輯 一鍵發布”&#xff0c;企業…