module-federation-examples icon indicating copy to clipboard operation
module-federation-examples copied to clipboard

Using Vue3 App in Vue2 Shell

Open sirajtechy opened this issue 3 years ago • 3 comments

I followed the Vue2 in Vue3 example and trying to do the opposite approach of it since my complete app is running on Vue2 and its merely a huge shift to move Vue3 and hence writing a new module with Vue3 and trying to integrate that app in V2 shell in a MF way . I am able to run the independent V3 app with MF config but when I try to consume it in V2 I encounter a below error.

consumes:143 Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/vue/vue
    at __webpack_require__.m.<computed> (consumes:143:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./src/main.js (log.js:59:1)
    at __webpack_require__ (bootstrap:24:1)
    at startup:6:1
    at startup:6:1

Sharing my two webpack files as well

V3 Webpack config

const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
// const deps = require("./package.json").dependencies;
module.exports = (env = {}) => ({
  mode: 'development',
  cache: false,
  devtool: 'source-map',
  optimization: {
    minimize: false,
  },
  entry: path.resolve(__dirname, './src/main.js'),
  output: {
    publicPath: 'http://localhost:3002/',
  },
  resolve: {
    extensions: ['.vue', '.jsx', '.js', '.json'],
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader',
      },
      {
        test: /\.png$/,
        use: {
          loader: 'url-loader',
          options: { limit: 8192 },
        },
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {},
          },
          'css-loader',
        ],
      }
    ],
  },
  plugins: [
    new VueLoaderPlugin(),
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
    new ModuleFederationPlugin({
      name: 'vue3App',
      filename: 'remoteEntry.js',
      exposes: {
        './Button': './src/components/Button',
      }
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, './index.html'),
    }),

  ],
  devServer: {
    static: {
      directory: path.join(__dirname),
    },
    compress: true,
    port: 3002,
    hot: true,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
    },
  },
});

V2 webpack config

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require("./package.json").dependencies;
module.exports = (env = {}) => ({
  mode: 'development',
  cache: false,
  devtool: 'source-map',
  optimization: {
    minimize: false,
  },
  entry: path.resolve(__dirname, './src/main.js'),
  output: {
    publicPath: 'http://localhost:3001/',
  },
  resolve: {
    extensions: ['.vue', '.jsx', '.js', '.json'],
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader',
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {},
          },
          'css-loader',
        ],
      },
    ],
  },
  plugins: [
    new VueLoaderPlugin(),
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
    new ModuleFederationPlugin({
      name: 'vue2',
      filename: 'remoteEntry.js',
      remotes: {
        vue3App: 'vue3App@http://localhost:3002/remoteEntry.js',
      },
      shared: {
        ...deps,
        vue: {
          eager:true,
          singleton:true,
          requiredVersion:deps.vue
        }
      }
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, './index.html'),
    }),
  ],
  devServer: {
    static: {
      directory: path.join(__dirname),
    },
    compress: true,
    port: 3001,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
    },
  },
});

@ScriptedAlchemy Pls tell me what am I missing here ?

sirajtechy avatar Jun 06 '22 12:06 sirajtechy

Is your entrypoint a dynamic import bootstrap?

ScriptedAlchemy avatar Jun 08 '22 23:06 ScriptedAlchemy

@ScriptedAlchemy yes . it is . Also I fixed the above issue now but the V2 component unable to consume the V3 on a flip side . !

https://github.com/siraj-ghl/vue-micro-app-poc

Trying out a POC on the above issue . I am able to expose the remoteEntry file and able to consume the same on V2 but its not rendering on the DOM . It seems to be weird not sure what is missing here

sirajtechy avatar Jun 13 '22 11:06 sirajtechy

@ScriptedAlchemy

Vue 3 webpack chunk snapshot

Screenshot 2022-06-13 at 6 16 45 PM

Vue 2 webpack chunk screenshot Screenshot 2022-06-13 at 6 17 40 PM

sirajtechy avatar Jun 13 '22 12:06 sirajtechy

Hi @sirajtechy , I am trying to do the same ,instead of Vue3 I am trying to render React in Vue 2 as my whole application is in Vue2 and migration is very difficult. I am able to render it using a shim file but when I use react-router in the react application it is failing. @ScriptedAlchemy Is there any example to render React in Vue2 using react-router, if so please point it out as it would help me a lot. Thanks for your amazing contribution. :)

Saicasm avatar Mar 17 '23 06:03 Saicasm