使用 create-react-app 和 Typescript 时如何在构建时加载 .md 文件?

Posted

技术标签:

【中文标题】使用 create-react-app 和 Typescript 时如何在构建时加载 .md 文件?【英文标题】:How to load an .md file on build when using create-react-app and Typescript? 【发布时间】:2021-03-31 08:32:25 【问题描述】:

我正在尝试加载要在构建时加载的降价文件。我已经设置了一个使用 Typescript 并使用 material_ui 博客主题的 create-react-app。

import ReactMarkdown from 'markdown-to-jsx';
import post1 from './blog-post.1.md';

export default function Main(props: MainProps) 
  const classes = useStyles();
  const  posts, title  = props;

  return (
    <Grid item xs=12 md=8>
      <Typography variant="h6" gutterBottom>
        title
      </Typography>
      <Divider />
      posts.map((post) => (
        <Markdown className=classes.markdown key=post.substring(0, 40)>
          post
        </Markdown>
      ))
    </Grid>
  );

如果帖子被指定为markdown,它将正确呈现:const post = '# Sample blog post #### April 1, 2020 by [Olivier](/)'

所以问题是 .md 文件没有加载到变量中。

npm start 运行时,html 显示:/static/media/blog-post.1.09e7833f.md 为什么会这样?这个数字是什么:文件路径中的 09e7833f?

理想情况下,我希望在构建期间加载文件,以便可以在 Netlify 之类的地方更快地提供文件。我不想使用this 答案建议的异步获取。

我假设我必须创建一个 webpack 加载器?这样做的问题是 create-react-app 在node_modules 中有webpack.config.js,这意味着自定义它将在新构建期间被覆盖。如果我无法配置它,我认为使用 raw-loader 没有帮助。

我也按照here 的建议尝试了import post1 from 'raw-loader!./blog-post.1.md';,但 Typescript 不知道该怎么做。

任何建议都会有所帮助。

【问题讨论】:

【参考方案1】:

这似乎是之前提出的问题 (https://github.com/facebook/create-react-app/issues/3025),但不幸的是,现在似乎无法直接将 markdown 作为 javascript/TypeScript 中的字符串导入。

当要求create-react-app 导入md 文件时,它似乎获得了文件的URL(带有十六进制字符串),而不是其中包含的原始字符串。解决方法如下:

    创建一个.d.ts 文件来告诉 TypeScript 如何解释一个md 文件:
declare module '*.md' 
  const value: string; // markdown is just a string
  export default value;

    如下导入你的md文件(the_text.md)
import theTextFile from './the_text.md';
    fetch文件内容获取实际降价(https://github.com/facebook/create-react-app/issues/2961#issuecomment-322916352)
const [postMarkdown, setPostMarkdown] = useState('');

// useEffect with an empty dependency array (`[]`) runs only once
useEffect(() => 
  fetch(theTextFile)
    .then((response) => response.text())
    .then((text) => 
      // Logs a string of Markdown content.
      // Now you could use e.g. <rexxars/react-markdown> to render it.
      // console.log(text);
      setPostMarkdown(text);
    );
, []);
    将 markdown 文本放入 Markdown 标签中即可呈现:
<Markdown className=classes.markdown>
  post
</Markdown>

请记住,您还可以覆盖用于显示最终内容的 JSX 元素。对于 Material-UI,这可能类似于:

import  Typography  from '@material-ui/core';
import  MarkdownToJSX  from 'markdown-to-jsx';

const Foo = (): JSX.Element => 

  const MdOverrideTypography = (
    children,
  : // ...props
  React.DetailedHTMLProps<
    React.HTMLAttributes<HTMLParagraphElement>,
    HTMLParagraphElement
  >): JSX.Element => (
    <Typography paragraph>
      children
    </Typography>
  );

  const mdOverrides: MarkdownToJSX.Overrides = 
    // "p" paragraph elements are substituted with MUI "Typography"
    p: MdOverrideTypography,
  ;

  // ...

  return (
    <Markdown options= overrides: mdOverrides >
      post
    </Markdown>
  )

(https://www.npmjs.com/package/markdown-to-jsx#optionsoverrides---rendering-arbitrary-react-components)

【讨论】:

有谁知道 material-ui 在他们的在线示例网站上是如何做到的? (material-ui.com/getting-started/templates/blog) 他们是在构建 s-s-r 期间加载它吗?他们的代码结构与上面的问题类似。谢谢

以上是关于使用 create-react-app 和 Typescript 时如何在构建时加载 .md 文件?的主要内容,如果未能解决你的问题,请参考以下文章

使用 'lodash-es' 和 create-react-app 减少捆绑包中的 Lodash

create-react-app 和 jest - 不能在模块外使用 import 语句

使用 create-react-app 和 Typescript 时如何在构建时加载 .md 文件?

Create-React-App项目外使用它的eslint配置

使用 create-react-app 和 webpack 发出 CORS API 请求 - 不明确

使用create-react-app搭建react应用