originjs / vite-plugin-federation

Module Federation for vite & rollup
Other
2.39k stars 241 forks source link

Shared dependancies trying to load directly from `node_modules` instead of Vite Dev Server #539

Open iamdriz opened 1 year ago

iamdriz commented 1 year ago

Versions

Steps to reproduce

We're using Vite Ruby (https://vite-ruby.netlify.app/) to run a Ruby on Rails application with a Vite front-end. In this app we want to pull in some external remotes apps using vite-plugin-federation. However it seems that the shared option causes some issues when it tries to load in the dependancies such as react etc.

Our vite.config.js on our HOST application is as follows:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import RubyPlugin from "vite-plugin-ruby";
import FullReload from "vite-plugin-full-reload";
import federation from "@originjs/vite-plugin-federation";

export default defineConfig({
  plugins: [
    react(),
    RubyPlugin(),
    FullReload(["config/routes.rb", "app/views/**/*"]),
    federation({
      name: "host",
      remotes: {
        remote_app: "http://localhost:5000/assets/remoteEntry.js",
      },
      shared: ["react", "react-dom"],
    }),
  ],
  build: {
    target: "esnext",
    minify: false,
    cssCodeSplit: false,
    modulePreload: false,
  },
});

Our vite.config.js on our REMOTE application is as follows:

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

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: "remoteApp",
      filename: "remoteEntry.js",
      exposes: {
        "./App": "./src/App",
      },
      shared: ["react", "react-dom"],
    }),
  ],
  build: {
    target: "esnext",
    minify: false,
    cssCodeSplit: false,
    modulePreload: false,
  },
  preview: {
    host: "localhost",
    port: 5000,
    strictPort: true,
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
  },
});

What is actually happening?

When we start the application we get a 404 error when it tries to load react.js:

__x00__virtual:__federation__:20 

       GET http://localhost:3000/node_modules/.vite/deps/react.js?v=0ab3fa3a net::ERR_ABORTED 404 (Not Found)
get @ __x00__virtual:__federation__:20
get @ __x00__virtual:__federation__:29
getSharedFromRuntime @ __federation_fn_import.js:385
importShared @ __federation_fn_import.js:363
(anonymous) @ __federation_expose_App.849a9f8f.js:35
remoteApp:1 Uncaught TypeError: Failed to fetch dynamically imported module: http://localhost:3000/node_modules/.vite/deps/react.js?v=0ab3fa3a

What is Expected?

It should be loading that file from:

http://localhost:3000/vite-dev/@fs/Users/cameron/Projects/app/node_modules/.vite/deps/react.js?v=0ab3fa3a

Looking into the source code (Chrome DevTools) this is due to the code using window.location.origin to load the file and NOT prefixing it with the vite-dev server location:

image

As this 'share' code is generated by this plugin, I'm assuming its an issue with how that wrapShareScope is generated. Possible this file/line here: https://github.com/originjs/vite-plugin-federation/blob/7b88529a80caa396b4e2cab6b8f120093578ac47/packages/lib/src/dev/remote-development.ts#L406

How can I resolve this? Are we able to pass some additional configuration to make this look at the correct location? As this is a big blocker and prevents any shared dependancies such as React, etc.

iamdriz commented 1 year ago

I've added a temporary hack into our Rails app that intercepts requests to /node_modules and then redirects to the Vite Dev Server which works, so it is a case of handling this URL to make it work... it would be better to have this handled by the plugin... any ideas why it's failing to do this out of the box and defaulting to the location.origin?

liu351 commented 1 year ago

seeing the same issue, one remote MFE that is running on 1.3.2 is not using the original server path to load a missing dependency and using the host's URL. But a different remote MFE running 1.2.0 is loading from the correct base href if a shared dependency is missing

Dodje commented 1 year ago

Same thing. Can't make it work. 404 for the shared vue package..

Actually, it's quite a bad situation, because we have our main project builded via nuxt3 wich is being runned on vite. And we need to somehow make it work with federation plugin.

I hope for response in not too long time... sadly it's 2 weeks already without any answer what to do :(

iamdriz commented 12 months ago

In order to make this in Rails I've had to add this controller:

class NodeModulesController < ApplicationController
  def show
    redirect_to "#{request.protocol}#{request.host_with_port}/vite-dev/@fs#{Rails.root}#{request.path}"
  end
end

And then a route that captures any requests to /nodules_modules from the client:

get '/node_modules(/*path)', to: 'node_modules#show'
pslamavertice commented 9 months ago

Same issue, workaround with proxy in vite.config

server: {
      port: 3001,
      proxy: {
        '^/node_modules': {
          target: 'http://localhost:3001',
          changeOrigin: true,
          rewrite: path => [process.cwd(), path].join(''),
        }
      }
    },
front-refined commented 1 month ago

Use pnpm's patch tool or other patch tools ✅

diff --git a/dist/index.mjs b/dist/index.mjs
index dd456fef8953a8ae8d833939db3cb0972ae65bba..9ba24e93b73ce2ba3bdb789f979bc165bbc361ec 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -1374,6 +1374,7 @@ export {__federation_method_ensure, __federation_method_getRemote , __federation
   async function devSharedScopeCode(shared) {
     const res = [];
     if (shared.length) {
+      const base = viteDevServer.config.base.slice(0,-1);
       const serverConfiguration = viteDevServer.config.server;
       const cwdPath = normalizePath(process.cwd());
       for (const item of shared) {
@@ -1391,7 +1392,7 @@ export {__federation_method_ensure, __federation_method_getRemote , __federation
         if (typeof obj === "object") {
           const origin = serverConfiguration.origin;
           const pathname = relativePath ?? `/@fs/${moduleInfo.id}`;
-          const url = origin ? `'${origin}${pathname}'` : `window.location.origin+'${pathname}'`;
+          const url = origin ? `'${origin}${pathname}'` : `window.location.origin+'${base}${pathname}'`;
           str += `get:()=> get(${url}, ${REMOTE_FROM_PARAMETER})`;
           res.push(`'${sharedName}':{'${obj.version}':{${str}}}`);
         }