日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

webpack从入门到精通(四)优化打包配置总结②

發(fā)布時(shí)間:2025/3/20 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 webpack从入门到精通(四)优化打包配置总结② 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. tree shaking

tree-shaking的本質(zhì)是消除無(wú)用的js代碼。無(wú)用代碼消除廣泛存在于傳統(tǒng)的編程語(yǔ)言編譯器中,編譯器可以判斷出某些代碼根本不影響輸出,然后消除這些代碼,這個(gè)稱(chēng)之為DCE(dead code elimination)。

Tree-shaking 是 DCE 的一種新的實(shí)現(xiàn),Javascript同傳統(tǒng)的編程語(yǔ)言不同的是,javascript絕大多數(shù)情況需要通過(guò)網(wǎng)絡(luò)進(jìn)行加載,然后執(zhí)行,加載的文件大小越小,整體執(zhí)行時(shí)間更短,所以去除無(wú)用代碼以減少文件體積,對(duì)javascript來(lái)說(shuō)更有意義。

它依賴(lài)于 ES2015 模塊系統(tǒng)中的靜態(tài)結(jié)構(gòu)特性,例如 import 和 export。這個(gè)術(shù)語(yǔ)和概念實(shí)際上是興起于 ES2015 模塊打包工具 rollup。

新的 webpack 4 正式版本,擴(kuò)展了這個(gè)檢測(cè)能力,通過(guò) package.json 的 "sideEffects" 屬性作為標(biāo)記,向 compiler 提供提示,表明項(xiàng)目中的哪些文件是 "pure(純的 ES2015 模塊)",由此可以安全地刪除文件中未使用的部分。

在一個(gè)純粹的 ESM 模塊世界中,識(shí)別出哪些文件有副作用很簡(jiǎn)單。然而,我們的項(xiàng)目無(wú)法達(dá)到這種純度,所以,此時(shí)有必要向 webpack 的 compiler 提供提示哪些代碼是“純粹部分”。

如果所有代碼都不包含副作用,我們就可以簡(jiǎn)單地將該屬性標(biāo)記為 false,來(lái)告知 webpack,它可以安全地刪除未用到的 export 導(dǎo)出。

如果你的代碼確實(shí)有一些副作用,那么可以改為提供一個(gè)數(shù)組。

前提:1. 必須使用ES6模塊化 2. 開(kāi)啟production環(huán)境 ? 在package.json中配置 "sideEffects": ["*.css", "*.less"]

index.js

import { mul } from './test'; import '../css/index.css'; ? function sum(...args) {return args.reduce((p, c) => p + c, 0); } ? // eslint-disable-next-line console.log(mul(2, 3)); // eslint-disable-next-line console.log(sum(1, 2, 3, 4));

test.js

export function mul(x, y) {return x * y; } ? export function count(x, y) {return x - y; }

可以發(fā)現(xiàn),count()函數(shù)我們并沒(méi)有使用。打包后的文件中將不會(huì)包含count()函數(shù)。

2. code split

何為Code Split?

webpack從入口文件開(kāi)始遍歷,找到所有依賴(lài)文件,然后打包成最終的一個(gè)文件,即bundle.js文件,這是我們經(jīng)常使用的方式,當(dāng)一個(gè)項(xiàng)目慢慢變得復(fù)雜的時(shí)候會(huì)導(dǎo)致這個(gè)bundle.js文件越來(lái)越大,瀏覽器加載的速度也會(huì)越來(lái)越慢,這個(gè)過(guò)程還不排除我們需要引用的第三方文件,這樣每次無(wú)論是構(gòu)建,還是瀏覽器加載這個(gè)最終文件,都會(huì)存在效率問(wèn)題,webpack提供了codesplitting功能來(lái)解決這個(gè)問(wèn)題,這可以最大限度的減少瀏覽器加載必要代碼時(shí)間(比如首屏渲染優(yōu)化)。這個(gè)過(guò)程我們可以分為兩種情況來(lái)討論,第三方的分為靜態(tài)文件處理,瀏覽器加載必要文件作為動(dòng)態(tài)文件處理(按需加載,懶加載)

常見(jiàn)的 webpack code split 方法有三種。

1)多入口配置

?// 單入口// entry: './src/js/index.js',entry: {// 多入口:有一個(gè)入口,最終輸出就有一個(gè)bundleindex: './src/js/index.js',test: './src/js/test.js'}

2)使用plugins配置進(jìn)行分割

webpack 在4.0版本開(kāi)始對(duì)防重復(fù)方式進(jìn)行了改寫(xiě),通過(guò)配置optimization。

  • 可以將node_modules中代碼單獨(dú)打包一個(gè)chunk最終輸出

  • 自動(dòng)分析多入口chunk中,有沒(méi)有公共的文件。如果有會(huì)打包成單獨(dú)一個(gè)chunk

?optimization: {splitChunks: {chunks: 'all'}}

我們下面演示一下:

我們?cè)趇ndex.js和test.js中都引入第三方庫(kù)jquery

index.js

import $ from 'jquery'; import { mul } from './test'; function sum(...args) {return args.reduce((p, c) => p + c, 0); } ? ? console.log(sum(1, 2, 3, 4)); console.log($);; console.log(mul(2,3));

test.js

import $ from 'jquery'; ? // eslint-disable-next-line console.log($); ? export function mul(x, y) {return x * y; } ? export function count(x, y) {return x - y; }

單入口配置webpack.config.js

const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); ? module.exports = {// 單入口entry: './src/js/index.js',output: {// [name]:取文件名filename: 'js/[name].[contenthash:10].js',path: resolve(__dirname, 'build')},plugins: [new HtmlWebpackPlugin({template: './src/index.html',minify: {collapseWhitespace: true,removeComments: true}})],/*1. 可以將node_modules中代碼單獨(dú)打包一個(gè)chunk最終輸出2. 自動(dòng)分析多入口chunk中,有沒(méi)有公共的文件。如果有會(huì)打包成單獨(dú)一個(gè)chunk*/optimization: {splitChunks: {chunks: 'all'}},mode: 'production' };

打包出的文件如下:

jquery被單獨(dú)打成一個(gè)文件。

注意:如果沒(méi)有引入optimization插件,則只會(huì)生成main.js一個(gè)文件,且文件大小會(huì)比較大。

多入口配置webpack.config.js

?entry: {index: './src/js/index.js',test: './src/js/test.js'}

打包出的文件如下:

index.js和test.js中引入了同樣的jquery,被合并打包成同一個(gè)文件。

3)動(dòng)態(tài)導(dǎo)入

上面我們發(fā)現(xiàn),在單入口配置中,index.js中引入了test.js,但是test.js并不會(huì)單獨(dú)打包,我們可以通過(guò)import來(lái)動(dòng)態(tài)導(dǎo)入。

語(yǔ)法如下:

// 可以通過(guò)注釋來(lái)設(shè)置文件名 import(/* webpackChunkName: "home" */ "url文件路徑").then((text)=> {// do something })

index.js

function sum(...args) {return args.reduce((p, c) => p + c, 0); } ? /*通過(guò)js代碼,讓某個(gè)文件被單獨(dú)打包成一個(gè)chunkimport動(dòng)態(tài)導(dǎo)入語(yǔ)法:能將某個(gè)文件單獨(dú)打包可以通過(guò)注釋來(lái)設(shè)置文件名 */ import(/* webpackChunkName: 'test' */'./test').then(({ mul, count }) => {// 文件加載成功~// eslint-disable-next-lineconsole.log(mul(2, 5));}).catch(() => {// eslint-disable-next-lineconsole.log('文件加載失敗~');}); ? // eslint-disable-next-line console.log(sum(1, 2, 3, 4)); ?

打包出的文件如下:

可以發(fā)現(xiàn),test.js和main.js分別打包成了兩個(gè)文件。

3. 懶加載和預(yù)加載

懶加載或者按需加載,是一種很好的優(yōu)化網(wǎng)頁(yè)或應(yīng)用的方式。這種方式實(shí)際上是先把你的代碼在一些邏輯斷點(diǎn)處分離開(kāi),然后在一些代碼塊中完成某些操作后,立即引用或即將引用另外一些新的代碼塊。這樣加快了應(yīng)用的初始加載速度,減輕了它的總體體積,因?yàn)槟承┐a塊可能永遠(yuǎn)不會(huì)被加載。

通俗來(lái)說(shuō)就是,如果每次加載頁(yè)面的時(shí)候都會(huì)加載某些代碼塊,會(huì)重復(fù)的請(qǐng)求,造成資源的浪費(fèi),影響網(wǎng)站性能。所以提出了懶加載的解決辦法:按需加載,初始化不需要加載此代碼塊,等到具體的執(zhí)行需要時(shí)候,再加載,從而優(yōu)化性能。

例如:在點(diǎn)擊按鈕的事件處理中,才需要用到來(lái)自print.js的print函數(shù)。所以可以將代碼寫(xiě)成點(diǎn)擊時(shí)候觸發(fā)加載print.js。

正常加載:

即使沒(méi)有點(diǎn)擊,test.js文件也會(huì)直接加載。

console.log('index.js文件被加載了~'); ? import { mul } from './test'; ? ? document.getElementById('btn').onclick = function() {console.log(mul(4, 5)); };

懶加載:文件需要使用時(shí)才加載

只有點(diǎn)擊后,test.js文件才會(huì)加載。

console.log('index.js文件被加載了~'); ? document.getElementById('btn').onclick = function() { ?import(/* webpackChunkName: 'test' */'./test').then(({ mul }) => {console.log(mul(4, 5));}); };

點(diǎn)擊前的資源加載如下:

預(yù)加載 prefetch:會(huì)在使用之前,提前加載 js 文件,等其他資源加載完畢,瀏覽器空閑了,偷偷加載資源

console.log('index.js文件被加載了~'); ? document.getElementById('btn').onclick = function() {import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {console.log(mul(4, 5));}); };

預(yù)加載的效果和懶加載是一樣的,不過(guò)資源文件加載方式如下:

可以發(fā)現(xiàn),雖然沒(méi)使用test.js,但會(huì)提前加載資源

4. 多進(jìn)程打包

1)下載plugin包

npm install --save-dev thread-loader

2)分析

進(jìn)程啟動(dòng)大概為 600ms,進(jìn)程通信也有開(kāi)銷(xiāo),當(dāng)只有工作消耗時(shí)間比較長(zhǎng)時(shí),才需要多進(jìn)程打包

3)配置文件

{test: /\.js$/,use: [{loader: 'thread-loader',options: {workers: 2 // 進(jìn)程2個(gè)}}] }

5. externals

webpack 中的 externals 配置提供了不從 bundle 中引用依賴(lài)的方式。解決的是,所創(chuàng)建的 bundle 依賴(lài)于那些存在于用戶(hù)環(huán)境(consumer environment)中的依賴(lài)。

怎么理解呢,意思是如果需要引用一個(gè)庫(kù),但是又不想讓webpack打包(減少打包的時(shí)間),并且又不影響我們?cè)诔绦蛑幸訡MD、AMD或者window/global全局等方式進(jìn)行使用(一般都以import方式引用使用),那就可以通過(guò)配置externals。

這樣做的目的就是將不怎么需要更新的第三方庫(kù)脫離webpack打包,不被打入bundle中,從而減少打包時(shí)間,但又不影響運(yùn)用第三方庫(kù)的方式,例如import方式等。

例如:

在index.html中引入jquery庫(kù)

?<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>

webpack.config.js配置如下:

const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); ? module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})],mode: 'production',externals: {// 拒絕jQuery被打包進(jìn)來(lái)jquery: 'jQuery'} }; ?

index.js

import $ from 'jquery'; ? console.log($);

排除之后,我們的jquery并沒(méi)有打包進(jìn)index.js中。

這樣不僅之前對(duì)第三方庫(kù)的用法方式不變,還把第三方庫(kù)剝離出webpack的打包中,從而加速webpack的打包速度。

6. dll

事先把常用但又構(gòu)建時(shí)間長(zhǎng)的代碼提前打包好(例如 react、react-dom),取個(gè)名字叫 dll。后面再打包的時(shí)候就跳過(guò)原來(lái)的未打包代碼,直接用 dll。這樣一來(lái),構(gòu)建時(shí)間就會(huì)縮短,提高 webpack 打包速度。

使用dll時(shí),可以把構(gòu)建過(guò)程分成dll構(gòu)建過(guò)程和主構(gòu)建過(guò)程(實(shí)質(zhì)也就是如此),所以需要兩個(gè)構(gòu)建配置文件,例如叫做webpack.config.js和webpack.dll.config.js。

1)使用DLLPlugin打包需要分離到動(dòng)態(tài)庫(kù)的模塊

DllPlugin是webpack內(nèi)置的插件,不需要額外安裝,直接配置webpack.dll.config.js文件:

/*使用dll技術(shù),對(duì)某些庫(kù)(第三方庫(kù):jquery、react、vue...)進(jìn)行單獨(dú)打包當(dāng)你運(yùn)行 webpack 時(shí),默認(rèn)查找 webpack.config.js 配置文件需求:需要運(yùn)行 webpack.dll.js 文件--> webpack --config webpack.dll.config.js */ ? const { resolve } = require('path'); const webpack = require('webpack'); ? module.exports = {entry: {// 最終打包生成的[name] --> jquery// ['jquery'] --> 要打包的庫(kù)是jqueryjquery: ['jquery']},output: {filename: '[name].js',path: resolve(__dirname, 'dll'),library: '[name]_[hash]' // 打包的庫(kù)里面向外暴露出去的內(nèi)容叫什么名字},plugins: [// 打包生成一個(gè) manifest.json --> 提供和jquery映射new webpack.DllPlugin({name: '[name]_[hash]', // 映射庫(kù)的暴露的內(nèi)容名稱(chēng)path: resolve(__dirname, 'dll/manifest.json') // 輸出文件路徑})],mode: 'production' }; ?

執(zhí)行:webpack --config webpack.dll.config,然后到指定的輸出文件夾查看輸出:

  • jquery.js文件

  • manifest.json文件里,是用來(lái)描述對(duì)應(yīng)的dll文件里保存的模塊里暴露出剛剛構(gòu)建的所有模塊

  • {"name":"jquery_a3c4dcd85c404db1c6a0","content":{"../../../node_modules/jquery/dist/jquery.js":{"id":1,"buildMeta":{"providedExports":true}}}}

    2)在主構(gòu)建配置文件使用動(dòng)態(tài)庫(kù)文件

    在webpack.config中使用dll要用到DllReferencePlugin,這個(gè)插件通過(guò)引用 dll 的 manifest 文件來(lái)把依賴(lài)的名稱(chēng)映射到模塊的 id 上。

    下面的配置文件還使用了dd-asset-html-webpack-plugin,會(huì)讓我們的index.html自動(dòng)引入該資源。

    const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin'); ? module.exports = {entry: './src/index.js',output: {filename: 'built.js',path: resolve(__dirname, 'build')},plugins: [new HtmlWebpackPlugin({template: './src/index.html'}),// 告訴webpack哪些庫(kù)不參與打包,同時(shí)使用時(shí)的名稱(chēng)也得變~new webpack.DllReferencePlugin({manifest: resolve(__dirname, 'dll/manifest.json')}),// 將某個(gè)文件打包輸出去,并在html中自動(dòng)引入該資源new AddAssetHtmlWebpackPlugin({filepath: resolve(__dirname, 'dll/jquery.js')})],mode: 'production' };

    打包前的index.html

    ?<h1 id="title">hello html</h1>

    打包后的index.html

    ?<h1 id="title">hello html</h1> <script type="text/javascript" src="jquery.js"></script><script type="text/javascript" src="built.js"></script></body>

    ?

    總結(jié)

    以上是生活随笔為你收集整理的webpack从入门到精通(四)优化打包配置总结②的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。