首頁 > 軟體

umi外掛開發仿dumi專案實現基礎路由解析

2023-01-28 18:02:37

實現過程

umi預設約定在/src/pages新增的(j|t)sx?檔案會自動載入為路由。同樣我們希望實現在某個目錄下新增的markdown檔案自動載入成為路由直接存取,本章我們首先來實現路由自動解析及頁面展示的功能。

  • 約定/docs目錄為markdown解析目錄
  • 新增路由解析外掛,
  • 解析/docs目錄下檔案為路由
  • 通過自動解析的路由存取頁面

本節完整程式碼可參考 domi/feature/routes

新增路由載入外掛

我們約定在專案根目錄下/docs目錄為markdown自動載入目錄,先建立這個目錄

mkdir /docs

在剛建立的/docs目錄下新增兩個元件,用於驗證解析效果

// /docs/index.tsx
import react from 'react'
const Home = () => {
    return (<div>hello domi</div>)
}
export default Home
// /docs/button/index.tsx
import react from 'react'
const Button = () => {
    return <button>Button</button>
}
export default Button

接下來建立路由解析外掛,外掛我們統一放在/src/features目錄下

# 建立外掛目錄
mkdir /src/features
# /docs目錄路由解析外掛
touch /src/features/routes.ts

接下來將外掛註冊到設定.umirc.ts

import { defineConfig } from "umi";
export default defineConfig({
    plugins: [
        './src/features/routes.ts',
    ],
});

modifyRoutes

umi提供了modifyRouteshook,通過這個勾點我們可以自由修改umi的路由,檔案可參考外掛 API | UmiJS

該函數入參為umi當前收集到的路由集合,返回值於入參一致,我們可以通過改變返回值來修改umi的路由。

通過列印入參,我們可以看到初始化專案預設的路由為以下結構:

{
  index: {
    path: '/',
    id: 'index',
    parentId: '@@/global-layout',
    file: 'index.tsx',
    absPath: '/'
  },
  docs: {
    path: 'docs',
    id: 'docs',
    parentId: '@@/global-layout',
    file: 'docs.tsx',
    absPath: '/docs'
  },
  '@@/global-layout': {
    id: '@@/global-layout',
    path: '/',
    file: 'D:/project/domi/src/layouts/index.tsx',
    parentId: undefined,
    absPath: '/',
    isLayout: true
  }
}

這裡有幾個關鍵的屬性:

  • isLayout屬性表示該物件是否為佈局,umi的路由物件有兩種形式,一種為頁面,另一種為佈局,通過該屬性值區分。
  • parentId則標註該頁面使用到了哪個佈局。
  • path表示頁面的存取路徑
  • file表示該物件的元件檔案路徑,相對路徑預設會在/src/pages中找

由於我們要自己來生成markdown專屬路由,用不到umi預設提供的約定路由特性,所以我們不會在/src/pages中寫頁面程式碼,這個目錄我們可以刪掉。

解析生成路由

我們需要在modifyRoutes勾點函數中,根據/docs目錄下的檔案來建立對應的路由,程式碼如下所示

// /src/features/routes.ts
import path from 'path';
import type { IApi } from 'umi';
import type { IRoute } from '@umijs/core/dist/types';
import { getConventionRoutes } from '@umijs/core';
export default (api: IApi) => {
  api.describe({ key: 'domi:routes' });
  api.modifyRoutes((oRoutes: Record<string, IRoute>) => {
    const routes: Record<string, IRoute> = {}
    const docDir = 'docs'
    // 獲取某個目錄下所有可以設定成umi約定路由的檔案
    const dirRoutes: Record<string, IRoute> = getConventionRoutes({
      base: path.join(api.cwd, docDir),
    });
    Object.entries(dirRoutes).forEach(([key, route]) => {
      // 這裡將檔案的路徑改為絕對路徑,否則umi會預設找/src/pages下元件
      route.file = path.resolve(docDir, route.file);
      routes[route.id] = route;
    });
    return routes;
  });
};

注意:如果用pnpm來安裝依賴,上面程式碼的imoprt可能找不到依賴,需要在.npmrc中新增一行node-linker=hoisted,並從新pnpm install,將依賴扁平化處理。

getConventionRoutes

這裡用到了一個umi內建的函數getConventionRoutes,該函數可以將某個目錄下符合umi定義的約定路由的檔案,轉換成為路由物件

前面我們已經在/docs下建立了兩個測試檔案,將其列印出來dirRoutes變數為:

{   
  'button/index': {
    path: 'button',
    id: 'button/index',      
    parentId: undefined,     
    file: 'button/index.tsx',
    absPath: '/button'       
  },
  index: {
    path: '/',
    id: 'index',
    parentId: undefined,     
    file: 'index.tsx',       
    absPath: '/'
  }
}

從列印結果可以看到,getConventionRoutes函數已經幫我們將/docs目錄下的檔案解析出來。我們只需要處理以下檔案路徑,即可使用。

存取執行

執行專案可以看到我們能正常存取到//button下的兩個頁面,到這裡我們就成功實現了路由載入。到這一步我們其實和umi提供的約定式路由功能差不多,只不過umi是在/src/pages下寫頁面,我們這裡是在/docs下寫頁面。

現在切換頁面需要我們手動輸入地址比較麻煩,下一節我們來實現一個全域性Layout佈局元件,將導航放在這個元件中。

以上就是umi外掛開發仿dumi專案實現基礎路由解析的詳細內容,更多關於umi外掛仿dumi路由解析的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com