Загружать Vue однофайловый компонент динамически во время выполнения - PullRequest
0 голосов
/ 27 мая 2020

У нас есть приложение Vue, и мы хотим разрешить третьим лицам создавать плагины. Мы хотели бы, чтобы подключаемые модули были построены в виде однофайлового компонента Vue.

Во время выполнения конечный пользователь должен выбрать подключаемый модуль для добавления в приложение. Приложение получит файл с открытым текстом. vue, скомпилирует его на лету и отобразит в приложении.

Vue поддерживает компоненты Dynami c и asyn c , но они должны быть скомпилированы в приложение заранее. Мы бы хотели сделать то же самое, за исключением загрузки кода на лету.

Как я могу заставить это работать?

Вот что у меня есть на данный момент:

<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>

(Я изменил сборку так, чтобы в ней присутствовал vue -template-compiler.)

Приведенный выше код генерирует эту ошибку:

[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

Я предполагаю, что все, что производит parseComponent (), не то, что ищет <component>.

1 Ответ

1 голос
/ 27 мая 2020

Я предполагаю, что все, что производит parseComponent(), не то, что <component> ищет

Я бы сказал, что да, так как кажется, что это не компилируется в любые render функции.

Как указано в docs , vue-template-compiler предназначен для компиляции во время выполнения. И в большинстве случаев вы должны использовать его с vue-loader.

Как я могу это сделать?

Возможно, вы захотите использовать Vue.compile , поскольку он позволяет вам скомпилировать строку шаблона в функцию render; который затем можно привязать к объекту для компонента asyn c или Dynami c.

Обратите внимание, однако, что это доступно только в полной сборке , т.е. примерно на 30% тяжелее, чем аналоги сборки только во время выполнения. Подробнее о Runtime + Compiler vs. Runtime-only .

Имея это в виду, так как вы не упомянули в вопросе, какой пакет вы используете, я собираюсь предположим, что Webpack с Vue -CLI, и вот как вы настроили бы псевдоним vue (в качестве ориентира при импорте).

Проверка вашего набора Vue "псевдоним"

В консоли (из root проекта) запустите:

vue inspect resolve.alias.vue$

Если это приведет к чему-то вроде "vue / dist / vue .runtime.esm. js" (it должно быть по умолчанию), тогда ясно, что нам нужно изменить эту часть.

Настройка

Теперь, поскольку внутренняя конфигурация веб-пакета поддерживается с использованием webpack-chain, мы бы настроили / сбросили псевдоним следующим образом:

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

Ознакомьтесь с описанием различных сборок .

Использование

И на этом этапе все, что вам нужно сделать, это передать шаблон "Dynami c" функции compile, исключая, однако, тег <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>
...