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

Hug*_*hes 8 markdown typescript reactjs webpack create-react-app

我正在尝试加载要在构建时加载的 markdown 文件。我已经设置了一个使用 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>
  );
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

理想情况下,我希望在构建期间加载该文件,以便可以更快地在 Netlify 等地方提供服务。我不想像这个答案所建议的那样使用异步获取。

我想我必须创建一个 webpack 加载器?问题在于 create-react-app 具有,webpack.config.jsnode_modules意味着自定义它会在新构建期间被覆盖。如果我无法配置它,我认为使用raw-loader没有帮助。

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

任何的意见都将会有帮助。

小智 10

这似乎是之前被问过的问题(https://github.com/facebook/create-react-app/issues/3025),但不幸的是,现在似乎不可能直接将 markdown 作为 JavaScript 中的字符串导入/打字稿。

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

  1. 创建一个.d.ts文件来告诉 TypeScript 如何解释md文件:
declare module '*.md' {
  const value: string; // markdown is just a string
  export default value;
}
Run Code Online (Sandbox Code Playgroud)
  1. 按如下方式导入您的md文件 ( the_text.md)
import theTextFile from './the_text.md';
Run Code Online (Sandbox Code Playgroud)
  1. 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);
    });
}, []);
Run Code Online (Sandbox Code Playgroud)
  1. 将 Markdown 文本放入 Markdown 标签中,它将被渲染:
<Markdown className={classes.markdown}>
  {post}
</Markdown>
Run Code Online (Sandbox Code Playgroud)

请记住,您还可以覆盖用于显示最终内容的 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>
  )
}
Run Code Online (Sandbox Code Playgroud)

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

  • 有谁知道material-ui是如何在他们的在线示例网站上做到这一点的?(https://material-ui.com/getting-started/templates/blog/) 他们是否在 SSR 构建期间加载它?他们的代码结构与上面的问题类似。谢谢 (4认同)