vue.jsviteantdmicro-frontendant-design-vue

Unable to get Ant Design to work with Vue 3 micro frontend app


I'm using vite-plugin-federation to create a micro frontend app using Vue 3. There is a remote app that exposes components and there's a host app that is going to consume those components. I've been successfully able to federate simple and nested components from the remote app to the host, but the components that are based on Ant Design (antd) do not render on the host.

Here's a component as an example:

BasicComponent.vue

<template>
    <span>This is a basic component</span>
    
    <a-button type="primary">Basic Ant Button</a-button>

    <SubComponent />
</template>
<script setup>
import SubComponent from "./SubComponent.vue"
</script>

Here's my vite.config.js file for the remote:

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import federation from "@originjs/vite-plugin-federation";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    federation({
      name: "remote",
      filename: "remoteEntry.js",
      exposes: {
        "./Header": "./src/components/Header.vue",
        "./BasicComponent": "./src/components/BasicComponent.vue",
      },
      shared: ["vue", "ant-design-vue", "@ant-design/icons-vue", "vue-router"],
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  build: {
    modulePreload: false,
    target: "esnext",
    minify: false,
    cssCodeSplit: false,
  },
});

And here's the vite.config.js file for the host:

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import federation from "@originjs/vite-plugin-federation";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    federation({
      name: "host",
      remotes: {
        remoteApp: "http://localhost:5001/assets/remoteEntry.js",
      },
      shared: ["ant-design-vue", "@ant-design/icons-vue", "vue-router"],
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  build: {
    modulePreload: false,
    target: "esnext",
    minify: false,
    cssCodeSplit: false,
  },
});

Here's the main.js (on both the remote and the host)

import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';

const app = createApp(App)

app.use(router)

app.use(Antd)

app.mount('#app')

And here's how I'm trying to use the BasicComponent on the host:

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/Home.vue'
import BasicComponent from 'remoteApp/BasicComponent'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
    },
    {
      path: '/basic',
      name: 'Basic',
      component: BasicComponent
    },
  ]
})

export default router

I've tried with both sharing and not sharing ant-design-vue in the vite.config.js file but to no success. The <a-button> renders into <button> perfectly on the remote app but remains <a-button> when used in the host app. Also, there are no errors or warning on the web browser's developer console.


Solution

  • So, I was able figure this out. The vite.config.js for the host needed to have vue shared the same way as the remote. So, instead of:

    shared: ["ant-design-vue", "@ant-design/icons-vue", "vue-router"],
    

    it had to be:

    shared: ["vue", "vue-router"],
    

    I had to deal with the following error when I added vue to the shared list on host:

    Top-level await is not available in the configured target environment

    But thanks to vite-plugin-top-level-await package, I was able to work around that. This other thread mentioned adding build.target: "esnext" but I already had it in my vite.config.js so it wasn't working for me.

    The antd (Ant Design) packages didn't have to be shared on host and it seems that the shared vue creates some kind of context necessary for the design framework to function.