我們從 UmiJS 遷移到了 Vite

大家好,我是若川。最近組織了源碼共讀活動,感興趣的可以點此加我微信ruochuan12?進群參與,每周大家一起學習200行左右的源碼,共同進步。已進行三個月了,很多小伙伴表示收獲頗豐。

我們從 UmiJS遷移到 Vite 已經上線半年多了。遷移過程中也遇到了不少問題,好在 Vite 足夠優秀,繼承自 Rollup 的插件系統,使我們有了自由發揮空間。目前很多人對 Vite 躍躍欲試,Vite 開發體驗到底怎么樣,今天來敘敘遷移到 Vite 的親身經歷。

先說結論,Vite 已經很成熟,強烈建議有條件的可以從 webpack 遷移過來。

為什么要放棄 UmiJS

2019 年底,在 Webpack 橫行霸道,各種腳手架琳瑯滿目的時代選擇了 UmiJS。它配置少、功能多、文檔齊全、持續更新。一整套的解決方案,非常適合一個大部分非 React 技術棧的團隊。經過不斷地磨合,團隊很快適應了這種 React 開發模式,開發效率也是水漲船高。

凡事總有個原因,為什么要遷移。2021 年初,為適應公司的發展,前端架構也需要做調整與升級。在項目日益增長的情況下,一次項目啟動需要耗費一分多鐘,熱更新也慢得基本無法使用。差點的機器配置啟動項目要么好幾分鐘、要么內存溢出。這種模式極大地降低了開發效率。無論是自定義修改內部 webpack 插件、從各種角度如多核編譯、緩存等方式優化,依然是杯水車薪。雖然 UmiJS 提供了 webpack5 插件,不過在當時處于不可用的狀態。

我們主要的矛盾是:

  1. 啟動時間長

  2. 熱更新慢

  3. 太臃腫

  4. 框架 BUG 修復不及時

  5. 過度封裝,自定義插件難度大

  6. 約定式功能太單一

適應業務的要求,我們也需要上微前端。UmiJS 也提供了微前端插件 “乾坤”。但依然解決不了根本開發體驗問題。因此,在基礎腳手架上,我們尋求更多的是可控性及透明性。(盡管UmiJS?現在已經支持Module Federation 的打包提速方案)

為什么是 Vite

市面上的腳手架很多,陣營卻很少,大部分是基于 webpack 的上層封裝。webpack 的缺點很明顯,當冷啟動開發服務器時,基于打包器的方式啟動必須優先抓取并構建你的整個應用,然后才能提供服務。

025db80adc63551efc8ae9162a42fb45.png

在瀏覽器 ESM 支持得很普遍得今天,Vite 這種可以稱得上是下一代前端開發與構建工具。在 Vite 中,HMR 是在原生 ESM 上執行的。當編輯一個文件時,無論應用大小如何,HMR 始終能保持快速更新。

329770296b08f7f5e78440b85be3efd3.png

Vite 這種方式在我們習慣 webpack 的陰影下顯得尤為驚艷,可以說 Vite 完美地解決了我們所有的痛點。不過 Vite 也是剛發布 2.0 不久,踩過坑的人也是相當少。我們便試試 Vite

前期調研

遷移的必要條件是在原有的功能下找到替代方案,我們便統計用到了 UmiJS 中的 API 及特性

UmiJS 配置

  • alias - 配置別名(對應 resolve.alias)

  • base - 設置路由前綴(對應 base)

  • define - 用于提供給代碼中可用的變量(對應 define)

  • outputPath - 指定輸出路徑(對應 build.outDir)

  • hash - 配置是否讓生成的文件包含 hash 后綴 (Vite 自帶)

  • antd - 整合 antd 組件庫 (無需框架提供,Vite 中可自己引用)

  • dva - 整合 dva 數據流(此庫已經很久沒有更新了,在 hooks 時代使用顯得格格不入。我們沒有大量使用,重寫一個文件很輕松)

  • locale - 國際化插件,用于解決 i18n 問題(需要自己實現國際化邏輯,都是基于 react-intl 封裝,在 Vite 中實現無壓力)

  • fastRefresh - 快速刷新(對應 @vitejs/plugin-react-refresh 插件)

  • dynamicImport - 是否啟用按需加載(路由級的按需加載,在 Vite 中用 React.lazy 封裝)

  • targets - 配置需要兼容的瀏覽器最低版本(對應 @vitejs/plugin-legacy 插件)

  • theme - 配置 less 變量(對應 css.preprocessorOptions.less.modifyVars 配置)

  • lessLoader - 設置 less-loader 配置項(與 theme 配置相同)

  • ignoreMomentLocale - 忽略 moment 的 locale 文件(可以通過 alias 設置別名方式解決)

  • proxy - 配置代理能力(對應 server.proxy)

  • externals - 設置哪些模塊可以不被打包(對應 build.rollupOptions.external)

  • copy - 設置要復制到輸出目錄的文件或文件夾(對應 rollup-plugin-copy)

  • mock - 配置 mock 屬性(對應 vite-plugin-mock)

  • extraBabelPlugins - 配置額外的 babel 插件(對應 @rollup/plugin-babel)

通過配置分析,基本上所有的 UmiJS 配置都可以在 Vite 中找到替代方案。除了配置還有一些約定

UmiJS 中 @/* 路徑,代替方式

defineConfig({resolve: {alias: {'@/': `${path.resolve(process.cwd(), 'src')}/`,},},
});

遷移

Review 現有的代碼,找出可能出問題的點并統計。做前期準備。跑起來優先:

從頭 Vite 官方模板中創建一個項目,安裝所需依賴包。UmiJS 內置封裝了 react-routerantd react-intl,這里我們需要手動加上 BrowserRouterConfigProviderLocaleProvider

// App.tsx
export default function App() {return (<AppProvider><BrowserRouter><ConfigProvider locale={currentLocale}><LocaleProvider><BasicLayout><Routes /></BasicLayout></LocaleProvider></ConfigProvider></BrowserRouter></AppProvider>);
}

根據之前約定式路由,添加相應的路由配置

export const basicRoutes = [{path: '/',exact: true,trunk: () => import('@/pages/index'),},{path: '/login',exact: true,trunk: () => import('@/pages/login'),},{path: '/my-app',trunk: () => import('@/pages/my-app'),},// ...
];

路由渲染組件,通過 React.lazy 實現 UmiJS 中的 dynamicImport

const routes = basicRoutes.map(({ trunk, ...config }) => {const Trunk = React.lazy(() => trunk());return {...config,component: (<React.Suspense fallback={<Spinner />}><Trunk /></React.Suspense>),};
});export default function Routes() {return (<Switch>{routes.map((route) => (<Route key={route.key || route.path} path={route.path} exact={route.exact} render={() => route.component} />))}</Switch>);
}

從原先的約定式路由遷移完成,項目中主要不兼容的地方就是從 umi 導入的成員

import { useIntl, history, useLocation, useSelector } from 'umi';

我們需要將所有 umi 中導入的變量,通過編輯器的正則替換批量修改替換。

  • 國際化的 useIntl 通過將語言文件和 react-intl 封裝,導出一個全局的 formatMessage 方法

  • 路由相關的 API 用 react-router-dom 導出替換

  • Redux 相關的,用 react-redux 導出替換

  • 查找項目中使用 require 的地方,替換為動態 import

  • 查找項目中使用 process.env.NODE_ENV,替換為 import.meta.env.DEV,因為再 Vite 中不再有 node.js 相關的 API

antd 添加進項目后,發現 babel-plugin-import 對應的 Vite 插件似乎有問題,某些樣式在 dev 模式下缺失,打包后正常。排查發現是組件包里面引用了 antd,在 dev 模式下包名被“依賴預構建” 混淆,導致插件無法正確插入 antd 的樣式。為此,我們自己寫了個插件,在 dev 模式下全量引入樣式,prod 才走插件。

很輕松,第一個頁面成功運行。

由于遷移之后需要使用微前端,因此我們將公共配置通過外置插件統一管理。

export default defineConfig({server: {// 每個項目配置不同的端口號port: 3001,},plugins: [reactRefresh(),// 公共配置插件baseConfigPlugin(),// AntD 插件antdPlugin(),],
});

遷移后發現 Vite 需要配置的其實很少,抽取的公共配置,封裝成 Vite 插件。

import path from 'path';
import LessPluginImportNodeModules from 'less-plugin-import-node-modules';export default function vitePluginBaseConfig(config: CustomConfig): Plugin {return {enforce: 'post',name: 'base-config',config() {return {cacheDir: '.vite',resolve: {alias: {'@/': `${path.resolve(process.cwd(), 'src')}/`,lodash: 'lodash-es','lodash.debounce': 'lodash-es/debounce','lodash.throttle': 'lodash-es/throttle',},},server: {host: '0.0.0.0',},css: {preprocessorOptions: {less: {modifyVars: {'@primary-color': '#f99b0b',...config.theme,// 自定義 ant 前綴'@ant-prefix': config.antPrefix || 'ant',},plugins: [new LessPluginImportNodeModules()],javascriptEnabled: true,},},},};},};
}

遷移的整個過程沒有想象中那么繁雜,反而相對容易。幾乎常用的功能 Vite 都有方案支持,這也許是 Vite 的厲害之處吧。其實本質上的復雜度在于業務,項目的復雜度就是代碼量的體現,通過 IDE 的搜索替換,很快便完成了遷移并成功的運行。

現在,我們所有的項目都基于 Vite,完全沒有了等待而摸魚的煩惱。

問題/解決

轉換 less 文件 @import '~antd/es/style/themes/default.less' 中的 ~ 別名報錯

配置 less 插件less-plugin-import-node-modules

SyntaxError: The requested module 'xxx' does not provide an export named 'default'

我們將公共組件作為獨立的 npm 包之后使用時遇到的錯誤。本想著公共組件包自己不編譯,統一交給使用方編譯。所以導出了 TS 源文件。而這種情況常規下沒有問題,Vite 一旦遇到 CommonJSUMD 的包才導致無法解析。雖然可以將無法解析的包放入 optimizeDeps.include 。但是架不住包的數量多啊,還是將它 tsc 轉譯為 JS 文件再發布。

打包提速

首次打包發現需要 70 多秒,我們來優化打包結構

  • 通過 build.minify 改為 esbuild(最新版 Vite 已經默認 esbuild) 。Esbuildterser 快 20-40 倍,壓縮率只差 1%-2%。開啟后降低到 30 多秒

  • babel-plugin-import 的類似 babel 插件嚴重拖后腿,總共不到 40 秒的時間,它就要占 10 秒。我們通過正則的方式做了個插件,完美解決

  • 通過分析 rollup@ant-design/iconslodash 包的 transform 數量非常多。我們將這些包也加入到剛剛做的插件中

通過一頓操作下來,提速到 16 秒,先這樣吧。

為什么將 cacheDir 放在根目錄

cacheDir 作為存儲緩存文件的目錄。此目錄下會存儲預打包的依賴項或 vite 生成的某些緩存文件,使用緩存可以提高性能。在某些情況下需要聯調 node_modules 里包,從而導致修改后未生效。這時需要使用 --force 命令行選項或手動刪除目錄,放在根目錄便于刪除。

兼容性問題

Vite 的兼容性可以通過官方的插件 @vitejs/plugin-legacy 解決。我們已經放棄支持 IE 11,無限制在生產使用 ESM,羨慕嗎?

結語

如果你是新的項目,完全不必考慮 Webpack 了,Viterollup 的完全生態足夠支撐上生產。如果你是 Webpack 生態老項目,不忍體驗上的折磨,滿足遷移條件的話,不妨試試 Vite,肯定會帶給你驚喜。

后面我會分享 Vite 和自己實現的微前端搭配組合,以及Vite?相關的插件,請持續關注。


最近組建了一個湖南人的前端交流群,如果你是湖南人可以加我微信?ruochuan12?私信 湖南 拉你進群。

推薦閱讀

1個月,200+人,一起讀了4周源碼
我歷時3年才寫了10余篇源碼文章,但收獲了100w+閱讀

老姚淺談:怎么學JavaScript?

我在阿里招前端,該怎么幫你(可進面試群)

c6018231e99dddb535d8b6f33bff6ace.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》10余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助1000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

f452ebba7ed3a85aeaf1a476f2340dd5.png

識別方二維碼加我微信、拉你進源碼共讀

今日話題

略。分享、收藏、點贊、在看我的文章就是對我最大的支持~

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

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

相關文章

將DataTable的內容以EXCEl的形式導出到本地

1.在搞項目的時候一般會遇到&#xff0c;將GridView或者Repeater的內容以Excel的形式保存到本地&#xff0c;即導出功能。我總結了兩個方法。 方法一&#xff1a; 1 DataTable dt query.GetItems().GetDataTable();2 if (dt ! null)3 {4 …

智能家居數據庫設計_設計更智能的數據表

智能家居數據庫設計重點 (Top highlight)Data tables are hard. There are many different ways to think about them. So, naturally, the first step would be to figure out what your users need.數據表很難。 有許多不同的方式來考慮它們。 因此&#xff0c;自然地&#x…

可能是全網首個前端源碼共讀活動,誠邀你加入一起學習

大家好&#xff0c;我是若川。眾所周知&#xff0c;從8月份開始&#xff0c;我組織了源碼共讀活動&#xff0c;每周學習200行左右的源碼&#xff0c;到現在持續了3個多月&#xff0c;堅持答疑解惑。幫助了不少人&#xff0c;還是挺開心的。另外&#xff0c;涌現了很多優秀的讀者…

vsftpd 的配置項目

基本配置說明&#xff1a; 1&#xff09;local_root/ftpfile(當本地用戶登入時&#xff0c;將被更換到定義的目錄下&#xff0c;默認值為各用戶的家目錄) 2&#xff09;anon_root/ftpfile(使用匿名登入時&#xff0c;所登入的目錄) 3&#xff09;use_localtimeYES(默認是GMT時…

線段樹專輯——pku 3667 Hotel

http://poj.org/problem?id3667 哈哈&#xff0c;經典中的經典題啊。利用線段樹求最大連續空閑區間&#xff0c;并返回空閑區間的起點坐標。 View Code 1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 using namespace std; 5 6 …

houseparty不流暢_重新設計Houseparty –用戶體驗案例研究

houseparty不流暢Houseparty has become very popular during the COVID-19 period because it helps you connect with others in a fun way. The concept is simple, you open the app and jump on a video call with your friends. You can even play online games with the…

你不知道的 Node.js 工具函數

從類型判斷說起在 JavaScript 中&#xff0c;進行變量的類型校驗是一個非常令人頭疼的事&#xff0c;如果只是簡單的使用 typeof 會到各種各樣的問題。舉幾個簡單的&#x1f330;&#xff1a;console.log(typeof null) // object console.log(typeof new Array) // object cons…

Java應用集群下的定時任務處理方案(mysql)

今天來說一個Java多機部署下定時任務的處理方案。 需求: 有兩臺服務器同時部署了同一套代碼&#xff0c; 代碼中寫有spring自帶的定時任務&#xff0c;但是每次執行定時任務時只需要一臺機器去執行。 當拿到這個需求時我腦子中立馬出現了兩個簡單的解決方案&#xff1a; 利用ip…

概念驗證_設置成功的UX概念驗證

概念驗證用戶體驗/概念證明/第1部分 (USER EXPERIENCE / PROOF OF CONCEPT / PART 1) This is the first article of a four-part series. Please read Part 2 and Part 3.這是由四個部分組成的系列文章的第一篇。 請閱讀 第2 部分 和 第3部分 。 How do today’s top UX desi…

從 vue3 和 vite 源碼中,我學到了一行代碼統一規范團隊包管理器的神器

1. 前言大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。已進行四個月了&#xff0c;很多小伙伴表示收獲頗豐。想學源碼&#xff0c;極力推薦之前我寫…

什么事接口

假設你設計一個和人交流的程序。 先建立一個接口 interface 人 //定義接口&#xff0c;它代表一個人&#xff0c; {void Hello(); }//接口虛函數&#xff0c;用來跟這個人說話 但不同的人有不用的交流方式&#xff0c;具體方式用類來實現&#xff0c;比如。 class 美國人&#…

6個高效辦公的Excel小技巧,學會讓你高效辦公

很多人在做Excel表格的時候&#xff0c;會出現下面這種情況&#xff1a;好不容易把內容都輸入好了&#xff0c;才發現文字或是數字的排列組合需要重新調整&#xff0c;這個時候頭就大了&#xff0c;到底是要一個個復制黏貼&#xff0c;還是要刪除后再添加&#xff1f;不管哪種方…

unity 完美像素_像素完美

unity 完美像素從Kidpix到設計系統 (From Kidpix to design systems) Did you ever create stamps in KidPix? Kidpix is bitmap drawing software that’s been around since the nineties, and I remember many happy — more like maddening — hours creating tiny pixela…

整整4個月了,盡全力組織了源碼共讀活動~

大家好&#xff0c;我是若川。從8月份到現在11月結束了。每周一期&#xff0c;一起讀200行左右的源碼&#xff0c;撰寫輔助文章&#xff0c;截止到現在整整4個月了。由寫有《學習源碼整體架構系列》20余篇的若川【若川視野公眾號號主】傾力組織&#xff0c;召集了各大廠對于源碼…

kvm 學習(二)

Linux下 如何通過命令行使用現有的鏡像創建、啟動kvm虛擬機 這里假定已經創建好了相應的鏡像&#xff1a; eg&#xff1a;我這里制作的鏡像名稱為zu1-centos7.img # lszu1-centos7.img 1、拷貝這個鏡像到某一個目錄 cp zu1-centos7.img /data2/ 2、編寫鏡像的配置文件&#x…

字節內部前端開發手冊(完整版)開放下載!

備戰2022&#xff0c;準備好了嗎&#xff1f;據字節HR部門發布的最新信息&#xff0c;2019年以來字節連續3年擴招&#xff0c;而即將到來的2022年春招前端崗位數不低于3000&#xff0c;雖連年擴招&#xff0c;但是報錄比卻從2019年的3%下降到今年的1%。BAT等一線大廠同樣有類似…

EBS中Java并發程序筆記(1)

在Oracle EBS中的Java并發程序&#xff08;Java Concurrent Program&#xff09;是系統功能中的一個亮點&#xff0c;它的出現使得用戶可以在ERP系統中運行自己定義的Java程序。本文為學習筆記&#xff0c;所以不會介紹太多背景知識。 使用Java并發程序的好處&#xff1a; 當遇…

figma設計_5位來自雜亂無章的設計師的Figma技巧

figma設計When starting a design project, a fast pace and multiple design iterations can easily lead to a cluttered mess. Taking the time in the beginning to build good organizational habits will save you time later. You’ll thank your past self when you do…

hello,你知道獲取元素有哪幾種方式嗎?

收下我的小心心&#xff01;&#xff08;害羞臉&#xff09; 根據id屬性的值獲取元素&#xff0c;返回來的是一個元素對象 document.getElementById("id屬性的值") 根據標簽名獲取元素&#xff0c;返回來的是一個偽數組&#xff0c;里面保存了多個的DOM對象 documen…

設計和實現一個 Chrome 插件提升登錄效率

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以點此加我微信ruochuan12 進群參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。已進行4個月了&#xff0c;很多小伙伴表示收獲頗豐。前言在我們的工作過程中&#xff0c;每當…