您好,登錄后才能下訂單哦!
本文介紹了webpack4.0打包優化策略整理小結,分享給大家,具體如下:
webapck4 新特性介紹-參考資料
當前依賴包的版本
1.優化loader配置
1.1 縮小文件匹配范圍(include/exclude)
通過排除node_modules下的文件 從而縮小了loader加載搜索范圍 高概率命中文件
module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/, // 排除不處理的目錄 include: path.resolve(__dirname, 'src') // 精確指定要處理的目錄 } ] }
1.2 緩存loader的執行結果(cacheDirectory)
cacheDirectory是loader的一個特定的選項,默認值是false。指定的目錄(use: 'babel-loader?cacheDirectory=cacheLoader')將用來緩存loader的執行結果,減少webpack構建時Babel重新編譯過程。如果設置一個空值(use: 'babel-loader?cacheDirectory') 或true(use: 'babel-loader?cacheDirectory=true') 將使用默認的緩存目錄(node_modules/.cache/babel-loader),如果在任何根目錄下都沒有找到 node_modules 目錄,將會降級回退到操作系統默認的臨時文件目錄。
module: { rules: [ { test: /\.js$/, use: 'babel-loader?cacheDirectory', // 緩存loader執行結果 發現打包速度已經明顯提升了 exclude: /node_modules/, include: path.resolve(__dirname, 'src') } ] }
2.resolve優化配置
2.1 優化模塊查找路徑 resolve.modules
Webpack的resolve.modules配置模塊庫(即 node_modules)所在的位置,在 js 里出現 import 'vue' 這樣不是相對、也不是絕對路徑的寫法時,會去 node_modules 目錄下找。但是默認的配置,會采用向上遞歸搜索的方式去尋找,但通常項目目錄里只有一個 node_modules,且是在項目根目錄,為了減少搜索范圍,可以直接寫明 node_modules 的全路徑;同樣,對于別名(alias)的配置,亦當如此:
const path = require('path'); function resolve(dir) { // 轉換為絕對路徑 return path.join(__dirname, dir); } resolve: { modules: [ // 優化模塊查找路徑 path.resolve('src'), path.resolve('node_modules') // 指定node_modules所在位置 當你import 第三方模塊時 直接從這個路徑下搜索尋找 ] }
配置好src目錄所在位置后,由于util目錄是在src里面 所以可以用下面方式引入util中的工具函數
// main.js import dep1 from 'util/dep1'; import add from 'util/add';
2.2 resolve.alias 配置路徑別名
創建 import 或 require 的路徑別名,來確保模塊引入變得更簡單。配置項通過別名來把原導入路徑映射成一個新的導入路徑 此優化方法會影響使用Tree-Shaking去除無效代碼
例如,一些位于 src/ 文件夾下的常用模塊:
alias: { Utilities: path.resolve(__dirname, 'src/utilities/'), Templates: path.resolve(__dirname, 'src/templates/') }
現在,替換「在導入時使用相對路徑」這種方式,就像這樣:
import Utility from '../../utilities/utility';
你可以這樣使用別名:
import Utility from 'Utilities/utility';
resolve: { alias: { // 別名配置 通過別名配置 可以讓我們引用變的簡單 'vue$': 'vue/dist/vue.common.js', // $表示精確匹配 src: resolve('src') // 當你在任何需要導入src下面的文件時可以 import moduleA from 'src/moduleA' src會被替換為resolve('src') 返回的絕對路徑 而不需要相對路徑形式導入 } }
也可以在給定對象的鍵后的末尾添加 $,以表示精準匹配:
alias: { util$: resolve('src/util/add.js') }
這將產生以下結果:
import Test1 from 'util'; // 精確匹配,所以 src/util/add.js 被解析和導入 import Test2 from 'util/dep1.js'; // 精確匹配,觸發普通解析 util/dep1.js
2.3resolve.extensions
當引入模塊時不帶文件后綴 webpack會根據此配置自動解析確定的文件后綴
resolve: { extensions: ['.js', '.vue'] }
3.module.noParse
用了noParse的模塊將不會被loaders解析,所以當我們使用的庫如果太大,并且其中不包含import require、define的調用,我們就可以使用這項配置來提升性能, 讓 Webpack 忽略對部分沒采用模塊化的文件的遞歸解析處理。
// 忽略對jquery lodash的進行遞歸解析 module: { // noParse: /jquery|lodash/ // 從 webpack 3.0.0 開始 noParse: function(content) { return /jquery|lodash/.test(content) } }
4.HappyPack
HappyPack是讓webpack對loader的執行過程,從單一進程形式擴展為多進程模式,也就是將任務分解給多個子進程去并發的執行,子進程處理完后再把結果發送給主進程。從而加速代碼構建 與 DLL動態鏈接庫結合來使用更佳。
npm i happypack@next -D
webpack.config.js
const HappyPack = require('happypack'); const os = require('os'); // node 提供的系統操作模塊 // 根據我的系統的內核數量 指定線程池個數 也可以其他數量 const happyThreadPool = HappyPack.ThreadPool({size: os.cpus().lenght}) module: { rules: [ { test: /\.js$/, use: 'happypack/loader?id=babel', exclude: /node_modules/, include: path.resolve(__dirname, 'src') } ] }, plugins: [ new HappyPack({ // 基礎參數設置 id: 'babel', // 上面loader?后面指定的id loaders: ['babel-loader?cacheDirectory'], // 實際匹配處理的loader threadPool: happyThreadPool, // cache: true // 已被棄用 verbose: true }); ]
happypack提供的loader,是對文件實際匹配的處理loader。這里happypack提供的loader與plugin的銜接匹配,則是通過id=happypack來完成。
npm run dev
5.DLL動態鏈接庫
在一個動態鏈接庫中可以包含其他模塊調用的函數和數據,動態鏈接庫只需被編譯一次,在之后的構建過程中被動態鏈接庫包含的模塊將不會被重新編譯,而是直接使用動態鏈接庫中的代碼。
5.1 定義DLL配置
依賴的兩個內置插件:DllPlugin 和 DllReferencePlugin
5.1.1 創建一個DLL配置文件webpack_dll.config.js
module.exports = { entry: { react: ['react', 'react-dom'] }, output: { filename: '[name].dll.js', // 動態鏈接庫輸出的文件名稱 path: path.join(__dirname, 'dist'), // 動態鏈接庫輸出路徑 libraryTarget: 'var', // 鏈接庫(react.dll.js)輸出方式 默認'var'形式賦給變量 b library: '_dll_[name]_[hash]' // 全局變量名稱 導出庫將被以var的形式賦給這個全局變量 通過這個變量獲取到里面模塊 }, plugins: [ new webpack.DllPlugin({ // path 指定manifest文件的輸出路徑 path: path.join(__dirname, 'dist', '[name].manifest.json'), name: '_dll_[name]_[hash]', // 和library 一致,輸出的manifest.json中的name值 }) ] }
5.1.2 output.libraryTarget 規定了以哪一種導出你的庫 默認以全局變量形式 瀏覽器支持的形式
具體包括如下:
5.1.3 打包生成動態鏈接庫
webpack --config webpack_dll.config.js --mode production
在dist目錄下 多出react.dll.js 和 react.manifest.json
5.2 在主配置文件中使用動態鏈接庫文件
// webpack.config.js const webpack = require('webpack'); plugins: [ // 當我們需要使用動態鏈接庫時 首先會找到manifest文件 得到name值記錄的全局變量名稱 然后找到動態鏈接庫文件 進行加載 new webpack.DllReferencePlugin({ manifest: require('./dist/react.manifest.json') }) ]
5.3 將動態鏈接庫文件加載到頁面中
需要借助兩個webpack插件
html-webpack-plugin 產出html文件
html-webpack-include-assets-plugin 將js css資源添加到html中 擴展html插件的功能
npm i html-webpack-plugin html-webpack-include-assets-plugin -D
配置webpack.config.js
const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlIncludeAssetsPlugin = require('html-webpack-include-assets-plugin'); pluings: [ new webpack.DllReferencePlugin({ manifest: require('./dist/react.manifest.json') }), new HtmlWebpackPlugin({ template: path.join(__dirname, 'src/index.html') }), new HtmlIncludeAssetsPlugin({ assets: ['./react.dll.js'], // 添加的資源相對html的路徑 append: false // false 在其他資源的之前添加 true 在其他資源之后添加 }); ]
此時react.dll.js和main.js被自動引入到頁面中,并且dll文件在main.js之前加載
6.ParallelUglifyPlugin
這個插件可以幫助有很多入口點的項目加快構建速度。把對JS文件的串行壓縮變為開啟多個子進程并行進行uglify。
cnpm i webpack-parallel-uglify-plugin -D
// webpck.config.js const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin'); plugins: [ new ParallelUglifyPlugin({ workerCount: 4, uglifyJS: { output: { beautify: false, // 不需要格式化 comments: false // 保留注釋 }, compress: { // 壓縮 warnings: false, // 刪除無用代碼時不輸出警告 drop_console: true, // 刪除console語句 collapse_vars: true, // 內嵌定義了但是只有用到一次的變量 reduce_vars: true // 提取出出現多次但是沒有定義成變量去引用的靜態值 } } }); ]
執行壓縮
webpack --mode production
7.Tree Shaking
剔除JavaScript中用不上的代碼。它依賴靜態的ES6模塊化語法,例如通過impot和export導入導出
commonJS模塊 與 es6模塊的區別
commonJS模塊:
1.動態加載模塊 commonJS 是運行時加載 能夠輕松實現懶加載,優化用戶體驗
2.加載整個模塊 commonJS模塊中,導出的是整個模塊
3.每個模塊皆為對象 commonJS模塊被視作一個對象
4.值拷貝 commonJS的模塊輸出和函數的值傳遞相似,都是值得拷貝
es6模塊
1.靜態解析 es6模塊時 編譯時加載 即在解析階段就確定輸出的模塊的依賴關系,所以es6模塊的import一般寫在被引入文件的開頭
2.模塊不是對象 在es6里,每個模塊并不會當做一個對象看待
3.加載的不是整個模塊 在es6模塊中 一個模塊中有好幾個export導出
4.模塊的引用 es6模塊中,導出的并不是模塊的值得拷貝,而是這個模塊的引用
7.1 保留ES6模塊化語法
// .babelrc { "presets": [ [ "env", { modules: false // 不要編譯ES6模塊 }, "react", "stage-0" ] ] }
7.2 執行生產編譯 默認已開啟Tree Shaking
webpack --mode production
什么是Tree Shaking?
有個funs.js 里面有兩個函數
// funs.js export const sub = () => 'hello webpack!'; export const mul = () => 'hello shaking!';
main.js 中依賴funs.js
// main.js import {sub} from './funs.js' sub();
在main.js只使用了里面的 sub函數 默認情況下也會將funs.js里面其他沒有的函數也打包進來, 如果開啟tree shaking 生產編譯時
webpack --mode production //此時funs.js中沒有被用到的代碼并沒打包進來 而被剔除出去了
未完待續...
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。