# React 優化項目(四): Router Lazy Loading ###### tags: `React` `Optimize` `Router` `LazyLoading` > [time=Thu, Feb 3, 2022 5:55 PM] 只加載當前需要用到的頁面 bundle,路由懶加載 Lazy Loading, 先來看看在專案 build 完後並且本地啟動所需要加載的東西 ``` $ yarn build // 執行打包 $ yarn global add serve // 安裝全局 server $ serve -s build // 啟動剛剛打包完的專案 ``` :::info [關於 CRA 打包後的產物可以參考這裡 >>](https://hackmd.io/@yellow/rysIz5v0t) ::: 開啟動 server 後可以在 JS 中看到第一次訪問時就載入了所有東西,裡面包含所有頁面套件及必要執行的依賴。 但是對使用者來說,當下的網路速度會決定他載入的時間,當網路太慢就會影響到使用者體驗。 而能不能當使用者需要時在跟網路請求檔案呢? ![](https://i.imgur.com/JCSoe06.png) <br /> ## 使用 Lazy Loading 動態加載當前頁面的 bundle 主要使用這兩個做改寫 - `React.lazy(() => import('...'))` - `<Suspense />` 原先的寫法,把頁面 import 進來並且定義路由位置 現在將 import 的部分使用 `React.lazy` 改寫 ``` // 原先使用 import 的方法 // import MainLayout from './layout/MainLayout'; // import Welcome from './view/Welcome'; // import HookTry from './view/HookTry'; // import RouterTry from './view/RouterTry'; // 使用 React.lazy 改寫 const Welcome = React.lazy(() => import('./view/Welcome')); const HookTry = React.lazy(() => import('./view/HookTry')); const RouterTry = React.lazy(() => import('./view/RouterTry')); ... const App = () => ( <BrowserRouter> <Switch> <Route path="/" exact> <Redirect to="/welcome" /> </Route> <Route path="/welcome" exact> <Welcome /> </Route> <Route path="/routerTry"> <RouterTry /> </Route> <Route path="/hookTry"> <HookTry /> </Route> </Switch> </BrowserRouter> ); ``` 但執行畫面卻報錯 >> ![](https://i.imgur.com/JVKKkB4.png) 這個問題是改成需要時才與網路請求下載,中間會有等待時間,下載完才能加載檔案,而中間的等待就需要使用 `<Suspense>` 做處理。 ``` import React, { Suspense } from 'react'; ... const App = () => ( <BrowserRouter> <Suspense fallback={<p>Loading...</p>}> <Switch> <Route path="/" exact> <Redirect to="/welcome" /> </Route> <Route path="/welcome" exact> <Welcome /> </Route> <Route path="/routerTry"> <RouterTry /> </Route> <Route path="/hookTry"> <HookTry /> </Route> </Switch> </Suspense> </BrowserRouter> ); ``` ### 驗收 觀察 JS 在入切換不同頁面時 ![](https://i.imgur.com/IE72O6E.png) 可以看到原本 bundle 跟 vendor 包不見了,變成隨機的 xxx.chunk.js,main.chunk.js 也變小了。 現在點選不同頁面會發現每點選一頁就會加載一個檔案 實現了懶加載功能了 ![](https://i.imgur.com/FAg7yNz.png) 專案裡面可能有十幾頁,但是使用者可能常用到的只有2~3頁,使用懶加載就能避免把所有頁面都下載下來,提高了使用效能,避免在網路不好的時候還需要下載不必要的檔案。 <br /> ## 調整寫法 新增 `lazyLoadView fun` ```javascript ... const lazyLoadView = (view) => { const LazyView = React.lazy(() => import(/* webpackChunkName: "view-[request]" */ `@VIEW/${view}`)); return <LazyView />; }; ... // 使用 <Route path="/routerTry">{lazyLoadView('RouterTry')}</Route> <Route path="/hookTry">{lazyLoadView('HookTry')}</Route> <Route path="/renderTry">{lazyLoadView('RenderTry')}</Route> ... ``` 這邊要注意的是 `import` 的註解處 `webpackChunkName`,預設是輸出數字較不直覺,可以直接定義 `webpackChunkName`,而`view-` 是自定義 string 後面接的 `[request]` 是 webpack 根據 filename 來定義的值 ![](https://i.imgur.com/ICi7KFx.png) [Webpack](https://webpack.js.org/api/module-methods/#magic-comments) 最後 `@VIEW/${view}` 是利用 craco 的 alias 定義的 [如何設定可以看這裡 >>](https://hackmd.io/@yellow/S1mlj0yCK) ### 驗收輸出 進行打包後,出來的包就會長這樣: ``` ... 363 B build/static/js/view-RouterTry.33c2577e.chunk.js 310 B build/static/js/view-HookTry.69a08fb5.chunk.js 310 B build/static/js/view-RenderTry.69a08fb5.chunk.js ```