国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

前端構(gòu)建效率優(yōu)化之路

這篇具有很好參考價(jià)值的文章主要介紹了前端構(gòu)建效率優(yōu)化之路。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

項(xiàng)目背景

我們的系統(tǒng)(一個(gè) ToB 的 Web 單頁應(yīng)用)前端單頁應(yīng)用經(jīng)過多年的迭代,目前已經(jīng)累積有大幾十萬行的業(yè)務(wù)代碼,30+ 路由模塊,整體的代碼量和復(fù)雜度還是比較高的。

項(xiàng)目整體是基于 Vue + TypeScirpt,而構(gòu)建工具,由于最早項(xiàng)目是經(jīng)由?vue-cli?初始化而來,所以自然而然使用的是 Webpack。

我們知道,隨著項(xiàng)目體量越來越大,我們在開發(fā)階段將項(xiàng)目跑起來,也就是通過?npm run serve?的單次冷啟動(dòng)時(shí)間,以及在項(xiàng)目發(fā)布時(shí)候的?npm run build?的耗時(shí)都會(huì)越來越久。

因此,打包構(gòu)建優(yōu)化也是伴隨項(xiàng)目的成長需要持續(xù)不斷去做的事情。在早期,項(xiàng)目體量比較小的時(shí),構(gòu)建優(yōu)化的效果可能還不太明顯,而隨著項(xiàng)目體量的增大,構(gòu)建耗時(shí)逐漸增加,如何盡可能的降低構(gòu)建時(shí)間,則顯得越來越重要:

  1. 大項(xiàng)目通常是團(tuán)隊(duì)內(nèi)多人協(xié)同開發(fā),單次開發(fā)時(shí)的冷啟動(dòng)時(shí)間的降低,乘上人數(shù)及天數(shù),經(jīng)年累月節(jié)省下來的時(shí)間非??捎^,能較大程度的提升開發(fā)效率、提升開發(fā)體驗(yàn)

  2. 大項(xiàng)目的發(fā)布構(gòu)建的效率提升,能更好的保證項(xiàng)目發(fā)布、回滾等一系列操作的準(zhǔn)確性、及時(shí)性

本文,就將詳細(xì)介紹整個(gè) WMS FE 項(xiàng)目,在隨著項(xiàng)目體量不斷增大的過程中,對整體的打包構(gòu)建效率的優(yōu)化之路。

瓶頸分析

再更具體一點(diǎn),我們的項(xiàng)目最初是基于?vue-cli 4,當(dāng)時(shí)其基于的是 webpack4 版本。如無特殊說明,下文的一些配置會(huì)基于 webpack4 展開。

工欲善其事必先利其器,解決問題前需要分析問題,要優(yōu)化構(gòu)建速度,首先得分析出 Webpack 構(gòu)建編譯我們的項(xiàng)目過程中,耗時(shí)所在,側(cè)重點(diǎn)分布。

這里,我們使用的是 SMP 插件,統(tǒng)計(jì)各模塊耗時(shí)數(shù)據(jù)。

speed-measure-webpack-plugin?是一款統(tǒng)計(jì) webpack 打包時(shí)間的插件,不僅可以分析總的打包時(shí)間,還能分析各階段loader 的耗時(shí),并且可以輸出一個(gè)文件用于永久化存儲(chǔ)數(shù)據(jù)。

// 安裝npm install --save-dev speed-measure-webpack-plugin
// 使用方式
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");const smp = new SpeedMeasurePlugin();config.plugins.push(smp());

開發(fā)階段構(gòu)建耗時(shí)

對于?npm run serve,也就是開發(fā)階段而言,在沒有任何緩存的前提下,單次冷啟動(dòng)整個(gè)項(xiàng)目的時(shí)間達(dá)到了驚人的 4 min。

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

生產(chǎn)階段構(gòu)建耗時(shí)

而對于?npm run build,也就是實(shí)際線上生產(chǎn)環(huán)境的構(gòu)建,看看總體的耗時(shí):

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

因此,對于構(gòu)建效率的優(yōu)化可謂是勢在必行。首先,我們需要明確,優(yōu)化分為兩個(gè)方向:

  1. 基于開發(fā)階段?npm run serve?的優(yōu)化

在開發(fā)階段,我們的核心目標(biāo)是在保有項(xiàng)目所有功能的前提下,盡可能提高構(gòu)建速度,保證開發(fā)時(shí)的效率,所以對于 Live 才需要的一些功能,譬如代碼混淆壓縮、圖片壓縮等功能是可以不開啟的,并且在開發(fā)階段,我們需要熱更新。

  1. 基于生產(chǎn)階段?npm run build?的優(yōu)化

而在生產(chǎn)打包階段,盡管構(gòu)建速度也非常重要,但是一些在開發(fā)時(shí)可有可無的功能必須加上,譬如代碼壓縮、圖片壓縮。因此,生產(chǎn)構(gòu)建的目標(biāo)是在于保證最終項(xiàng)目打包體積盡可能小,所需要的相關(guān)功能盡可能完善的前提下,同時(shí)保有較快的構(gòu)建速度。

兩者的目的不盡相同,因此一些構(gòu)建優(yōu)化手段可能僅在其中一個(gè)環(huán)節(jié)有效。

基于上述的一些分析,本文將從如下幾個(gè)方面探討對構(gòu)建效率優(yōu)化的探索:

  1. 基于 Webpack 的一些常見傳統(tǒng)優(yōu)化方式

  2. 分模塊構(gòu)建

  3. 基于 Vite 的構(gòu)建工具切換

  4. 基于 Es-build 插件的構(gòu)建效率優(yōu)化

為什么這么慢?

那么,為什么隨著項(xiàng)目的增大,構(gòu)建的效率變得越來越慢了呢?

從上面兩張截圖不難看出,對于我們這樣一個(gè)單頁應(yīng)用,構(gòu)建過程中的大部分時(shí)間都消耗在編譯 JavaScript 文件及 CSS 文件的各類 Loader 上。

本文不會(huì)詳細(xì)描述 Webpack 的構(gòu)建原理,我們只需要大致知道,Webpack 的構(gòu)建流程,主要時(shí)間花費(fèi)在遞歸遍歷各個(gè)入口文件,并基于入口文件不斷尋找依賴逐個(gè)編譯再遞歸處理的過程,每次遞歸都需要經(jīng)歷 String->AST->String 的流程,然后通過不同的 loader 處理一些字符串或者執(zhí)行一些 JavaScript 腳本,由于 NodeJS 單線程的特性以及語言本身的效率限制,Webpack 構(gòu)建慢一直成為它飽受詬病的原因。

因此,基于上述 Webpack 構(gòu)建的流程及提到的一些問題,整體的優(yōu)化方向就變成了:

  1. 緩存

  2. 多進(jìn)程

  3. 尋路優(yōu)化

  4. 抽離拆分

  5. 構(gòu)建工具替換

基于 Webpack 的傳統(tǒng)優(yōu)化方式

上面也說了,構(gòu)建過程中的大部分時(shí)間都消耗在遞歸地去編譯 JavaScript 及 CSS 的各類 Loader 上,并且會(huì)受限于 NodeJS 單線程的特性以及語言本身的效率限制。

如果不替換掉 Webpack 本身,語言本身(NodeJS)的執(zhí)行效率是沒法優(yōu)化的,只能在其他幾個(gè)點(diǎn)做文章。

因此在最早期,我們所做的都是一些比較常規(guī)的優(yōu)化手段,這里簡單介紹最為核心的幾個(gè):

  1. 緩存

  2. 多進(jìn)程

  3. 尋址優(yōu)化

緩存優(yōu)化

其實(shí)對于?vue-cli 4?而言,已經(jīng)內(nèi)置了一些緩存操作,譬如上圖可見到 loader 的過程中,有使用?cache-loader,所以我們并不需要再次添加到項(xiàng)目之中。

  • cache-loader: 在一些性能開銷較大的 loader 之前添加 cache-loader,以便將結(jié)果緩存到磁盤里

那還有沒有一些其他的緩存操作呢用上的呢?我們使用了一個(gè)?HardSourceWebpackPlugin

HardSourceWebpackPlugin

  • HardSourceWebpackPlugin: HardSourceWebpackPlugin 為模塊提供中間緩存,緩存默認(rèn)存放的路徑是?node_modules/.cache/hard-source,配置了?HardSourceWebpackPlugin?之后,首次構(gòu)建時(shí)間并沒有太大的變化,但是第二次開始,構(gòu)建時(shí)間將會(huì)大大的加快。

首先安裝依賴:

npm install hard-source-webpack-plugin -D

修改?vue.config.js?配置文件:

const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
  ...
  configureWebpack: (config) => {
    // ...
    config.plugins.push(new HardSourceWebpackPlugin());
  },
  ...
}

配置了?HardSourceWebpackPlugin?的首次構(gòu)建時(shí)間,和預(yù)期的一樣,并沒有太大的變化,但是第二次構(gòu)建從平均 4min 左右降到了平均 20s 左右,提升的幅度非常的夸張,當(dāng)然,這個(gè)也因項(xiàng)目而異,但是整體而言,在不同項(xiàng)目中實(shí)測發(fā)現(xiàn)它都能比較大的提升開發(fā)時(shí)二次編譯的效率。

設(shè)置 babel-loader 的 cacheDirectory 以及 DLL

另外,在緩存方面我們的嘗試有:

  1. 設(shè)置 babel-loader 的 cacheDirectory

  2. DLL

但是整體收效都不太大,可以簡單講講。

打開 babel-loader 的 cacheDirectory 的配置,當(dāng)有設(shè)置時(shí),指定的目錄將用來緩存 loader 的執(zhí)行結(jié)果。之后的 webpack 構(gòu)建,將會(huì)嘗試讀取緩存,來避免在每次執(zhí)行時(shí),可能產(chǎn)生的、高性能消耗的 Babel 重新編譯過程。實(shí)際的操作步驟,你可以看看?Webpack - babel-loader。

那么 DLL 又是什么呢?

DLL 文件為動(dòng)態(tài)鏈接庫,在一個(gè)動(dòng)態(tài)鏈接庫中可以包含給其他模塊調(diào)用的函數(shù)和數(shù)據(jù)。

為什么要用 DLL?

原因在于包含大量復(fù)用模塊的動(dòng)態(tài)鏈接庫只需要編譯一次,在之后的構(gòu)建過程中被動(dòng)態(tài)鏈接庫包含的模塊將不會(huì)在重新編譯,而是直接使用動(dòng)態(tài)鏈接庫中的代碼。

由于動(dòng)態(tài)鏈接庫中大多數(shù)包含的是常用的第三方模塊,例如 Vue、React、React-dom,只要不升級這些模塊的版本,動(dòng)態(tài)鏈接庫就不用重新編譯。

DLL 的配置非常繁瑣,并且最終收效甚微,我們在過程中借助了?autodll-webpack-plugin,感興趣的可以自行嘗試。值得一提的是,Vue-cli 已經(jīng)剔除了這個(gè)功能。

多進(jìn)程

基于 NodeJS 單線程的特性,當(dāng)有多個(gè)任務(wù)同時(shí)存在,它們也只能排隊(duì)串行執(zhí)行。

而如今大多數(shù) CPU 都是多核的,因此我們可以借助一些工具,充分釋放 CPU 在多核并發(fā)方面的優(yōu)勢,利用多核優(yōu)勢,多進(jìn)程同時(shí)處理任務(wù)。

從上圖中可以看到,Vue CLi4 中,其實(shí)已經(jīng)內(nèi)置了?thread-loader

  • thread-loader: 把?thread-loader?放置在其它 loader 之前,那么放置在這個(gè) loader 之后的 loader 就會(huì)在一個(gè)單獨(dú)的 worker 池中運(yùn)行。這樣做的好處是把原本需要串行執(zhí)行的任務(wù)并行執(zhí)行。

那么,除了?thread-loader,還有哪些可以考慮的方案呢?

HappyPack

HappyPack 與?thread-loader?類似。

HappyPack 可利用多進(jìn)程對文件進(jìn)行打包, 將任務(wù)分解給多個(gè)子進(jìn)程去并行執(zhí)行,子進(jìn)程處理完后,再把結(jié)果發(fā)送給主進(jìn)程,達(dá)到并行打包的效果、HappyPack 并不是所有的 loader 都支持, 比如 vue-loader 就不支持。

可以通過?Loader Compatibility List?來查看支持的 loaders。需要注意的是,創(chuàng)建子進(jìn)程和主進(jìn)程之間的通信是有開銷的,當(dāng)你的 loader 很慢的時(shí)候,可以加上 happypack。否則,可能會(huì)編譯的更慢。

當(dāng)然,由于 HappyPack 作者對 JavaScript 的興趣逐步丟失,維護(hù)變少,webpack4 及之后都更推薦使用?thread-loader。因此,這里沒有實(shí)際結(jié)論給出。

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

上一次 HappyPack 更新已經(jīng)是 3 年前

尋址優(yōu)化

對于尋址優(yōu)化,總體而言提升并不是很大。

它的核心即在于,合理設(shè)置 loader 的?exclude?和?include?屬性。

  • 通過配置 loader 的 exclude 選項(xiàng),告訴對應(yīng)的 loader 可以忽略某個(gè)目錄

  • 通過配置 loader 的 include 選項(xiàng),告訴 loader 只需要處理指定的目錄,loader 處理的文件越少,執(zhí)行速度就會(huì)更快

這肯定是有用的優(yōu)化手段,只是對于一些大型項(xiàng)目而言,這類優(yōu)化對整體構(gòu)建時(shí)間的優(yōu)化不會(huì)特別明顯。

分模塊構(gòu)建

在上述的一些常規(guī)優(yōu)化完成后。整體效果仍舊不是特別明顯,因此,我們開始思考一些其它方向。

我們再來看看 Webpack 構(gòu)建的整體流程:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

上圖是大致的 webpack 構(gòu)建流程,簡單介紹一下:

  1. entry-option:讀取 webpack 配置,調(diào)用 new Compile(config) 函數(shù)準(zhǔn)備編譯

  2. run:開始編譯

  3. make:從入口開始分析依賴,對依賴模塊進(jìn)行 build

  4. before-resolve:對位置模塊進(jìn)行解析

  5. build-module:開始構(gòu)建模塊

  6. normal-module-loader:生成 AST 樹

  7. program:遍歷 AST 樹,遇到 require 語句收集依賴

  8. seal:build 完成開始優(yōu)化

  9. emit:輸出 dist 目錄

隨著項(xiàng)目體量地不斷增大,耗時(shí)大頭消耗在第 7 步,遞歸遍歷 AST,解析 require,如此反復(fù)直到遍歷完整個(gè)項(xiàng)目。

而有意思的是,對于單次單個(gè)開發(fā)而言,極大概率只是基于這整個(gè)大項(xiàng)目的某一小個(gè)模塊進(jìn)行開發(fā)即可。

所以,如果我們可以在收集依賴的時(shí)候,跳過我們本次不需要的模塊,或者可以自行選擇,只構(gòu)建必要的模塊,那么整體的構(gòu)建時(shí)間就可以大大減少。

這也就是我們要做的 --?分模塊構(gòu)建。

什么意思呢?舉個(gè)栗子,假設(shè)我們的項(xiàng)目一共有 6 個(gè)大的路由模塊 A、B、C、D、E、F,當(dāng)新需求只需要在 A 模塊范圍內(nèi)進(jìn)行優(yōu)化新增,那么我們在開發(fā)階段啟動(dòng)整個(gè)項(xiàng)目的時(shí)候,可以跳過 B、C、D、E、F 這 5 個(gè)模塊,只構(gòu)建 A 模塊即可:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

假設(shè)原本每個(gè)模塊的構(gòu)建平均耗時(shí) 3s,原本 18s 的整體冷啟動(dòng)構(gòu)建耗時(shí)就能下降到 3s

分模塊構(gòu)建打包的原理

Webpack 是靜態(tài)編譯打包的,Webpack 在收集依賴時(shí)會(huì)去分析代碼中的 require(import 會(huì)被 bebel 編譯成 require) 語句,然后遞歸的去收集依賴進(jìn)行打包構(gòu)建。

我們要做的,就是通過增加一些配置,簡單改造下我們的現(xiàn)有代碼,使得 Webpack 在初始化遍歷整個(gè)路由模塊收集依賴的時(shí)候,可以跳過我們不需要的模塊。

再說得詳細(xì)點(diǎn),假設(shè)我們的路由大致代碼如下:

import Vue from 'vue';
import VueRouter, { Route } from 'vue-router';

// 1. 定義路由組件.
// 這里簡化下模型,實(shí)際項(xiàng)目中肯定是一個(gè)一個(gè)的大路由模塊,從其他文件導(dǎo)入
const moduleA = { template: '<div>AAAA</div>' }
const moduleB = { template: '<div>BBBB</div>' }
const moduleC = { template: '<div>CCCC</div>' }
const moduleD = { template: '<div>DDDD</div>' }
const moduleE = { template: '<div>EEEE</div>' }
const moduleF = { template: '<div>FFFF</div>' }

// 2. 定義一些路由
// 每個(gè)路由都需要映射到一個(gè)組件。
// 我們后面再討論嵌套路由。
const routesConfig = [
  { path: '/A', component: moduleA },
  { path: '/B', component: moduleB },
  { path: '/C', component: moduleC },
  { path: '/D', component: moduleD },
  { path: '/E', component: moduleE },
  { path: '/F', component: moduleF }
]

const router = new VueRouter({
  mode: 'history',
  routes: routesConfig,
});

// 讓路由生效 ...
const app = Vue.createApp({})
app.use(router)

我們要做的,就是每次啟動(dòng)項(xiàng)目時(shí),可以通過一個(gè)前置命令行腳本,收集本次需要啟動(dòng)的模塊,按需生成需要的?routesConfig?即可。

我們嘗試了:

  1. IgnorePlugin?插件

  2. webpack-virtual-modules?配合?require.context

  3. NormalModuleReplacementPlugin?插件進(jìn)行文件替換

最終選擇了使用?NormalModuleReplacementPlugin?插件進(jìn)行文件替換的方式,原因在于它對整個(gè)項(xiàng)目的侵入性非常小,只需要添加前置腳本及修改 Webpack 配置,無需改變?nèi)魏温酚晌募a??偨Y(jié)而言,該方案的兩點(diǎn)優(yōu)勢在于:

  1. 無需改動(dòng)上層代碼

  2. 通過生成臨時(shí)路由文件的方式,替換原路由文件,對項(xiàng)目無任何影響

使用 NormalModuleReplacementPlugin 生成新的路由配置文件

利用?NormalModuleReplacementPlugin?插件,可以不修改原來的路由配置文件,在編譯階段根據(jù)配置生成一個(gè)新的路由配置文件然后去使用它,這樣做的好處在于對整個(gè)源碼沒有侵入性。

NormalModuleReplacementPlugin?插件的作用在于,將目標(biāo)源文件的內(nèi)容替換為我們自己的內(nèi)容。

我們簡單修改 Webpack 配置,如果當(dāng)前是開發(fā)環(huán)境,利用該插件,將原本的?config.ts?文件,替換為另外一份,代碼如下:

// vue.config.js
if (process.env.NODE_ENV === 'development') {
  config.plugins.push(new webpack.NormalModuleReplacementPlugin(
      /src\/router\/config.ts/,
      '../../dev.routerConfig.ts'
    )
  )
}

上面的代碼功能是將實(shí)際使用的?config.ts?替換為自定義配置的?dev.routerConfig.ts?文件,那么?dev.routerConfig.ts?文件的內(nèi)容又是如何產(chǎn)生的呢,其實(shí)就是借助了?inquirer?與?EJS?模板引擎,通過一個(gè)交互式的命令行問答,選取需要的模塊,基于選擇的內(nèi)容,動(dòng)態(tài)的生成新的?dev.routerConfig.ts?代碼,這里直接上代碼。

改造一下我們的啟動(dòng)腳本,在執(zhí)行?vue-cli-service serve?前,先跑一段我們的前置腳本:

{
  // ...
  "scripts": {
    - "dev": "vue-cli-service serve",
    + "dev": "node ./script/dev-server.js && vue-cli-service serve",
  },
  // ...
}

而?dev-server.js?所需要做的事,就是通過?inquirer?實(shí)現(xiàn)一個(gè)交互式命令,用戶選擇本次需要啟動(dòng)的模塊列表,通過?ejs?生成一份新的?dev.routerConfig.ts?文件。

// dev-server.js
const ejs = require('ejs');
const fs = require('fs');
const child_process = require('child_process');
const inquirer = require('inquirer');
const path = require('path');

const moduleConfig = [
    'moduleA',
    'moduleB',
    'moduleC',
    // 實(shí)際業(yè)務(wù)中的所有模塊
]

//選中的模塊
const chooseModules = [
  'home'
]

function deelRouteName(name) {
  const index = name.search(/[A-Z]/g);
  const preRoute = '' + path.resolve(__dirname, '../src/router/modules/') + '/';
  if (![0, -1].includes(index)) {
    return preRoute + (name.slice(0, index) + '-' + name.slice(index)).toLowerCase();
  }
  return preRoute + name.toLowerCase();;
}

function init() {
  let entryDir = process.argv.slice(2);
  entryDir = [...new Set(entryDir)];
  if (entryDir && entryDir.length > 0) {
    for(const item of entryDir){
      if(moduleConfig.includes(item)){
        chooseModules.push(item);
      }
    }
    console.log('output: ', chooseModules);
    runDEV();
  } else {
    promptModule();
  }
}

const getContenTemplate = async () => {
  const html = await ejs.renderFile(path.resolve(__dirname, 'router.config.template.ejs'), { chooseModules, deelRouteName }, {async: true});
  fs.writeFileSync(path.resolve(__dirname, '../dev.routerConfig.ts'), html);
};

function promptModule() {
  inquirer.prompt({
    type: 'checkbox',
    name: 'modules',
    message: '請選擇啟動(dòng)的模塊, 點(diǎn)擊上下鍵選擇, 按空格鍵確認(rèn)(可以多選), 回車運(yùn)行。注意: 直接敲擊回車會(huì)全量編譯, 速度較慢。',
    pageSize: 15,
    choices: moduleConfig.map((item) => {
      return {
        name: item,
        value: item,
      }
    })
  }).then((answers) => {
    if(answers.modules.length===0){
      chooseModules.push(...moduleConfig)
    }else{
      chooseModules.push(...answers.modules)
    }
    runDEV();
  });
}

init();

模板代碼的簡單示意:

// 模板代碼示意,router.config.template.ejs
import { RouteConfig } from 'vue-router';

<% chooseModules.forEach(function(item){%>
import <%=item %> from '<%=deelRouteName(item) %>';
<% }) %>
let routesConfig: Array<RouteConfig> = [];
/* eslint-disable */
  routesConfig = [
    <% chooseModules.forEach(function(item){%>
      <%=item %>,
    <% }) %>
  ]

export default routesConfig;

dev-server.js?的核心在于啟動(dòng)一個(gè) inquirer 交互命令行服務(wù),讓用戶選擇需要構(gòu)建的模塊,類似于這樣:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

模板代碼示意?router.config.template.ejs?是 EJS 模板文件,chooseModules?是我們在終端輸入時(shí),獲取到的用戶選擇的模塊集合數(shù)組,根據(jù)這個(gè)列表,我們?nèi)ド尚碌?routesConfig?文件。

這樣,我們就實(shí)現(xiàn)了分模塊構(gòu)建,按需進(jìn)行依賴收集。以我們的項(xiàng)目為例,我們的整個(gè)項(xiàng)目大概有 20 個(gè)不同的模塊,幾十萬行代碼:

構(gòu)建模塊數(shù) 耗時(shí)
冷啟動(dòng)全量構(gòu)建 20 個(gè)模塊 4.5min
冷啟動(dòng)只構(gòu)建 1 個(gè)模塊 18s
有緩存狀態(tài)下二次構(gòu)建 1 個(gè)模塊 4.5s

實(shí)際效果大致如下,無需啟動(dòng)所有模塊,只啟動(dòng)我們選中的模塊進(jìn)行對應(yīng)的開發(fā)即可:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

這樣,如果單次開發(fā)只涉及固定的模塊,單次項(xiàng)目冷啟動(dòng)的時(shí)間,可以從原本的 4min+ 下降到 18s 左右,而有緩存狀態(tài)下二次構(gòu)建 1 個(gè)模塊,僅僅需要 4.5s,屬于一個(gè)比較大的提升。

受限于 Webpack 所使用的語言的性能瓶頸,要追求更快的構(gòu)建性能,我們不可避免的需要把目光放在其他構(gòu)建工具上。這里,我們的目光聚焦在了 Vite 與 esbuild 上。

使用 Vite 優(yōu)化開發(fā)時(shí)構(gòu)建

Vite,一個(gè)基于瀏覽器原生 ES 模塊的開發(fā)服務(wù)器。利用瀏覽器去解析 imports,在服務(wù)器端按需編譯返回,完全跳過了打包這個(gè)概念,服務(wù)器隨起隨用。同時(shí)不僅有 Vue 文件支持,還搞定了熱更新,而且熱更新的速度不會(huì)隨著模塊增多而變慢。

當(dāng)然,由于 Vite 本身特性的限制,目前只適用于在開發(fā)階段替代 Webpack。

我們都知道 Vite 非常快,它主要快在什么地方?

  1. 項(xiàng)目冷啟動(dòng)更快

  2. 熱更新更快

那么是什么讓它這么快?

Webpack 與 Vite 冷啟動(dòng)的區(qū)別

我們先來看看 Webpack 與 Vite 的在構(gòu)建上的區(qū)別。下圖是 Webpack 的遍歷遞歸收集依賴的過程:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

上文我們也講了,Webpack 啟動(dòng)時(shí),從入口文件出發(fā),調(diào)用所有配置的 Loader 對模塊進(jìn)行編譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經(jīng)過了本步驟的處理。

這一過程是非常非常耗時(shí)的,再看看 Vite:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

Vite 通過在一開始將應(yīng)用中的模塊區(qū)分為?依賴?和?源碼?兩類,改進(jìn)了開發(fā)服務(wù)器啟動(dòng)時(shí)間。它快的核心在于兩點(diǎn):

  1. 使用 Go 語言的依賴預(yù)構(gòu)建:Vite 將會(huì)使用?esbuild?進(jìn)行預(yù)構(gòu)建依賴。esbuild 使用 Go 編寫,并且比以 JavaScript 編寫的打包器預(yù)構(gòu)建依賴快 10-100 倍。依賴預(yù)構(gòu)建主要做了什么呢?

    • 開發(fā)階段中,Vite 的開發(fā)服務(wù)器將所有代碼視為原生 ES 模塊。因此,Vite 必須先將作為 CommonJS 或 UMD 發(fā)布的依賴項(xiàng)轉(zhuǎn)換為 ESM
    • Vite 將有許多內(nèi)部模塊的 ESM 依賴關(guān)系轉(zhuǎn)換為單個(gè)模塊,以提高后續(xù)頁面加載性能。如果不編譯,每個(gè)依賴包里面都可能含有多個(gè)其他的依賴,每個(gè)引入的依賴都會(huì)又一個(gè)請求,請求多了耗時(shí)就多
  2. 按需編譯返回:Vite 以?原生 ESM?方式提供源碼。這實(shí)際上是讓瀏覽器接管了打包程序的部分工作:Vite 只需要在瀏覽器請求源碼時(shí)進(jìn)行轉(zhuǎn)換并按需提供源碼。根據(jù)情景動(dòng)態(tài)導(dǎo)入代碼,即只在當(dāng)前屏幕上實(shí)際使用時(shí)才會(huì)被處理。

Webpack 與 Vite 熱更新的區(qū)別

使用 Vite 的另外一個(gè)大的好處在于,它的熱更新也是非常迅速的。

我們首先來看看 Webpack 的熱更新機(jī)制:

  • 按需編譯返回:Vite 以?原生 ESM?方式提供源碼。這實(shí)際上是讓瀏覽器接管了打包程序的部分工作:Vite 只需要在瀏覽器請求源碼時(shí)進(jìn)行轉(zhuǎn)換并按需提供源碼。根據(jù)情景動(dòng)態(tài)導(dǎo)入代碼,即只在當(dāng)前屏幕上實(shí)際使用時(shí)才會(huì)被處理。

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

一些名詞解釋:

  • Webpack-complier:Webpack 的編譯器,將 Javascript 編譯成 bundle(就是最終的輸出文件)
  • HMR Server:將熱更新的文件輸出給 HMR Runtime
  • Bunble Server:提供文件在瀏覽器的訪問,也就是我們平時(shí)能夠正常通過 localhost 訪問我們本地網(wǎng)站的原因
  • HMR Runtime:開啟了熱更新的話,在打包階段會(huì)被注入到瀏覽器中的 bundle.js,這樣 bundle.js 就可以跟服務(wù)器建立連接,通常是使用 Websocket ,當(dāng)收到服務(wù)器的更新指令的時(shí)候,就去更新文件的變化
  • bundle.js:構(gòu)建輸出的文件

Webpack 熱更新的大致原理是,文件經(jīng)過 Webpack-complier 編譯好后傳輸給 HMR Server,HMR Server 知道哪個(gè)資源 (模塊) 發(fā)生了改變,并通知 HMR Runtime 有哪些變化,HMR Runtime 就會(huì)更新我們的代碼,這樣瀏覽器就會(huì)更新并且不需要刷新。

而 Webpack 熱更新機(jī)制主要耗時(shí)點(diǎn)在于,Webpack 的熱更新會(huì)以當(dāng)前修改的文件為入口重新 build 打包,所有涉及到的依賴也都會(huì)被重新加載一次

而 Vite 號稱?熱更新的速度不會(huì)隨著模塊增多而變慢。它的主要優(yōu)化點(diǎn)在哪呢?

Vite 實(shí)現(xiàn)熱更新的方式與 Webpack 大同小異,也通過創(chuàng)建 WebSocket 建立瀏覽器與服務(wù)器建立通信,通過監(jiān)聽文件的改變向客戶端發(fā)出消息,客戶端對應(yīng)不同的文件進(jìn)行不同的操作的更新。

Vite 通過?chokidar?來監(jiān)聽文件系統(tǒng)的變更,只用對發(fā)生變更的模塊重新加載,只需要精確的使相關(guān)模塊與其臨近的 HMR 邊界連接失效即可,這樣 HMR 更新速度就不會(huì)因?yàn)閼?yīng)用體積的增加而變慢而 Webpack 還要經(jīng)歷一次打包構(gòu)建。所以 HMR 場景下,Vite 表現(xiàn)也要好于 Webpack。

通過不同的消息觸發(fā)一些事件。做到瀏覽器端的即時(shí)熱模塊更換(熱更新)。通過不同事件,觸發(fā)更細(xì)粒度的更新(目前只有 Vue 和 JS,Vue 文件又包含了 template、script、style 的改動(dòng)),做到只更新必須的文件,而不是全量進(jìn)行更新。在些事件分別是:

  • connected: WebSocket 連接成功
  • vue-reload: Vue 組件重新加載(當(dāng)修改了 script 里的內(nèi)容時(shí))
  • vue-rerender: Vue 組件重新渲染(當(dāng)修改了 template 里的內(nèi)容時(shí))
  • style-update: 樣式更新
  • style-remove: 樣式移除
  • js-update: js 文件更新
  • full-reload: fallback 機(jī)制,網(wǎng)頁重刷新

本文不會(huì)在 Vite 原理上做太多深入,感興趣的可以通過官方文檔了解更多 --??為什么選 Vite | Vite 官方中文文檔

基于 Vite 的改造,相當(dāng)于在開發(fā)階段替換掉 Webpack,下文主要講講我們在替換過程中遇到的一些問題。

基于 Vue-cli 4 的 Vue2 項(xiàng)目改造,大致只需要:

  1. 安裝 Vite

  2. 配置 index.html(Vite 解析?<script type="module" src="...">?標(biāo)簽指向源碼)

  3. 配置 vite.config.js

  4. package.json 的?scripts?模塊下增加啟動(dòng)命令?"vite": "vite"

當(dāng)以命令行方式運(yùn)行?npm run vite時(shí),Vite 會(huì)自動(dòng)解析項(xiàng)目根目錄下名為?vite.config.js?的文件,讀取相應(yīng)配置。而對于?vite.config.js?的配置,整體而言比較簡單:

  1. Vite 提供了對 .scss, .sass, .less, 和 .stylus 文件的內(nèi)置支持

  2. 天然的對 TS 的支持,開箱即用

  3. 基于 Vue2 的項(xiàng)目支持,可能不同的項(xiàng)目會(huì)遇到不同的問題,根據(jù)報(bào)錯(cuò)逐步調(diào)試即可,譬如通過一些官方插件兼容?.tsx.jsx

當(dāng)然,對于項(xiàng)目的源碼,可能需要一定的改造,下面是我們遇到的一些小問題:

  1. tsx 中使用裝飾器導(dǎo)致的編譯問題,我們通過魔改了?@vitejs/plugin-vue-jsx,使其支持 Vue2 下的 jsx

  2. 由于 Vite 僅支持 ESM 語法,需要將代碼中的模塊引入方式由?require?改為?import

  3. Sass 預(yù)處理器無法正確解析樣式中的?/deep/,可使用?::v-deep?替換

  4. 其他一些小問題,譬如 Webpack 環(huán)境變量的兼容,SVG iCON 的兼容

對于需要修改到源碼的地方,我們的做法是既保證能讓 Vite 進(jìn)行適配,同時(shí)讓該改動(dòng)不會(huì)影響到原本 Webpack 的構(gòu)建,以便在關(guān)鍵時(shí)刻或者后續(xù)迭代能切回 Webpack

解決完上述的一些問題后,我們成功地將開發(fā)時(shí)基于 Webpack 的構(gòu)建打包遷移到了 Vite,效果也非常驚人,全模塊構(gòu)建耗時(shí)只有 2.6s

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

至此,開發(fā)階段的構(gòu)建耗時(shí)從原本的 4.5min 優(yōu)化到了 2.6s:

構(gòu)建模塊數(shù) 耗時(shí)
Webpack 冷啟動(dòng)全量構(gòu)建 20 個(gè)模塊 4.54min
Webpack 冷啟動(dòng)只構(gòu)建 1 個(gè)模塊 18s
Webpack 有緩存狀態(tài)下二次構(gòu)建 1 個(gè)模塊 4.5s
Vite 冷啟動(dòng) 2.6s

優(yōu)化生產(chǎn)構(gòu)建

好,上述我們基本已經(jīng)完成了整個(gè)開發(fā)階段的構(gòu)建優(yōu)化。下一步是優(yōu)化生產(chǎn)構(gòu)建。

我們的生產(chǎn)發(fā)布是基于 GitLab 及 Jenkins 的完整 CI/CD 流。

在優(yōu)化之前,看看我們的整個(gè)項(xiàng)目線上發(fā)布的耗時(shí):

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

可以看到,生產(chǎn)環(huán)境構(gòu)建時(shí)間較長, build 平均耗時(shí)約 9 分鐘,整體發(fā)布構(gòu)建時(shí)長在 15 分鐘左右,整體構(gòu)建環(huán)節(jié)耗時(shí)過長, 效率低下,嚴(yán)重影響測試以及回滾?。

好,那我們看看,整個(gè)構(gòu)建流程,都需要做什么事情:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

其中,?Build base?和?Build Region?階段存在較大優(yōu)化空間。

Build base?階段的優(yōu)化,涉及到環(huán)境準(zhǔn)備,鏡像拉取,依賴的安裝。前端能發(fā)揮的空間不大,這一塊主要和 SRE 團(tuán)隊(duì)溝通,共同進(jìn)行優(yōu)化,可以做的有增加緩存處理、外掛文件系統(tǒng)、將依賴寫進(jìn)容器等方式。

我們的優(yōu)化,主要關(guān)注?Build Region?階段,也就是核心關(guān)注如何減少?npm run build?的時(shí)間。

文章開頭有貼過?npm run build?的耗時(shí)分析,簡單再貼下:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

一般而言, 代碼編譯時(shí)間和代碼規(guī)模正相關(guān)。

根據(jù)以往優(yōu)化經(jīng)驗(yàn),代碼靜態(tài)檢查可能會(huì)占據(jù)比較多時(shí)間,目光鎖定在?eslint-loader?上。

在生產(chǎn)構(gòu)建階段,eslint 提示信息價(jià)值不大,考慮在 build 階段去除,步驟前置

同時(shí),我們了解到,可以通過?esbuild-loader?插件去替代非常耗時(shí)的 babel-loader、ts-loader 等 loader。

因此,我們的整體優(yōu)化方向就是:

  1. 改寫打包腳本,引入 esbuild 插件

  2. 優(yōu)化構(gòu)架邏輯,減少 build 階段不必要的檢查

優(yōu)化前后流程對比:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

優(yōu)化構(gòu)架邏輯,減少 build 階段不必要的檢查

這個(gè)上面說了,還是比較好理解的,在生產(chǎn)構(gòu)建階段,eslint 提示信息價(jià)值不大,考慮在 build 階段去除,步驟前置。

比如在?git commit?的時(shí)候利用?lint-staged?及?git hook?做檢查, 或者利用 CI 在?git merge?的時(shí)候加一條流水線任務(wù),專門做靜態(tài)檢查。

我們兩種方式都有做,簡單給出接入 Gitlab CI 的代碼:

// .gitlab-ci.yml
stages:
  - eslint

eslint-job:
  image: node:14.13.0
  stage: eslint
  script:
    - npm run lint 
    - echo 'eslint success'
  retry: 1
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "test"'

通過?.gitlab-ci.yml?配置文件,指定固定的時(shí)機(jī)進(jìn)行 lint 指令,前置步驟。

改寫打包腳本,引入 esbuild 插件

這里,我們主要借助了?esbuild-loader。

上面其實(shí)我們也有提到 esbuild,Vite 使用 esbuild 進(jìn)行預(yù)構(gòu)建依賴。這里我們借助的是 esbuild-loader,它把 esbuild 的能力包裝成 Webpack 的 loader 來實(shí)現(xiàn) Javascript、TypeScript、CSS 等資源的編譯。以及提供更快的資源壓縮方案。

接入起來也非常簡單。我們的項(xiàng)目是基于 Vue CLi 的,主要修改?vue.config.js,改造如下:

// vue.config.js
const { ESBuildMinifyPlugin } = require('esbuild-loader');

module.exports = {
  // ...

  chainWebpack: (config) => {
    // 使用 esbuild 編譯 js 文件
    const rule = config.module.rule('js');

    // 清理自帶的 babel-loader
    rule.uses.clear();

    // 添加 esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        loader: 'ts', // 如果使用了 ts, 或者 vue 的 class 裝飾器,則需要加上這個(gè) option 配置, 否則會(huì)報(bào)錯(cuò): ERROR: Unexpected "@"
        target: 'es2015',
        tsconfigRaw: require('./tsconfig.json')
      })

    // 刪除底層 terser, 換用 esbuild-minimize-plugin
    config.optimization.minimizers.delete('terser');

    // 使用 esbuild 優(yōu)化 css 壓縮
    config.optimization
      .minimizer('esbuild')
      .use(ESBuildMinifyPlugin, [{ minify: true, css: true }]);
  }
}

移除 ESLint,以及接入 esbuild-loader 這一番組合拳打完,本地單次構(gòu)建可以優(yōu)化到 90 秒。

階段 耗時(shí)
優(yōu)化前 200S
移除 ESLint、接入 esbuild-loader 90S

再看看線上的 Jenkins 構(gòu)建耗時(shí),也有了一個(gè)非常明顯的提升:

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

前端工程化的演進(jìn)及后續(xù)規(guī)劃

整體而言,上述優(yōu)化完成后,對整個(gè)項(xiàng)目的打包構(gòu)建效率是有著一個(gè)比較大的提升的,但是這并非已經(jīng)做到了最好。

看看我們旁邊兄弟組的 Live 構(gòu)建耗時(shí):

前端構(gòu)建效率優(yōu)化之路,前端,javascript,webpack,node.js

在項(xiàng)目體量差不多的情況下,他們的生產(chǎn)構(gòu)建耗時(shí)(npm run build)在 2 分鐘出頭,細(xì)究其原因在于:

  1. 他們的項(xiàng)目是 React + TSX,我這次優(yōu)化的項(xiàng)目是 Vue,在文件的處理上就需要多過一層?vue-loader;

  2. 他們的項(xiàng)目采用了微前端,對項(xiàng)目對了拆分,主項(xiàng)目只需要加載基座相關(guān)的代碼,子應(yīng)用各自構(gòu)建。需要構(gòu)建的主應(yīng)用代碼量大大減少,這是主要原因;

是的,后續(xù)我們還有許多可以嘗試的方向,譬如我們正在做的一些嘗試有:

  1. 對項(xiàng)目進(jìn)行微前端拆分,將相對獨(dú)立的模塊拆解出來,做到獨(dú)立部署

  2. 基于 Jenkinks 構(gòu)建時(shí),在?Build Base?階段優(yōu)化的提升,譬如將構(gòu)建流程前置,結(jié)合 CDN 做快速回滾,以及將依賴預(yù)置進(jìn) Docker 容器中,減少在容器中每次?npm install?時(shí)間的消耗等

同時(shí),我們也必須看到,前端技術(shù)日新月異,各種構(gòu)建工具目不暇給。前端從最早期的刀耕火種,到逐步向工程化邁進(jìn),到如今的泛前端工程化囊括的各式各樣的標(biāo)準(zhǔn)、規(guī)范、各種提效的工具。構(gòu)建效率優(yōu)化可能會(huì)處于一種一直在路上的狀態(tài)。當(dāng)然,這里不一定有最佳實(shí)踐,只有最適合我們項(xiàng)目的實(shí)踐,需要我們不斷地去摸索嘗試。文章來源地址http://www.zghlxwxcb.cn/news/detail-836894.html

到了這里,關(guān)于前端構(gòu)建效率優(yōu)化之路的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • AJAX入門到實(shí)戰(zhàn),學(xué)習(xí)前端框架前必會(huì)的(ajax+node.js+webpack+git)(七)

    AJAX入門到實(shí)戰(zhàn),學(xué)習(xí)前端框架前必會(huì)的(ajax+node.js+webpack+git)(七)

    實(shí)操: server.js utils/lib/index.js utils/package.json 從別處(網(wǎng)上、其他人手中)拿到寫好的項(xiàng)目,一般不攜帶node_modules文件夾(所占存儲(chǔ)空間大) 但有package.json文件,里面記載了當(dāng)前項(xiàng)目下載過的包 還有package-lock.json文件,固定軟件包的版本 導(dǎo)入模塊/包,除了自己創(chuàng)建的模塊、包

    2024年01月22日
    瀏覽(67)
  • 前端構(gòu)建工具 代碼優(yōu)化壓縮 模塊管理 依賴管理 資源處理轉(zhuǎn)換 自動(dòng)化任務(wù) 流程優(yōu)化 高級特性 Webpack Parcel Rollup Gulp 靜態(tài)資源

    前端構(gòu)建在前端開發(fā)中具有重要的意義,主要有以下幾個(gè)方面: 代碼優(yōu)化和壓縮:前端構(gòu)建工具可以對前端代碼進(jìn)行優(yōu)化和壓縮,例如去除注釋、空格,合并和縮小文件大小等。這可以減少文件的加載時(shí)間和傳輸大小,提高網(wǎng)頁加載速度,優(yōu)化用戶體驗(yàn) 模塊管理和依賴管理

    2024年02月09日
    瀏覽(21)
  • Node.js npm V8 React Express的運(yùn)行配合關(guān)系:構(gòu)建JavaScript應(yīng)用的基石

    目錄 Node.js 和 V8 引擎 Node.js 和 npm LTS(Long Term Support) React Node.js的作用 Express Node.js 和 V8 引擎 Node.js 使用 Google 的 V8 JavaScript 引擎 來執(zhí)行 JavaScript 代碼。V8 是一個(gè)高性能的 JavaScript 和 WebAssembly 引擎,用于在 Google Chrome 瀏覽器和 Node.js 中運(yùn)行 JavaScript。 V8 引擎的更新 通常包括

    2024年03月12日
    瀏覽(18)
  • AJAX入門到實(shí)戰(zhàn),學(xué)習(xí)前端框架前必會(huì)的(ajax+node.js+webpack+git)(五)—— 項(xiàng)目-新聞?lì)^條-數(shù)據(jù)管理平臺(tái)-ajax綜合案例前端

    AJAX入門到實(shí)戰(zhàn),學(xué)習(xí)前端框架前必會(huì)的(ajax+node.js+webpack+git)(五)—— 項(xiàng)目-新聞?lì)^條-數(shù)據(jù)管理平臺(tái)-ajax綜合案例前端

    愿許秋風(fēng)知我意,解我心中意難平。 推薦使用, 每個(gè)程序員都有自己的管理方式。 HTML結(jié)構(gòu): 1.為什么要提取公共前綴地址(基地址),因?yàn)楣緲I(yè)務(wù)可能會(huì)更換服務(wù)器,如果你不想一條一條地修改請求地址的話。 后續(xù)使用axios時(shí),url不需要再寫前綴。 2.請求成功與失敗 成

    2024年01月25日
    瀏覽(24)
  • 前端10年進(jìn)化 Node.js、模塊化、CommonJS、AMD、CMD、Webpack、Vue-cli、Electron-vue

    模塊化的概念在軟件開發(fā)領(lǐng)域已經(jīng)存在很長時(shí)間,但在?JavaScript?中的模塊化發(fā)展相對較晚。以下是對您提出的問題的回答: 提出時(shí)間:JavaScript?中的模塊化概念相對較早地提出于?CommonJS?規(guī)范。CommonJS?是一種?JavaScript?模塊化規(guī)范,最早在?2009?年由?Ryan?Dahl?和其他社區(qū)成

    2024年02月11日
    瀏覽(25)
  • 前端Vue Node.js + Express + MongoDB 構(gòu)建的后端服務(wù)API接口

    構(gòu)建一個(gè)使用 Vue.js 作為前端, Node.js + Express + MongoDB 作為后端服務(wù)的全棧應(yīng)用涉及到多個(gè)步驟。這里簡要概述整個(gè)過程,并提供一些基本的代碼示例來幫助你開始。 安裝 MongoDB: 根據(jù)你的操作系統(tǒng)從 MongoDB 官網(wǎng) 下載并安裝 MongoDB。 啟動(dòng) MongoDB 服務(wù): 安裝完成后,根據(jù) MongoDB 的

    2024年04月14日
    瀏覽(42)
  • WebPack優(yōu)化
Webpack構(gòu)建速度優(yōu)化

    WebPack優(yōu)化 Webpack構(gòu)建速度優(yōu)化

    目錄 1 常用的loader和plugin 2 WebPack多入口配置: 3?如何抽離壓縮css文件 4 webpack如何抽離公共代碼和第三方代碼 ?5 webpack如何實(shí)現(xiàn)異步加載JS (懶加載) 6? module chunk bundle 的區(qū)別 7??webpack優(yōu)化構(gòu)建速度 hard-source-webpack-plugin 8 webpack 優(yōu)化產(chǎn)出代碼 9 什么是Tree-Shaking 10 ES6 Module和 Commo

    2024年02月11日
    瀏覽(29)
  • 【萬字解析】Webpack 優(yōu)化構(gòu)建性能(分析->優(yōu)化)

    全局安裝 webpack-bundle-analyzer 插件 運(yùn)行 webpack-bundle-analyzer 開始打包,需要獲取所有的依賴模塊 搜索所有的依賴項(xiàng),這需要占用一定的時(shí)間,即搜索時(shí)間,那么就確定了: 需要優(yōu)化的第一個(gè)時(shí)間就是 搜索時(shí)間 。 解析所有的依賴模塊(解析成瀏覽器可運(yùn)行的代碼) Webpack 根據(jù)

    2024年01月21日
    瀏覽(48)
  • Node.js與Webpack筆記(二)

    Node.js與Webpack筆記(二)

    上一篇:Node.js與Webpack筆記(一)-CSDN博客 1.Webpack簡介以及體驗(yàn) webpack是一個(gè)靜態(tài)模塊打包工具,從入口構(gòu)建依賴圖,打包有關(guān)的模塊,最后用于展示你的內(nèi)容 靜態(tài)模塊:編寫代碼過程中,html,css,js,圖片等固定內(nèi)容的文件 打包過程,注意:只有和入口有直接/間接引入關(guān)系

    2024年03月10日
    瀏覽(26)
  • 第三節(jié):Node.js 之 Webpack 打包

    第三節(jié):Node.js 之 Webpack 打包

    官網(wǎng)網(wǎng)址:https://webpack.docschina.org/ 減少文件數(shù)量,縮減代碼體積,提高瀏覽器打開速度。 用于分析、并打包代碼。支持所有類型文件的打包,其本質(zhì)是一個(gè)第三方模塊包。 初始化包環(huán)境 安裝依賴包 配置package.json 的 scripts(自定義命令) 在根目錄下新建 src 文件夾, 所有要

    2024年02月15日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包