module-federation / vite

Vite Plugin for Module Federation
MIT License
307 stars 22 forks source link

Unable to run host or remote using dev server if a base url is defined #159

Open JamesMHenderson opened 1 week ago

JamesMHenderson commented 1 week ago

If your vite config contains a url in the base config the application fails to load, as modules are attempted to be loaded from a path not including the base url

Example config

export default defineConfig({
  base: '/conductor/remotes/current',
  plugins: [
    react(),
    federation({
      name: 'current',
      filename: 'remoteEntry.js',
      // Modules to expose
      exposes: {
        './Page': './src/Page.tsx',
      },
      shared: {
        ...dependencies,
        '@redwood/react-components': {
          requiredVersion: dependencies['@redwood/react-components'],
        },
      },
    }),
  ],
  server: {
    port: 3001,
    strictPort: true,
    host: true,
  },
  preview: {
    port: 3001,
    host: true,
    strictPort: true,
  },
  build: {
    target: 'ES2022',
  },
});

when you start the dev server up using the command vite --host the app fails to load as it fails to load virtual modules

image image

If you browse to one of the files it fails to load you get the error

The server is configured with a public base URL of /conductor/remotes/current - did you mean to visit [/conductor/remotes/current/@id/virtual:mf-exposes](http://localhost:3001/conductor/remotes/current/@id/virtual:mf-exposes) instead?

This module is exposed from http://localhost:3001/conductor/remotes/current/@id/virtual:mf-exposes as expected


    export default {

        "./Page": async () => {
          const importModule = await import("/conductor/remotes/current/src/Page.tsx")
          const exportModule = {}
          Object.assign(exportModule, importModule)
          Object.defineProperty(exportModule, "__esModule", {
            value: true,
            enumerable: false
          })
          return exportModule
        }

  }

//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInZpcnR1YWw6bWYtZXhwb3NlcyJdLCJzb3VyY2VzQ29udGVudCI6WyJcbiAgICBleHBvcnQgZGVmYXVsdCB7XG4gICAgXG4gICAgICAgIFwiLi9QYWdlXCI6IGFzeW5jICgpID0+IHtcbiAgICAgICAgICBjb25zdCBpbXBvcnRNb2R1bGUgPSBhd2FpdCBpbXBvcnQoXCIvY29uZHVjdG9yL3JlbW90ZXMvY3VycmVudC9zcmMvUGFnZS50c3hcIilcbiAgICAgICAgICBjb25zdCBleHBvcnRNb2R1bGUgPSB7fVxuICAgICAgICAgIE9iamVjdC5hc3NpZ24oZXhwb3J0TW9kdWxlLCBpbXBvcnRNb2R1bGUpXG4gICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydE1vZHVsZSwgXCJfX2VzTW9kdWxlXCIsIHtcbiAgICAgICAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgICAgICAgZW51bWVyYWJsZTogZmFsc2VcbiAgICAgICAgICB9KVxuICAgICAgICAgIHJldHVybiBleHBvcnRNb2R1bGVcbiAgICAgICAgfVxuICAgICAgXG4gIH1cbiAgIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0EsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDcEIsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNKLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQy9CLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUN0RixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNqQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsWUFBWSxDQUFDO0FBQ25ELENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM3RCxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFDeEIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsS0FBSztBQUM3QixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNaLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFlBQVk7QUFDN0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDVCxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNOLENBQUMsQ0FBQyxDQUFDO0FBQ0gsQ0FBQyJ9
rubiks-cube commented 1 week ago

try adding hostname as well in base url

zhangHongEn commented 1 week ago

vite.config set server.origin

gioboa commented 1 week ago

@JamesMHenderson have you tested these solutions?

JamesMHenderson commented 1 week ago

@gioboa I've tried both suggestions and I get the same issue

rubiks-cube commented 1 week ago

In addition to having hostname in base config in remote, are you using type:module in host config for this remote? for e.g.

remotes: {
      current:{
        name: 'current',
        entry: 'http://localhost:5174/remoteEntry.js',
        type:"module"
    }
} 
agudlc commented 6 days ago

I had this problem earlier in my config, i don't know if the solution is good but is working. I just add the complete path that i want in the base like "http://localhost:3001/conductor/remotes/current/". This create some duplication when i run preview in localhost but it's working normal when i get modules in the host app.

JamesMHenderson commented 6 days ago

In addition to having hostname in base config in remote, are you using type:module in host config for this remote? for e.g.

remotes: {
      current:{
        name: 'current',
        entry: 'http://localhost:5174/remoteEntry.js',
        type:"module"
    }
} 

Yes I am

JamesMHenderson commented 6 days ago

I had this problem earlier in my config, i don't know if the solution is good but is working. I just add the complete path that i want in the base like "http://localhost:3001/conductor/remotes/current/". This create some duplication when i run preview in localhost but it's working normal when i get modules in the host app.

This was the suggestion from @rubiks-cube which I tried and didn't resolve the problem

Eliwang4264 commented 6 days ago

I also encountered the same problem. I tried adding hostname as well in base url and set server.origin, but it didn't seem to work. Here is my viteconfig file, oh btw it's a .mts file

WXWorkCapture_1729141779185
mzglinski commented 6 days ago

It's a similar issue for me, I resolved it with the following patch but I don't know if it covers all edge cases.

This patch assumes that base is an absolute prefix, eg /_layout.

diff --git a/node_modules/@module-federation/vite/lib/index.cjs b/node_modules/@module-federation/vite/lib/index.cjs
index 3f608c4..72ca20a 100644
--- a/node_modules/@module-federation/vite/lib/index.cjs
+++ b/node_modules/@module-federation/vite/lib/index.cjs
@@ -37,6 +37,7 @@ var addEntry = function addEntry(_ref) {
   var devEntryPath = entryPath.startsWith('virtual:mf') ? '/@id/' + entryPath : entryPath;
   var entryFiles = [];
   var htmlFilePath;
+  var base;
   var _command;
   return [{
     name: 'add-entry',
@@ -44,6 +45,8 @@ var addEntry = function addEntry(_ref) {
     config: function config(_config, _ref2) {
       var command = _ref2.command;
       _command = command;
+      base = _config.base.endsWith('/') ? _config.base.slice(0, -1) : _config.base;
+      devEntryPath = base + devEntryPath;
     },
     configureServer: function configureServer(server) {
       var _server$httpServer;
@@ -56,7 +59,8 @@ var addEntry = function addEntry(_ref) {
           next();
           return;
         }
-        if (req.url && req.url.startsWith(fileName.replace(/^\/?/, '/'))) {
+        if (req.url && req.url.startsWith((base + '/' + fileName).replace(/^\/?/, '/'))) {
+
           req.url = devEntryPath;
         }
         next();
@@ -671,7 +675,8 @@ var Manifest = function Manifest() {
           next();
           return;
         }
-        if (req.url === mfManifestName.replace(/^\/?/, '/')) {
+        
+        if (req.url === `${server.config.base}${mfManifestName}`.replace(/^\/?/, '/')) {
           res.setHeader('Content-Type', 'application/json');
           res.setHeader('Access-Control-Allow-Origin', '*');
           res.end(JSON.stringify(_extends({}, generateMFManifest({}), {
gioboa commented 5 days ago

@mzglinski Can you drop a PR with this fix pls?

zhangHongEn commented 5 days ago

@mzglinski Please provide a reproduction demo first. If server.origin doesn’t meet the requirements, feel free to submit a PR.​

zhangHongEn commented 5 days ago

The base for a remote cannot be set to an absolute path.​

mzglinski commented 5 days ago

@gioboa I'm not confident that this is a proper fix and won't break other use cases. As I mentioned, it makes assumptions regarding base configuration, eg you cannot use a domain in it.

@zhangHongEn is it a specification requirement? The local setup that I'm using utilizes docker and proxy allowing the services to serve under the same domain. For example

https://project.localhost/_layout <- this is a remote
https://project.localhost <- first host
https://project.localhost/service-b <- second host

Without the patch, it works with production builds if I set

getPublicPath: `function() {return window.location.origin + '/_layout/'}`

in the configuration of the remote.

The dev mode was not working, with the patch it does. I've just rechecked different options passed to server.origin and couldn't get it to work. I will prepare a reproduction repo later.

zhangHongEn commented 5 days ago

@mzglinski Understood. If your host and remote are on the same domain during the dev mode, it can indeed support setting the base to an absolute path.​

zhangHongEn commented 5 days ago

@mzglinski Can you drop a PR with this fix pls?

@mzglinski I previously thought this was an unnecessary feature, but as @gioboa mentioned, you are welcome to fix this issue.​

gioboa commented 5 days ago

We will test the PR before release the fix, don't worry about that @mzglinski