umi插件开发仿dumi项目实现markdown文件转为页面

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

umi插件开发仿dumi项目实现markdown文件转为页面

kukiiu   2023-02-03 我要评论

引言

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

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

处理导入错误

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

button页面导出的是一个Button函数,返回的是创建该页面的代码

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

重启后发现又报错了

添加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文件内容已经能被渲染出来

用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

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们