Vue 3 外部 component/plugin 在运行时加载
Vue 3 external component/plugin loading in runtime
我正在为 Vue 3
应用程序设计一个基于分布式模块所有权的架构。模块系统将用插件表示(似乎是允许 vuex
模块和 vue-router
动态注入的最合适的解决方案)。每个这样的 module/plugin 都将由专门的团队在孤立的回购协议中开发。我们不能使用 npm
package-per-plugin 方法,因为部署过程也应该被隔离,并且使用 npm
方法核心应用程序团队将不得不在每次 npm
包插件有更新时重建应用程序.这意味着我们必须在运行时通过 http
.
加载这样的 plugins/pages
到目前为止,Markus Oberlehner 的 this approach 似乎是某种方式 - 它使用基于自定义 Promise
的解决方案来解决 webpack
丢失的“加载外部 url 运行时的脚本”功能。虽然它与 Vue 2
一起工作正常,但 Vue 3
给出 VNode type: undefined
错误。
上述文章提供了以下webpack
外部组件加载解决方案:
// src/utils/external-component.js
export default async function externalComponent(url) {
const name = url.split('/').reverse()[0].match(/^(.*?)\.umd/)[1];
if (window[name]) return window[name];
window[name] = new Promise((resolve, reject) => {
const script = document.createElement('script');
script.async = true;
script.addEventListener('load', () => {
resolve(window[name]);
});
script.addEventListener('error', () => {
reject(new Error(`Error loading ${url}`));
});
script.src = url;
document.head.appendChild(script);
});
return window[name];
}
但是上面,正如我所说,不适用于 Vue 3
defineAsyncComponent
机制。
// 2.x version WORKS
const oldAsyncComponent = () => externalComponent('http://some-external-script-url.js')
// 3.x version DOES NOT WORK
const asyncComponent = defineAsyncComponent(
() => externalComponent('http://some-external-script-url.js')
)
所以我有两个问题:
是否有更好的solutions/suggestions以上架构规范?
是否有 webpack
动态外部导入解决方案经过 Vue 3
测试?
UPD:这里是小reproduction repo
我们通过聊天一起解决了这个问题。
通过 Vue 3 vue-cli 构建的组件依赖于 Vue
在全局范围内可用。因此,为了渲染通过我文章中描述的技术加载的组件,您需要将 window.Vue
设置为对 Vue
本身的引用。然后一切正常。
更新:
如果从vue/dist/vue.esm-bundler
引入vue并设置为全局,则无需更改webpack / Vite配置,也无需从cdn加载vue。
import * as Vue from 'vue/dist/vue.esm-bundler';
window.Vue = Vue;
除了设置window.Vue
外,还要设置一些其他的webpack或Vite配置,否则控制台会报错:vue warn invalid vnode type symbol(static) (symbol)
Vue3 + webpack:(https://github.com/vuejs/vue-next/issues/2913#issuecomment-753716888)
// index.html:
<script src="https://cdn.jsdelivr.net/npm/vue@3.0.4"></script>
// vue.config.js
configureWebpack: config => {
...
config.externals = { vue: 'Vue' }
...
}
Vue3 + vite:(https://github.com/crcong/vite-plugin-externals)
// vite.config.js
import { viteExternalsPlugin } from 'vite-plugin-externals'
export default {
plugins: [
viteExternalsPlugin({
vue: 'Vue'
}),
]
}
我正在为 Vue 3
应用程序设计一个基于分布式模块所有权的架构。模块系统将用插件表示(似乎是允许 vuex
模块和 vue-router
动态注入的最合适的解决方案)。每个这样的 module/plugin 都将由专门的团队在孤立的回购协议中开发。我们不能使用 npm
package-per-plugin 方法,因为部署过程也应该被隔离,并且使用 npm
方法核心应用程序团队将不得不在每次 npm
包插件有更新时重建应用程序.这意味着我们必须在运行时通过 http
.
到目前为止,Markus Oberlehner 的 this approach 似乎是某种方式 - 它使用基于自定义 Promise
的解决方案来解决 webpack
丢失的“加载外部 url 运行时的脚本”功能。虽然它与 Vue 2
一起工作正常,但 Vue 3
给出 VNode type: undefined
错误。
上述文章提供了以下webpack
外部组件加载解决方案:
// src/utils/external-component.js
export default async function externalComponent(url) {
const name = url.split('/').reverse()[0].match(/^(.*?)\.umd/)[1];
if (window[name]) return window[name];
window[name] = new Promise((resolve, reject) => {
const script = document.createElement('script');
script.async = true;
script.addEventListener('load', () => {
resolve(window[name]);
});
script.addEventListener('error', () => {
reject(new Error(`Error loading ${url}`));
});
script.src = url;
document.head.appendChild(script);
});
return window[name];
}
但是上面,正如我所说,不适用于 Vue 3
defineAsyncComponent
机制。
// 2.x version WORKS
const oldAsyncComponent = () => externalComponent('http://some-external-script-url.js')
// 3.x version DOES NOT WORK
const asyncComponent = defineAsyncComponent(
() => externalComponent('http://some-external-script-url.js')
)
所以我有两个问题:
是否有更好的solutions/suggestions以上架构规范?
是否有
webpack
动态外部导入解决方案经过Vue 3
测试?
UPD:这里是小reproduction repo
我们通过聊天一起解决了这个问题。
通过 Vue 3 vue-cli 构建的组件依赖于 Vue
在全局范围内可用。因此,为了渲染通过我文章中描述的技术加载的组件,您需要将 window.Vue
设置为对 Vue
本身的引用。然后一切正常。
更新:
如果从vue/dist/vue.esm-bundler
引入vue并设置为全局,则无需更改webpack / Vite配置,也无需从cdn加载vue。
import * as Vue from 'vue/dist/vue.esm-bundler';
window.Vue = Vue;
除了设置window.Vue
外,还要设置一些其他的webpack或Vite配置,否则控制台会报错:vue warn invalid vnode type symbol(static) (symbol)
Vue3 + webpack:(https://github.com/vuejs/vue-next/issues/2913#issuecomment-753716888)
// index.html:
<script src="https://cdn.jsdelivr.net/npm/vue@3.0.4"></script>
// vue.config.js
configureWebpack: config => {
...
config.externals = { vue: 'Vue' }
...
}
Vue3 + vite:(https://github.com/crcong/vite-plugin-externals)
// vite.config.js
import { viteExternalsPlugin } from 'vite-plugin-externals'
export default {
plugins: [
viteExternalsPlugin({
vue: 'Vue'
}),
]
}