You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3+Vite嵌入组件:如何封装内置Vue避免冲突?

问题描述

我用Vue 3和Vite开发一款可嵌入的Widget组件,打算通过Vue的defineCustomElement特性实现。相关代码如下:

widget.js 文件

import { createApp, defineCustomElement } from "vue";
import Widget from "./components/Widget.ce.vue";

const TestWidget = defineCustomElement(Widget);
customElements.define("test-widget", TestWidget);

vite.config.js 文件

import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
    build: {
        rollupOptions: {
            input: {
                widget: "resources/js/widget.js",
            },
            output: {
                entryFileNames: `assets/[name].js`,
                chunkFileNames: `assets/[name].js`,
                assetFileNames: `assets/[name].[ext]`,
            },
        },
    },
});

把widget.js引入其他网站,加个<test-widget />标签就能正常跑,但如果那个网站本身已经引入了Vue包,就会出现一堆JS错误。能不能把组件内置的Vue封装起来,避免冲突?

解决方案

当然可以,核心就是让你的Widget用独立的Vue实例,不跟宿主网站的Vue共享全局作用域。具体操作步骤:

1. 配置Vite让Vue打包进Widget并启用沙箱

修改vite.config.js,调整Vue插件和Rollup构建配置,确保Vue被打包进Widget文件,且运行在沙箱里:

import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
    plugins: [
        vue({
            customElement: true,
            template: {
                compilerOptions: {
                    // 标记自己的自定义元素,避免Vue编译报错
                    isCustomElement: tag => tag === 'test-widget'
                }
            }
        }),
        laravel()
    ],
    build: {
        rollupOptions: {
            input: {
                widget: "resources/js/widget.js",
            },
            output: {
                entryFileNames: `assets/[name].js`,
                chunkFileNames: `assets/[name].js`,
                assetFileNames: `assets/[name].[ext]`,
            },
            // 不要把Vue设为外部依赖,强制打包进Widget
            external: []
        },
        // 禁用模块预加载,避免依赖宿主环境
        modulePreload: {
            polyfill: false
        }
    },
    resolve: {
        // 指定使用Vue的ESM打包版本,确保完全独立
        alias: {
            'vue': 'vue/dist/vue.runtime.esm-bundler.js'
        }
    }
});

2. 调整Widget入口文件,移除全局Vue依赖

修改widget.js,去掉不必要的createApp,只保留自定义元素注册逻辑,同时避免重复注册:

import { defineCustomElement } from "vue";
import Widget from "./components/Widget.ce.vue";

const TestWidget = defineCustomElement(Widget);
// 先检查元素是否已注册,防止重复定义报错
if (!customElements.get('test-widget')) {
    customElements.define("test-widget", TestWidget);
}

3. 验证效果

构建完成后,打开生成的widget.js,如果里面包含了Vue的runtime代码,就说明配置成功了。这时你的Widget会在自己的隔离环境里运行,不管宿主网站有没有Vue,都不会产生冲突。

内容的提问来源于stack exchange,提问作者Pennywise96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 15:45:25