【问题标题】:How to dynamically import markdown files如何动态导入markdown文件
【发布时间】:2021-06-07 03:58:01
【问题描述】:

我正在使用 Vue 构建一个博客,我希望将我的帖子写成 markdown 文件。

目前我有以下结构

src/
  posts/
    blogpost1.md
    blogpost2.md
  view/
    myComponent.vue

我希望myComponent.vue 根据路由参数动态加载降价帖子。

例如,如果我们访问了.../blog/blogpost2,那么我们将动态加载blogpost2.md

我目前的实现如下:

<template>
    <div
        v-html="md"
    ></div>
</template>

<script>
import marked from "marked";

export default {
    data () {
        return {
            md: undefined,
        };
    },
    created () {
        const importRoute = `posts/blog/${this.$route.params.postName}.md`;
        const md = require(importRoute);
        this.md = marked(md);
    },
};
</script>

要加载我在 webpack 中使用 markdown-loader 的降价文件。

我还使用copy-webpack-plugin 尝试将我的整个/posts 目录复制到我的构建文件夹中。

configureWebpack: {
    module: {
        rules: [{
            test: /\.md$/,
            use: [
                { loader: "html-loader", options: {} },
                { loader: "markdown-loader", options: {} },
            ],
        },
        ],
    },
    plugins: [
        new CopyPlugin({
            patterns: [
                { from: "src/posts", to: "posts" },
            ],
        }),
    ],
},

但是,当我运行 npm run serve 时,我收到 [Vue warn]: Error in created hook: "Error: Cannot find module './posts/blogpost2.md'"

当我在浏览器中查看页面时,我看不到 posts 目录(见下图)

但是,在运行 npm run build:staging 时,我确实在 /dist 中看到了 posts 目录

为什么我无法动态导入 import blogpost2.md

【问题讨论】:

  • 考虑使用已经存在的几个 Markdown 站点生成器之一(VuePress、VitePress、Nuxt Content、Gridsome)。不要重新发明轮子:)
  • 是的,我正在认真考虑这一点,但首先要尝试诊断为什么这不起作用。我想我在某种程度上误解了 webpack
  • 另外值得注意的是,如果我将 blogpost2 的导入引用设为常规字符串,它会成功运行

标签: javascript vue.js webpack


【解决方案1】:

// 我曾经需要做类似的事情并面临类似的挑战,但它是使用 Create React App 构建的,所以请对我的回答持怀疑态度。

尝试将您的导入路径放在require(…)(或import(…),如果您曾经使用过它)而不是声明一个变量然后将其传递。我记得当路径不是静态字符串时,WebPack 很难找到文件(很难-以这种方式编码)。无论动态路径是什么,您的路径都需要以静态字符串开头,但您可以在其后面连接动态值。

另外,请注意我添加到路径前面的./。如果你使用绝对导入,请忽略它,否则这也可能是代码失败的原因?

created () {
    // Instead of:
    // const importRoute = `posts/blog/${this.$route.params.postName}.md`;
    // const md = require(importRoute);
    // Try:
    const md = require(
      `./posts/blog/${this.$route.params.postName}.md`
    );
    this.md = marked(md);
},

额外:据我所知,Vue 中的 created 钩子应该只是同步的,但在偶然发现 this answer 之后,我决定也包含这个 sn-p。这个使用动态导入。如果一切都失败了,也许你可以试试这个?

async created () {
    const { default: url } = await import(
      `posts/blog/${this.$route.params.postName}.md`
    );
    const res = await fetch(url);
    const md = res.text();
    this.md = marked(md);
},

【讨论】:

  • 不幸的是,由于 webpack 捆绑代码的方式,第一个答案不起作用。我认为不可能让它以这种方式工作。你建议的第二个extra 实际上做了一些调整!将发布更详细的答案解释
【解决方案2】:

我尝试使用基于路由更改的动态导入将不起作用,因为 webpack 无法正确捆绑导入的文件。这是因为 webpack 需要知道它将导入什么才能正确打包它们。

相反,我们可以使用不同的方法将我们的 markdown 目录原样复制到 /dist 并发送请求以获取每个 markdown 文件。

我们最终在我们的 webpack 配置中得到了这个(或者在我的情况下是 vue.config.js):

const CopyPlugin = require("copy-webpack-plugin");

configureWebpack: {
        plugins: [
            new CopyPlugin({
                patterns: [
                    { from: "src/posts", to: "posts" },
                ],
            }),
        ],
    },

请注意,我们不需要我最初的问题中显示的 webpack 加载器,因为 webpack 本身不处理这些文件的加载。

这可确保 posts/ 在我们构建此项目时被复制。

然后在我们的组件中,我们可以像这样动态检索 Markdown 文件:

<template>
    <div
        v-html="md"
    ></div>
</template>

<script>
import marked from "marked";

export default {
    data () {
        return {
            md: undefined,
        };
    },
    async created () {
        const res = await fetch(`http://localhost:8081/posts/${this.$route.params.postName}.md`);
        const md = await res.text();
        this.md = marked(md);
    },
};
</script>

【讨论】:

    猜你喜欢
    • 2022-01-02
    • 2020-05-19
    • 2016-07-21
    • 2019-10-19
    • 1970-01-01
    • 2017-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多