vite-plugin-federation icon indicating copy to clipboard operation
vite-plugin-federation copied to clipboard

Bug with `importShared`

Open BEGEMOT9I opened this issue 3 years ago • 12 comments

Versions

Reproduction

I can add it, if u need)

Steps to reproduce

For example, we have remote vite app with config:

// vite.config.ts
const config = {
  build: {
    target: 'esnext',
  },
  plugins: [
    react(),
    federation({
      name: 'remote',
      filename: 'remoteEntry.js',
      exposes: {
        // IMPORTANT!!! Entry to `index`
        './Button': './src/components/Button/index.ts',
      },
      shared: [
        {
          react: {
            singleton: true,
            import: true,
          },
          'react-dom': {
            singleton: true,
            import: true,
          },
          'ui-components': {
            import: true,
          },
        },
      ],
    }),
  ],
}

And Button component:

// src/components/Button/index.ts
export * from './component';
// src/component/Button/component.tsx
import { type FC, useEffect, useState } from 'react';

import { type ButtonProps, Button as UIButton } from 'ui-components';

export const Button: FC<Omit<ButtonProps, 'children'>> = (props) => {
  const [text, setText] = useState('Init...');

  useEffect(() => {
    setText('Inited!');
  }, []);

  return <UIButton {...props}>{text}</UIButton>;
};

When is bundled i've got some code in __federation_expose_Button.js:

import{B as r}from"./component.81d3bf23.js";export{r as Button};

And in component.81d3bf23.js:

import { r as t } from './__federation_shared_react.js';
import { j as o, Button as n } from './[email protected]';
// code of Button

The problem is that in this case, the imports of shared modules are not wrapped in the importShared and, when using a remote, the assembled versions of the shared modules of the remote, not the host, are loaded. If i change expose entry to './Button': './src/components/Button/component.tsx',, code in component.tsx transpiled fine with importShared:

import { importShared as e } from './__federation_fn_import.js';
const { r: t } = await e('react'),
  { j: s, Button: c } = await e('@platformecoUi-components'),
// code of Button

As I understand it, the logic for determining the need for import transpilation is here: https://github.com/originjs/vite-plugin-federation/blob/main/packages/lib/src/prod/shared-production.ts#L297. Therefore two questions:

  1. will imports be transpiled in child chunks of the remote correctly?
  2. is there a way to get around this bug?

What is Expected?

importShared must be used for all shared-imports under the remoteEntry

What is actually happening?

See above

BEGEMOT9I avatar Mar 15 '22 10:03 BEGEMOT9I

Thanks, I probably see what you mean, it's a real problem

Jiannan-dev avatar Mar 15 '22 12:03 Jiannan-dev

Thank u for this package) Do u need some details?

BEGEMOT9I avatar Mar 15 '22 13:03 BEGEMOT9I

Thank u for this package) Do u need some details?

If you can provide a simple example, that would be great, but if not, that's fine, I probably know the problem, but this change can be a bit tricky, especially for applications with a lot of components, and may extend the packaging time considerably.

Jiannan-dev avatar Mar 16 '22 06:03 Jiannan-dev

Sry, but there is no time yet, so I won’t be able to drop the repo in the near future

BEGEMOT9I avatar Mar 17 '22 06:03 BEGEMOT9I

Sry, but there is no time yet, so I won’t be able to drop the repo in the near future

It's okay. I can reproduce the problem myself.

Jiannan-dev avatar Mar 17 '22 06:03 Jiannan-dev

@BEGEMOT9I this issue look like "problem 2" of #147 image the latest version fix above bug, and can this issue reproduce now?

Timehello avatar Mar 23 '22 03:03 Timehello

@Timehello Thank you for your contribution to this bug,but there seems to be some problems in some other scenarios, it looks like the problem is easy to fix,if you have time, can you try the following

  1. If the exposed component code does this it can cause problems(on my machine it will output an empty file)
export * from './Button'
  1. but if you do it another way it works fine
import Button from "./Button";
export {Button}

Jiannan-dev avatar Mar 23 '22 04:03 Jiannan-dev

@ruleeeer ok, I try to reproduce on my machine first

Timehello avatar Mar 23 '22 05:03 Timehello

@ruleeeer I can't reproduce on my machine, is something I miss? originjs: "@originjs/[email protected]" node: v14.17.3

// code before build
export * from './c-a'
// code after build
export { a } from './c-a.fb95e105.js';
// code of c-a
import { c as C } from './c-c'

export function a () {
  return (
    <div>
      c-a
      <C />
    </div>
  )
}

Timehello avatar Mar 23 '22 07:03 Timehello

@Timehello I'll try to reproduce it on my machine later, sorry, maybe it's a problem with the environment

Jiannan-dev avatar Mar 24 '22 01:03 Jiannan-dev

@Timehello no, it's not the same problem) Exposed chunks imports local shared deps instead of host, bcs they have no importShared wrapper

BEGEMOT9I avatar Mar 24 '22 06:03 BEGEMOT9I

Hi, Any update on this issue ?

I am using this plugin to include a child React application in a host React application. But the react shared dependency is being loaded twice.

It seems the child react application is importing the local shared dependencies as per @BEGEMOT9I comment.

midhunadarvin avatar Jun 21 '23 10:06 midhunadarvin