首頁 > 軟體

umi外掛開發仿dumi專案載入markdown檔案實現詳解

2023-01-28 18:02:45

引言

前面章節中我們已經順利將tsx元件轉換為頁面展示,但是目前提供的功能和umi的約定式路由功能差不多,接下來我們將實現將markdown檔案轉換為頁面展示。

為什麼不能直接展示markdown

我們前面所使用的頁面寫法都是react元件式寫法,umi通過webpack將react元件打包,這是react專案通用的模式。由於webpack不認識markdown檔案,所以我們直接引入markdown檔案會報錯。所以我們只需要讓webpack認識markdown,通過自定義loader來載入markdown檔案即可。

chainWebpack

umi提供chainWebpack外掛api,通過 webpack-chain 的方式修改 webpack 設定。

webpack loader

loader是用於webpack解析檔案的工具,不同的loader可以解析不同型別的檔案,使其解析的內容可被其他模組使用。

我們需要解析markdown檔案,那麼就需要寫一個能認識markdown檔案的loader,它的功能就是識別.md檔案並將檔案內容解析成物件返回給import這個檔案的程式碼使用。

實現過程

新建外掛

跟前面一樣,我們新建一個外掛來處理檔案解析:

// /src/features/compile.ts
import type { IApi } from 'umi';
export default (api: IApi) => {
  api.describe({ key: 'domi:compile' });
  api.chainWebpack(async (memo) => {
    const loaderPath = require.resolve('../loaders/markdown/loader.js');
    memo.module
      // 通過鏈式處理,向`webpack`新增了一條名為`domi-md`的處理規則
      .rule('domi-md')
        // 該規則用於處理`.md`檔案
        .test(/.md$/)
        // 給這個loader取個名字
        .use('md-loader')
        // loader的路徑
        .loader(loaderPath)
    return memo;
  });
};

新建loader

接下來建立loader檔案,注意這裡loader要使用js檔案,因為webpack無法直接解析ts型別的loader,第一個入參是檔案內容的字串形式,我們先直接返回。

// /src/loaders/markdown/loader.js
function mdLoader(context) {
    return context
}  
module.exports = mdLoader

為什麼`dumi`的loader是用`ts`寫的?

因為在`dumi`開發環境下,先將`ts`檔案轉成了`js`,`webpack`在執行時其實還是載入的`js`形式的loader。

dumi: 編譯 => 啟動umi(webpack) => 開發環境

domi: 啟動umi(webpack) => 開發環境 

新建測試檔案

// /docs/markdown.md
# 我是markdown

執行專案

啟動專案可以看到markdown檔案已經正確解析到導航欄中了

點開連結一看,啥也沒有,報錯了

解決檔案載入型別錯誤

看上面的報錯資訊,意思好像是懶載入的元件元素型別錯誤,開啟請求列表看看載入了什麼東西

應該就是這裡在載入markdown檔案時,只匯出了個url連結,我們開啟連結看看

這裡就返回了markdown內容,看來目前不能直接從頁面開啟。

我們換一種方式,在jsx中直接匯入這個檔案看看:

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

重新整理頁面可以看到,import進來的物件確實只是一個地址,那我們直接放個iframe來顯示:

// /docs/index.tsx
import react from 'react'
import md from './markdown.md'
const Home = () => {
    return (<>
        <div>hello domi!</div>
        <iframe src={md} />
    </>)
}
export default Home

哈哈終於顯示出來了

webpack ruletype

當然上面並不是我們想要的效果,從前面的嘗試大概能判斷出來是webpack在打包時並沒有想我們想象那樣能直接匯出我們想要的物件。這時候我們就要使用webpack一個設定ruletype,告訴他我們想要將markdown檔案import成一個包含正文內容的物件,而不是一個資源地址。

這裡webpack將檔案視為Resource資源,其將所有 .md 檔案都傳送到輸出目錄,並且其路徑將被注入到 bundle中,與我們常使用的在jsx中匯入圖片等一樣,具體可參考資源模組 | webpack 中文檔案 (docschina.org)

要改變這一預設行為,只需要設定時改變資源型別即可

// /src/features/compile.js
api.chainWebpack(async (memo) => {
    const loaderPath = require.resolve('../loaders/markdown/loader.js');
    memo.module
        .rule('domi-md')
            .test(/.md$/)
            // 表示檔案經過這個loader處理後轉換為可匯入的js模組
            .type('javascript/auto')
            .use('md-loader')
            .loader(loaderPath)
    return memo;
});

重啟後執行,發現又報了另一個錯誤

解決錯誤

從報錯上看,意思大概是.md檔案在經過loader解析後,解析返回值失敗,還告訴我們可能需要其他loader來處理返回值。

這個就比較好理解了,因為上面我們指定了經過loader處理後應該返回一個可匯出的js模組,而我們目前loader只返回了markdown的正文內容,並不是js資料,所以我們只需要改動以下loader的返回值即可:

// /src/loaders/markdown/loader.js
function mdLoader(content) {
  return `
      const content = '${JSON.stringify(content)}'
      export default { content };
  `
}
module.exports = mdLoader

此時經過loader處理後,將會匯出一個帶有content屬性的物件,再改變一下匯入展示的元件:

import react from 'react'
import md from './markdown.md'
const Home = () => {
    return (<div>hello domi! {md.content}</div>)
}
export default Home

重啟後可以看到如下所示,此時我們已經成功通過loader載入到markdown檔案顯示

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


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