引言
为什么不能直接展示markdown
chainWebpack
webpack loader
实现过程
新建插件
新建loader
新建测试文档
运行项目
解决文件加载类型错误
webpack ruletype
解决错误
引言前面章节中我们已经顺利将tsx
组件转换为页面展示,但是目前提供的功能和umi
的约定式路由功能差不多,接下来我们将实现将markdown
文件转换为页面展示。
我们前面所使用的页面写法都是react组件式写法,umi
通过webpack
将react组件打包,这是react项目通用的模式。由于webpack
不认识markdown
文件,所以我们直接引入markdown
文件会报错。所以我们只需要让webpack
认识markdown
,通过自定义loader
来加载markdown
文件即可。
umi
提供chainWebpack
插件api,通过 webpack-chain 的方式修改 webpack 配置。
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文件的资料请关注软件开发网其它相关文章!