umi插件开发仿dumi项目实现markdown文件转为页面
kukiiu 人气:0引言
前面我们已经成功将.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
加载全部内容