umi插件开发【仿dumi项目】 - 将markdown文件转为页面

lxf2023-05-22 01:35:25

前面我们已经成功将.md文件通过import加载到react组件中,并能拿到文件内容进行展示。但是点击markdown的导航链接还是会报错

umi插件开发【仿dumi项目】 - 将markdown文件转为页面

这个报错和前面的报错有点相似,只是前面是无法解析链接,这里是无法解析对象

处理导入错误

react渲染页面时,是调用一个个渲染函数来渲染页面,我们来对比一下button页和markdown页加载页面的bundle对比一下

umi插件开发【仿dumi项目】 - 将markdown文件转为页面 button页面导出的是一个Button函数,返回的是创建该页面的代码

umi插件开发【仿dumi项目】 - 将markdown文件转为页面 markdown导出的是一个js对象

而报错提示我们markdown也应该导出为一个类或函数,否则无法识别,所以下一步,我们就需要将这个带有markdown正文的js对象转换为react渲染函数。

loader返回渲染函数

我们前面通过自定义loader,将markdown转为js对象导入,那么我们能不能将markdown对象转为react渲染函数,直接交给react渲染呢?我们直接将loader改成返回一个react函数组件

// /src/loaders/markdown/loader.js
function mdLoader(content) {
  return `
    import react from 'react'
    const content = ${JSON.stringify(content)};
    const Markdown = () => {
        return (<div>{content}</div>)
    }
    export default Markdown
  `
}
module.exports = mdLoader

重启后发现又报错了

umi插件开发【仿dumi项目】 - 将markdown文件转为页面

添加react处理loader

上面的错误依然很熟悉,说无法解析返回的字符串,还告诉我们可能要添加其他loader来处理返回值。

umi默认配置的babel-loader可以用来处理react组件,我们将其添加到解析链中,注意babel的执行顺序是反的,所以要先写babel-loader再写md-loader

  api.chainWebpack(async (memo) => {
    const babelInUmi = memo.module.rule('src').use('babel-loader').entries();
    const loaderPath = require.resolve('../loaders/markdown/loader.js');
    memo.module
        .rule('domi-md')
            .test(/\.md$/)
            .type('javascript/auto')
            // 用默认带的babel-loader来处理react组件
            .use('babel-loader')
            .loader(babelInUmi.loader)
            .options(babelInUmi.options)
            .end()
            .use('md-loader')
            .loader(loaderPath)
    return memo;
  });

完成配置后,markdown文件就会先经过md-loader转为react组件字符串,接着使用babel-loader转换为可执行渲染函数。

再次启动可以看到markdown文件内容已经能被渲染出来

umi插件开发【仿dumi项目】 - 将markdown文件转为页面

用ts来写loader

前面说了我们目前只能用js来写loader,但是我们可以用一些小技巧,先绕过这个限制,使得不需要编译也能使用ts来写loader。让webpack还是加载原来的组件,但是原来的代码只做个代理,实际执行代码可以用ts来写:

改变原来的loader

// /src/loaders/markdown/loader.js
function mdLoader(content) {
  const options = this.getOptions({ 'handler': true })
  return options.handler.apply(this, [content])让
}
module.exports = mdLoader

创建新的loader

// /src/loaders/markdown/index.ts
export default function mdLoader(this: any, content: string) {
    return `
        import react from 'react'
        const content = ${JSON.stringify(content)};
        const Markdown = () => {
            return (<div>{content}</div>)
        }
        export default Markdown
    `
}

配置webpack

// /src/features/compile.ts
import MdLoader from '../loaders/markdown/index'
...
    .use('md-loader')
    .loader(loaderPath)
    .options({
        handler: MdLoader
    })
...

代码

完整代码可查看feature/render-markdown

本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!