Webpack加载markdown文件内容

前言

本文适合使用create-react-app(下文称之为cra)创建的项目,是react官方脚手架,内部由react-scripts支持;

markdown是一种轻量级的富文本文件类型,按照惯例,加载不同类型的文件,我们需要在webpack中配置对应的loader实现;

因为cra默认是将所有的配置都封装在react-scripts中,默认没有给我们提供对应的修改入口,要是我们修改的话有两个途径:

1、使用eject将webpack的配置释放出来;
2、借助插件重写启动脚本加载自定义配置;

因为eject操作是不可逆的,并且会导致react-scripts后期无法升级,所以我们第2种方法。
我们要借助一个插件(customize-cra)去实现。

实现

1. 安装依赖

yarn add customize-cra react-app-rewired markdown-loader html-loader@1 -D

说明:

  • customize-cra 自定义cra配置的插件,提供了很多的工具方法;
  • react-app-rewired 替换react-scripts的启动工具;
  • markdown-loader 负责将md文件转化成html;
  • html-loader 加载转化之后的html(这里的html-loader一定要装版本v1,否则会报错:this.getOptions is not a function;)

2. 修改配置

接下来我们创建或者修改项目根目录下的config-overrides.js文件,文件名不要随便写;
customize-cra提供的override方法可以允许我们修改配置并返回,当然customize-cra还提供了很多便捷的方法,因为官方没有给出自定义loader的方法,所以我们这次只研究自定义loader的部分;

通过debug查看react-scripts生成的webpack配置,我们可以看到以下的信息,包括loader、plugins、entry等,这里的所有都是可以修改的。

本次的需求是加一个文件类型的解析,我们就需要看看加在什么地方才能生效;
仔细观察上图高亮的两部分:

1、最外层的加载规则,分别配置了parser、js模块、其他文件类型处理;
2、oneOf中处理了除去js文件类型的所有配置,根据oneOf的匹配规则,要是匹配到其中的规则就不会继续向下匹配了

分析以下:

1、如果将markdown-loader放在标注1的 rules[0]和rules[1] 之间,虽然能解析成功,但是也会匹配下面的oneOf中的规则,最后发现生效的oneOf[9]的规则,所以我们必须要放在oneOf中配置
2、如果放在oneOf的最后,当然还是匹配到了oneOf[9],还是达不到效果,所以必须放在oneOf[9]之前的任意位置即可

根据上面的分析,我们添加配置,我们就将markdown的解析放在oneOf的第一个就行,具体配置如下:

const {override} = require("customize-cra");

module.exports = {
  webpack: override(config => {
    // 先找到oneOf下面所有的loader
    const oneOfLoaders = config.module.rules.find(rule => Array.isArray(rule.oneOf)).oneOf;
    // 一定要放到oneOf的最前面,否则没有效果,详细可以查看oneOf的具体作用
    // 不放到最前面的话,就会当作media处理,输出的media下面的文件
    oneOfLoaders.unshift({
      test: /\.md$/,
      use: [{
        loader: 'html-loader',
      }, {
        loader: 'markdown-loader',
        options: {}
      }]
    });
    return config;
  })
};

修改启动脚本

修改package.json启动脚本,加载自定义配置文件,react-app-rewired和react-scripts使用方法一致

{
  "scripts": {
    "start": "react-app-rewired start"
  }
}

加载md文件

然后在文件中直接使用markdown就可以了,使用实例如下:

import React from "react";
import BaseModal from "../BaseModal";
import content from './index.md';
import './index.less';

export default function DisclaimerModal({visible}) {
  return (
    <BaseModal visible={visible} title="免责声明">
      <div className="disclaimer-modal">
        <div dangerouslySetInnerHTML={{__html: content}}/>
      </div>
    </BaseModal>
  )
}

总结

上面涉及到两个难点

1、怎么在react-scripts生成的配置中添加loader?
2、特殊文件的loader应该加在什么地方?

常见问题

1、为啥要在代码中写markdown呢?
有时候我们涉及到大段的文案,例如游戏规则等,如果在代码中使用div堆的话还是很慢的,尤其是修改了里面的内容,我们几乎要替换所有的代码;如果使用markdown,大段的文案只需要简单的调一下格式,样式使用通用的标签加样式的形式实现。

2、因为不知名原因导致了webpack启动失败,一直显示Start Delevelop Server…,
需要安装 react-scripts@2.1.8解决;

留下回复