前言
之前一段時間工作原因把精力都放在小程序上,趁現在有點空閑時間,剛好官方文檔也補充完整了,我準備重溫一下 webpack 之路了,因為官方文檔已經寫得非常詳細,我會大量引用原文描述,主要重點放在怎么從零構建 webpack4 代碼上,這不是一個系統的教程,而是從零摸索一步步搭建起來的筆記,所以前期可能bug會后續發現繼續修復而不是修改文章.
webpack4從零開始構建(一)
webpack4+React16項目構建(二)
webpack4功能配置劃分細化(三)
webpack4引入Ant Design和Typescript(四)
webpack4 代碼去重,簡化信息和構建優化(五)
2024/04/16上傳,代碼同步到引入antd webpack4_demo_antd
抽取配置參數
同級目錄新建文件env.js
文件,我們將一些環境變量和配置變量獨立開來,盡量不耦合進webpack文件里.如下所示
const path = require('path'); const isDev = process.env.NODE_ENV !== "DEV", isProd = process.env.NODE_ENV !== "PROD", isServer = process.env.NODE_ENV !== "SERVER", entry = "./src/index.tsx", outputName = "[name].bundle.js", outputPath = path.resolve(__dirname, "../dist"), publicPath = "", title = "test"; module.exports = { isDev, isProd, isServer, entry, outputName, outputPath, publicPath, title };
webpack.common.js
相關變量替換如下:
...省略 const { isProd, entry, outputName, outputPath, publicPath, title } = require('./env'); module.exports = { // 入口 entry, // 輸出 output: { // 打包文件名 filename: outputName, // 輸出路徑 path: outputPath, // 資源請求路徑 publicPath }, module: { rules }, plugins: [ // 清除文件 new CleanWebpackPlugin(), // 提取樣式文件 new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // both options are optional filename: !isProd ? "[name].css" : "style/[name].[contenthash].css", chunkFilename: !isProd ? "[id].css" : "style/[id].[contenthash].css" }), new HtmlWebpackPlugin({ // title title, // 模板 template: "index.html" }) ], ...省略 };
進度條展示
yarn add progress-bar-webpack-plugin ------------------------------------------- new VueLoaderPlugin()
目測沒啥用處,求個視覺效果吧
定義環境變量
new webpack.DefinePlugin({
'process.env.project': 'demo'
}),
plugins部分最終代碼如下:
plugins: [ // 清除文件 new CleanWebpackPlugin(), // 進度條展示 new ProgressBarPlugin(), // 該插件幫助我們安心地使用環境變量 new webpack.DefinePlugin({ 'process.env.project': 'demo' }), // 提取樣式文件 new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // both options are optional filename: !isProd ? "[name].css" : "style/[name].[contenthash].css", chunkFilename: !isProd ? "[id].css" : "style/[id].[contenthash].css" }), new HtmlWebpackPlugin({ // title title, // 模板 template: "index.html" }) ],
輸出信息
我們可以自定義webpack打包的輸出信息,因為比較多字段,所以同級目錄新增stats.js
文件,具體似乎出看自己需求自由改動吧
module.exports = { // 未定義選項時,stats 選項的備用值(fallback value)(優先級高于 webpack 本地默認值) all: undefined, // 添加資源信息 assets: true, // 對資源按指定的字段進行排序 // 你可以使用 `!field` 來反轉排序。愛掏網 - it200.com // Some possible values: 'id' (default), 'name', 'size', 'chunks', 'failed', 'issuer' // For a complete list of fields see the bottom of the page assetsSort: 'field', // 添加構建日期和構建時間信息 builtAt: true, // 添加緩存(但未構建)模塊的信息 cached: true, // 顯示緩存的資源(將其設置為 `false` 則僅顯示輸出的文件) cachedAssets: true, // 添加 children 信息 children: true, // 添加 chunk 信息(設置為 `false` 能允許較少的冗長輸出) chunks: false, // 添加 namedChunkGroups 信息 chunkGroups: false, // 將構建模塊信息添加到 chunk 信息 chunkModules: false, // 添加 chunk 和 chunk merge 來源的信息 chunkOrigins: false, // 按指定的字段,對 chunk 進行排序 // 你可以使用 `!field` 來反轉排序。愛掏網 - it200.com默認是按照 `id` 排序。愛掏網 - it200.com // Some other possible values: 'name', 'size', 'chunks', 'failed', 'issuer' // For a complete list of fields see the bottom of the page chunksSort: 'field', // `webpack --colors` 等同于 colors: true, // 顯示每個模塊到入口起點的距離(distance) depth: false, // 通過對應的 bundle 顯示入口起點 entrypoints: false, // 添加 --env information env: false, // 添加錯誤信息 errors: true, // 添加錯誤的詳細信息(就像解析日志一樣) errorDetails: true, /* // 將資源顯示在 stats 中的情況排除 // 這可以通過 String, RegExp, 獲取 assetName 的函數來實現 // 并返回一個布爾值或如下所述的數組。愛掏網 - it200.com excludeAssets: "filter" | /filter/ | (assetName) => true | false | ["filter"] | [/filter/] | [(assetName) => true | false], // 將模塊顯示在 stats 中的情況排除 // 這可以通過 String, RegExp, 獲取 moduleSource 的函數來實現 // 并返回一個布爾值或如下所述的數組。愛掏網 - it200.com excludeModules: "filter" | /filter/ | (moduleSource) => true | false | ["filter"] | [/filter/] | [(moduleSource) => true | false], // 查看 excludeModules exclude: "filter" | /filter/ | (moduleSource) => true | false | ["filter"] | [/filter/] | [(moduleSource) => true | false], */ // 添加 compilation 的哈希值 hash: true, // 設置要顯示的模塊的最大數量 // maxModules: 15, // 添加構建模塊信息 modules: true, // 按指定的字段,對模塊進行排序 // 你可以使用 `!field` 來反轉排序。愛掏網 - it200.com默認是按照 `id` 排序。愛掏網 - it200.com // Some other possible values: 'name', 'size', 'chunks', 'failed', 'issuer' // For a complete list of fields see the bottom of the page modulesSort: 'field', // 顯示警告/錯誤的依賴和來源(從 webpack 2.5.0 開始) moduleTrace: true, // 當文件大小超過 `performance.maxAssetSize` 時顯示性能提示 performance: true, // 顯示模塊的導出 providedExports: false, // 添加 public path 的信息 publicPath: false, // 添加模塊被引入的原因 reasons: false, // 添加模塊的源碼 source: false, // 添加時間信息 timings: true, // 顯示哪個模塊導出被用到 usedExports: false, // 添加 webpack 版本信息 version: false, // 添加警告 warnings: true, // 過濾警告顯示(從 webpack 2.4.0 開始), // 可以是 String, Regexp, 一個獲取 warning 的函數 // 并返回一個布爾值或上述組合的數組。愛掏網 - it200.com第一個匹配到的為勝(First match wins.)。愛掏網 - it200.com // warningsFilter: "filter" | /filter/ | ["filter", /filter/] | (warning) => true| false }
禁止體積警告
performance: { hints: false // 取消靜態文件超過250kb的警告 },
設置后不影響打包,只是不會提示
完整代碼
const HtmlWebpackPlugin = require("html-webpack-plugin"), CleanWebpackPlugin = require("clean-webpack-plugin"), MiniCssExtractPlugin = require("mini-css-extract-plugin"), ProgressBarPlugin = require('progress-bar-webpack-plugin'), webpack = require('webpack'), alias = require("./alias"), rules = require("./rules"), stats = require("./stats"), { isProd, entry, outputName, outputPath, publicPath, title } = require('./env'); module.exports = { // 入口 entry, // 輸出 output: { // 打包文件名 filename: outputName, // 輸出路徑 path: outputPath, // 資源請求路徑 publicPath }, module: { rules }, stats, performance: { hints: false // 取消靜態文件超過250kbkb的警告 }, plugins: [ // 清除文件 new CleanWebpackPlugin(), // 進度條展示 new ProgressBarPlugin(), // 該插件幫助我們安心地使用環境變量 new webpack.DefinePlugin({ 'process.env.project': 'demo' }), // 提取樣式文件 new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // both options are optional filename: !isProd ? "[name].css" : "style/[name].[contenthash].css", chunkFilename: !isProd ? "[id].css" : "style/[id].[contenthash].css" }), new HtmlWebpackPlugin({ // title title, // 模板 template: "index.html" }) ], resolve: { // Add '.ts' and '.tsx' as resolvable extensions. extensions: [".ts", ".tsx", ".js", ".json"], // 創建 import 或 require 的別名,來確保模塊引入變得更簡單 alias } };
rules.js
原本代碼充斥很多重復代碼,將他們提取出來
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const tsImportPluginFactory = require("ts-import-plugin"); const { isProd, isServer, entry, outputName, outputPath, publicPath, title } = require('./env') const cssMiniLoader = !isServer ? { loader: MiniCssExtractPlugin.loader, options: { // you can specify a publicPath here // by default it use publicPath in webpackOptions.output publicPath: process.env.NODE_ENV === "DEV" ? "./" : "../" } } : "style-loader"; // 使用
因為現在已經有awesome-typescript-loader
處理,所以我們可以將js規則去掉.同時默認會禁止babel,如果需要的話可以配置babelOptions
webpack.server.js
我們稍微再細致一下配置,修改如下
const path = require('path'), webpack = require('webpack'), merge = require('webpack-merge'), common = require('./webpack.common.js'), BundleAnalyzerPlugin = require('webpack-bundle-analyzer') .BundleAnalyzerPlugin; module.exports = merge(common, { mode: "development", // 原始源代碼(僅限行) devtool: "cheap-module-eval-source-map", devServer: { clientLogLevel: 'warning', // none,error,warning // 打開模式, Iframe mode和Inline mode最后達到的效果都是一樣的,都是監聽文件的變化,然后再將編譯后的文件推送到前端,完成頁面的reload的 inline: true, progress: true, // 指定了服務器資源的根目錄 contentBase: path.join(__dirname, '../'), // 是否開啟gzip壓縮 compress: false, port: 9000, // 是否開啟熱替換功能 // hot: true, host: 'localhost', // 是否自動打開頁面,可以傳入指定瀏覽器名字打開 open: false, // 是否開啟部分熱替換功能 hotOnly: true, proxy: { }, // Shows a full-screen overlay in the browser when there are compiler errors or warnings. Disabled by default. If you want to show only compiler errors: overlay: { warnings: false, errors: true }, /* 惰性模式 將不監視文件改動,不想使用自動刷新功能時可設置為true */ lazy: false, /* 靜默模式,減少不必要的信息輸出 necessary for FriendlyErrorsPlugin */ quiet: false, watchOptions: { // Turn on polling by passing true, or specifying a poll interval in milliseconds: poll: false }, // 同stats stats: { builtAt: true, colors: true, modules: false, children: false, chunks: false, chunkModules: false, // 添加時間信息 timings: true } }, plugins: [ // 熱替換模塊 new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. new webpack.NoEmitOnErrorsPlugin() //在編譯出現錯誤時,使用 NoEmitOnErrorsPlugin 來跳過輸出階段。愛掏網 - it200.com這樣可以確保輸出資源不會包含錯誤。愛掏網 - it200.com對于所有資源,統計資料(stat)的 emitted 標識都是 false // 性能可視化 // new BundleAnalyzerPlugin() ] });
生產構建優化
當前配置代碼如下
const merge = require("webpack-merge"), common = require("./webpack.common.js"), OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"), ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); module.exports = merge(common, { mode: "production", // 原始源代碼 devtool: "cheap-module-eval-source-map", plugins: [new OptimizeCssAssetsPlugin()] });
可以看出構建文件和耗費時間
刪除映射
devtool: "none",
提供公共庫
簡單將node_modules
和業務代碼分開
optimization: { // Setting optimization.runtimeChunk to true or "multiple" adds an additional chunk to each entrypoint containing only the runtime. This setting is an alias for: runtimeChunk: { name: 'manifest' }, splitChunks: { minSize: 0, cacheGroups: { vendor: { // 優先級高于其他就不會被打包進其他chunk,如果想匹配自己定義的拆分規則,則priority需要設置為正數,優先匹配默認拆分規則就設置為負數。愛掏網 - it200.com priority: 10, name: 'vendor', test: /[\\/]node_modules[\\/]/, chunks: 'all' } } } },
結果如下
引入webpack-parallel-uglify-plugin
這插件能為多入口文件啟用多線程構建,提高打包速度,這里demo比較簡單暫時用不到,但是我們可以利用他做一些特殊處理
minimizer: [ // This plugin serves to help projects with many entry points speed up their builds. The UglifyJS plugin provided with webpack runs sequentially on each of the output files. This plugin runs uglify in parallel with one thread for each of your available cpus. This can lead to significantly reduced build times as minification is very CPU intensive. new ParallelUglifyPlugin({ // Optional absolute path to use as a cache. If not provided, caching will not be used. cacheDir: '.cache/', // 傳遞給 UglifyJS的參數如下: uglifyJS: { output: { /* 是否輸出可讀性較強的代碼,即會保留空格和制表符,默認為輸出,為了達到更好的壓縮效果, 可以設置為false */ beautify: false, /* 是否保留代碼中的注釋,默認為保留,為了達到更好的壓縮效果,可以設置為false */ comments: false }, compress: { /* 是否在UglifyJS刪除沒有用到的代碼時輸出警告信息,默認為輸出,可以設置為false關閉這些作用 不大的警告 */ warnings: false, /* 是否刪除代碼中所有的console語句,默認為不刪除,開啟后,會刪除所有的console語句 */ drop_console: true, /* 是否內嵌雖然已經定義了,但是只用到一次的變量,比如將 var x = 1; y = x, 轉換成 y = 5, 默認為不 轉換,為了達到更好的壓縮效果,可以設置為false */ collapse_vars: true, /* 是否提取出現了多次但是沒有定義成變量去引用的靜態值,比如將 x = 'xxx'; y = 'xxx' 轉換成 var a = 'xxxx'; x = a; y = a; 默認為不轉換,為了達到更好的壓縮效果,可以設置為false */ reduce_vars: true } } }) ]
最終代碼
const merge = require("webpack-merge"), common = require("./webpack.common.js"), OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"), ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); module.exports = merge(common, { mode: "production", // 原始源代碼 devtool: "none", optimization: { // Setting optimization.runtimeChunk to true or "multiple" adds an additional chunk to each entrypoint containing only the runtime. This setting is an alias for: runtimeChunk: { name: 'manifest' }, splitChunks: { minSize: 0, cacheGroups: { vendor: { // 優先級高于其他就不會被打包進其他chunk,如果想匹配自己定義的拆分規則,則priority需要設置為正數,優先匹配默認拆分規則就設置為負數。愛掏網 - it200.com priority: 10, name: 'vendor', test: /[\\/]node_modules[\\/]/, chunks: 'all' } } }, minimizer: [ // This plugin serves to help projects with many entry points speed up their builds. The UglifyJS plugin provided with webpack runs sequentially on each of the output files. This plugin runs uglify in parallel with one thread for each of your available cpus. This can lead to significantly reduced build times as minification is very CPU intensive. new ParallelUglifyPlugin({ // Optional absolute path to use as a cache. If not provided, caching will not be used. cacheDir: '.cache/', // 傳遞給 UglifyJS的參數如下: uglifyJS: { output: { /* 是否輸出可讀性較強的代碼,即會保留空格和制表符,默認為輸出,為了達到更好的壓縮效果, 可以設置為false */ beautify: false, /* 是否保留代碼中的注釋,默認為保留,為了達到更好的壓縮效果,可以設置為false */ comments: false }, compress: { /* 是否在UglifyJS刪除沒有用到的代碼時輸出警告信息,默認為輸出,可以設置為false關閉這些作用 不大的警告 */ warnings: false, /* 是否刪除代碼中所有的console語句,默認為不刪除,開啟后,會刪除所有的console語句 */ drop_console: true, /* 是否內嵌雖然已經定義了,但是只用到一次的變量,比如將 var x = 1; y = x, 轉換成 y = 5, 默認為不 轉換,為了達到更好的壓縮效果,可以設置為false */ collapse_vars: true, /* 是否提取出現了多次但是沒有定義成變量去引用的靜態值,比如將 x = 'xxx'; y = 'xxx' 轉換成 var a = 'xxxx'; x = a; y = a; 默認為不轉換,為了達到更好的壓縮效果,可以設置為false */ reduce_vars: true } } }) ] }, plugins: [new OptimizeCssAssetsPlugin()] });
打包結果
聲明:所有內容來自互聯網搜索結果,不保證100%準確性,僅供參考。如若本站內容侵犯了原著者的合法權益,可聯系我們進行處理。