我正在构建由不同的 Vite/Vue 项目组成的模块 vue.js 应用程序。
工作流程 - 拥有 Theme 插件 / **菜单 **插件,可以在 vue 应用程序中动态应用。
组件在应用程序的根级别渲染,但它在嵌套时无法渲染。 (主题组件渲染菜单组件),但是它在 DOM 中仅显示为组件名称....
我尝试创建单独的 vite/vue 应用程序,构建它们,然后在 index.html 中手动加载它们。
主题插件项目
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), vueJsx()],
build: {
rollupOptions: {
output: {
dir: "./dist",
entryFileNames: "plugin.js",
assetFileNames: "plugin.css",
chunkFileNames: "chunk.js",
manualChunks: undefined,
},
},
},
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});
<template>
<div class="vite-theme-plugin-build">
<MenuLauncher></MenuLauncher>
<div style="color:red" v-if="test1">Is Rendered from Theme Wrapper</div>
</div>
</template>
<script lang="ts">
import type { App, Component } from 'vue';
type Framework = {
app: App;
externalComponents: {
ThemeWrapper: Component;
MenuLauncher: Component;
};
};
const w = window as unknown as Framework;
console.log(w);
export default {
name: "ThemeWrapper",
components: {
MenuLauncher: w.externalComponents.MenuLauncher
},
setup() {
return {
test1: true,
};
},
};
</script>
import type { App, Component } from "vue";
import ThemeWrapperVue from "./ThemeWrapper.vue";
type Framework = {
app: App;
externalComponents: {
ThemeWrapper: Component;
MenuLauncher: Component;
};
};
const w = window as unknown as Framework;
w.externalComponents = w.externalComponents || {};
w.externalComponents.ThemeWrapper = ThemeWrapperVue;
菜单插件项目
Identical to the ThemePlugin project configuration
<template>
<div class="vite-menu-plugin-build">
<div>
This is dynamic menu launcher!
</div>
<div style="color:blue" v-if="test1">Is Rendered from MenuLauncher</div>
</div>
</template>
<script lang="ts">
export default {
name: "MenuLauncher",
setup() {
return {
test1: true,
};
},
};
</script>
import type { App, Component } from "vue";
import MenuLauncherVue from "./MenuLauncher.vue";
type Framework = {
app: App;
externalComponents: {
ThemeWrapper: Component;
MenuLauncher: Component;
};
};
const w = window as unknown as Framework;
w.externalComponents = w.externalComponents || {};
w.externalComponents.MenuLauncher = MenuLauncherVue;
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="./menu/dist/plugin.js"></script>
<script src="./theme/dist/plugin.js"></script>
</head>
<body>
<div id="app"></div>
<script>
document.addEventListener("DOMContentLoaded", (event) => {
window.app = Vue.createApp({
setup() {
return {};
},
template: `
<div>
<div style="border: 1px solid gainsboro; margin:1rem;">
<div>ThemeWrapper component doesn't load MenuLauncher component....</div>
<ThemeWrapper></ThemeWrapper>
</div>
<div style="border: 1px solid gainsboro; margin:1rem;">
<div>Root component is able to render MenuLauncher... But above "ThemeWrapper" component cannot render it Why???</div>
<MenuLauncher></MenuLauncher>
</div>
</div>`,
});
window.app.component('MenuLauncher', window.externalComponents.MenuLauncher)
window.app.component('ThemeWrapper', window.externalComponents.ThemeWrapper)
window.app.mount("#app");
});
</script>
</body>
</html>
期望的结果:
MenuLauncherVue
组件应该能够在 ThemeWrapper
组件内渲染。
我绝不是 vue 方面的专家,但我发现这很有趣。因此,在复制代码后,以下行似乎只会在构建时注册组件:
components: {
MenuLauncher: w.externalComponents.MenuLauncher
},
所以我想也许我们可以使用像
defineAsyncComponent
这样的东西,但我尝试使用<component :is="" />
,它似乎足以满足这个要求(它似乎能够在运行时注册,而不是构建时注册)。
所以在模板中,不要使用这个:
<MenuLauncher></MenuLauncher>
我们可以用这个:
<component :is="menuLauncherComponent"></component>
然后在脚本部分,我不知道为什么我们不能使用
ref
来表示 menuLauncherComponent
,所以我们可以使用好的 ol' options API,如下所示:
data() {
return {
menuLauncherComponent: null,
};
},
...
mounted() {
this.menuLauncherComponent = (window as any).externalComponents.MenuLauncher; // register the component here
},
所以
ThemeWrapper.vue
的完整代码可以是这样的:
<template>
<div class="vite-theme-plugin-build">
<component :is="menuLauncherComponent"></component>
<div style="color: red" v-if="test1">Is Rendered from Theme Wrapper</div>
</div>
</template>
<script lang="ts">
import type { App, Component } from "vue";
type Framework = {
app: App;
externalComponents: {
ThemeWrapper: Component;
MenuLauncher: Component;
};
};
export default {
name: "ThemeWrapper",
data() {
return {
menuLauncherComponent: null,
};
},
setup() {
return {
test1: true,
};
},
mounted() {
this.menuLauncherComponent = (window as any).externalComponents.MenuLauncher; // register the component here
},
};
</script>
我在这个存储库上对此进行了测试。