简体   繁体   English

运行时动态加载 Vue 单文件组件

[英]Load Vue single-file component dynamically at runtime

We've got a Vue app and would like to allow third parties to create plugins.我们有一个 Vue 应用程序,并希望允许第三方创建插件。 We'd like the plugins to be built in the form of a Vue single-file component.我们希望插件以 Vue 单文件组件的形式构建。

At runtime, the end user would select a plugin to add to the app.在运行时,最终用户将 select 一个插件添加到应用程序中。 The app would fetch the plain-text.vue file, compile it on the fly, and display it in the app.该应用程序将获取 plain-text.vue 文件,即时编译它,并将其显示在应用程序中。

Vue supports dynamic and async components , but these to be compiled into the app ahead of time. Vue 支持动态和异步组件,但这些要提前编译到应用程序中。 We'd like to do the same thing, except load the code on the fly.我们想做同样的事情,除了动态加载代码。

How can I make this work?我怎样才能使这项工作?

Here's what I've got so far:这是我到目前为止所得到的:

<template>
  <div>
    The component goes here:
    <component :is="pluginComponent"></component>
  </div>
</template>
<script>
import { parseComponent } from "vue-template-compiler";
export default {
  data() {
    return {
      pluginComponent: null
    };
  },
  mounted() {
    // fetch code from some external source here
    let code = "<template><div>hello</div></template>";
    let comp = parseComponent(code);
    this.pluginComponent = comp;
  }
};
</script>

(I modified the build so the vue-template-compiler is present.) (我修改了构建,因此存在 vue-template-compiler。)

The code above generates this error:上面的代码生成此错误:

[Vue warn]: invalid template option:[object Object]
found in
---> <Anonymous>
       <Pages/plugin/PluginId.vue> at pages/plugin/_plugin_id.vue
         <Nuxt>
           <Layouts/default.vue> at layouts/default.vue
             <Root> instrument.js:110
    instrumentConsole instrument.js:110
    VueJS 15
TypeError: "vnode is null"
    VueJS 14
instrument.js:110

I'm guessing that whatever parseComponent() produces isn't what <component> is looking for.我猜测无论 parseComponent() 产生什么,都不是<component>正在寻找的。

I'm guessing that whatever parseComponent() produces isn't what <component> is looking for我猜无论parseComponent()产生什么都不是<component>正在寻找的

I'd say yes, as it doesn't seem to compile to any render functions.我会说是的,因为它似乎没有编译成任何render函数。

As stated in the docs , vue-template-compiler is for runtime-compilation.文档中所述, vue-template-compiler用于运行时编译。 And in most cases you should be using it with vue-loader .在大多数情况下,你应该将它与vue-loader一起使用。

How can I make this work?我怎样才能使这项工作?

You might want to use Vue.compile as it allows you to compile template string into a render function;你可能想使用Vue.compile ,因为它允许你将模板字符串编译成render function; which you can then bind to an object for an async or dynamic component.然后您可以将其绑定到异步或动态组件的 object。

Do note, however, that this is only available in the full build , which is roughly 30% heavier-weight than the runtime-only build counterparts.但是请注意,这仅在完整构建中可用,它比仅运行时构建对应物重约 30%。 Read more on Runtime + Compiler vs. Runtime-only .阅读有关运行时 + 编译器与仅运行时的更多信息。

With that in mind, since you didn't mention in the question, which bundler you are using, I'm going to assume Webpack with Vue-CLI, and here's how you would configure the vue alias (as a reference point when importing).考虑到这一点,因为你没有在问题中提到你正在使用哪个捆绑器,我将假设 Webpack 与 Vue-CLI,这里是你如何配置vue别名(作为导入时的参考点) .

Verifying your set Vue "alias"验证您设置的 Vue“别名”

In your console (from the root of the project), run:在您的控制台中(从项目的根目录),运行:

vue inspect resolve.alias.vue$

If that results in something along "vue/dist/vue.runtime.esm.js" (it should be, by default), then it's clear that we need to change this part.如果这导致“vue/dist/vue.runtime.esm.js”(默认情况下应该是),那么很明显我们需要更改这部分。

Configuring it配置它

Now, since the internal webpack config is maintained using webpack-chain , we would configure/reset the alias like so:现在,由于内部 webpack 配置是使用webpack-chain维护的,我们将像这样配置/重置别名:

module.exports = {
  chainWebpack: config => {
    config.resolve.alias
      .set('vue$', 'vue/dist/vue.esm.js')
  }
}

Check out the explanation of different builds .查看不同构建的解释

Using it使用它

And at this point, all you'd need to do is pass the "dynamic" template to the compile function, excluding the <template> tag though.此时,您需要做的就是将“动态”模板传递给compile function,但不包括<template>标记。

import Vue from 'vue';

export default {
  mounted() {
    // fetch code from some external source here
    let code = '<div>hello</div>';
    let comp = Vue.compile(code);
    
    this.pluginComponent = comp;
  }
}
<template>
  <div>
    The component goes here:
    <component :is="pluginComponent"></component>
  </div>
</template>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM