module-federation / core

Module Federation is a concept that allows developers to share code and resources across multiple JavaScript applications
https://module-federation.io/
MIT License
1.49k stars 226 forks source link

[native-federation-tests] error with entry point cannot be marked as external #744

Closed erickbelfy closed 1 year ago

erickbelfy commented 1 year ago

with a given module-federation config

{
  name: 'AuthenticationApp',
  filename: 'authentication-ui/remoteEntry.js',
  remotes: {},
  exposes: {
    './LoginPage': './src/federated/RemoteLoginPage',
    './ResetPasswordPage': './src/federated/RemoteResetPasswordPage',
    './Routes': './src/federated/routes',
    './Context': './src/contexts',
    './Interceptors': './src/Interceptors',
    './Middlewares': './src/Middlewares',
    './reactAdminAuth': './src/reactAdminAuth',
    './FeatureFlags': './src/FeatureFlags'
  },
  shared: {
    '@emotion/react': { requiredVersion: '^11.10.5' },
    '@emotion/styled': { requiredVersion: '^11.10.5' },
    '@hookform/error-message': '^2.0.1',
    '@hookform/resolvers': '^2.9.10',
    '@mui/icons-material': { requiredVersion: '^5.11.0', singleton: true },
    '@mui/material': { requiredVersion: '^5.11.7', singleton: true },
    '@mui/styles': '^5.11.7',
    '@mui/x-date-pickers': '^5.0.16',
    '@onespan/components': { requiredVersion: '^0.15.0', singleton: true },
    '@oss-ui/express-server': '^1.10.4',
    axios: '1.3.4',
    'axios-hooks': '^4.0.0',
    clsx: '^1.2.1',
    express: '^4.18.2',
    'express-http-proxy': '^1.6.3',
    'express-pino-logger': '^7.0.0',
    'http-status-codes': '^2.2.0',
    immer: '^9.0.16',
    'jwt-decode': '^3.1.2',
    lodash: '^4.17.21',
    pluralize: '^8.0.0',
    polished: '^4.2.2',
    'ra-data-json-server': '^4.6.2',
    'ra-i18n-polyglot': '^4.7.2',
    'ra-language-english': '^4.7.2',
    'ra-language-french': '^4.7.2',
    react: '^18.2.0',
    'react-admin': { requiredVersion: '4.8.1', singleton: true },
    'react-dom': '^18.2.0',
    'react-error-boundary': '^3.1.4',
    'react-hook-form': '^7.31.3',
    'react-intl': '^5.25.1',
    'react-router-dom': { requiredVersion: '6.8.1', singleton: true },
    'source-map-support': '^0.5.21',
    yup: '^0.32.11'
  }
}

with the following webpack configuration

/* eslint-disable import/no-extraneous-dependencies */
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const {
  NativeFederationTestsRemote,
  // eslint-disable-next-line import/no-unresolved
} = require('@module-federation/native-federation-tests/webpack');
const {
  NativeFederationTypeScriptRemote,
  // eslint-disable-next-line import/no-unresolved
} = require('@module-federation/native-federation-typescript/webpack');
const nodePath = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { PROJECT_ID } = require('./constants');
const moduleFederationConfig = require('./mfe/module-federation.config');

const path = nodePath.resolve(__dirname, '../build');
module.exports = {
  target: 'web',
  mode: 'development',
  resolve: {
    extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
    modules: ['src', 'node_modules'],
  },
  output: {
    filename: `${PROJECT_ID}/assets/index_[contenthash].js`,
    chunkFilename: `${PROJECT_ID}/assets/chunk.[name].[contenthash].js`,
    path,
    /*
     * output.uniqueName string
     * A unique name of the webpack build to avoid multiple webpack runtimes to conflict when using globals.
     * It defaults to output.
     * Library name or the package name from package.json in the context, if both aren't found, it is set to an ''.
     * output.uniqueName will be used to generate unique globals for: output.chunkLoadingGlobal
     * more info : https://webpack.js.org/configuration/output/#outputuniquename
     * */
    uniqueName: PROJECT_ID,
    clean: true,
  },
  devtool: 'source-map',
  // force optimization false, since all module federations loads its resources on demand
  optimization: {
    runtimeChunk: false,
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx|js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react', '@babel/preset-env', '@babel/preset-typescript'],
            plugins: ['@babel/plugin-transform-runtime'],
          },
        },
      },
      {
        test: /\.json$/,
        loader: 'json-loader',
      },
      {
        test: /\.m?js/,
        type: 'javascript/auto',
        resolve: {
          fullySpecified: false,
        },
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.svg$/,
        use: ['file-loader'],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      templateParameters: {
        projectId: PROJECT_ID,
      },
      template: './public/template.ejs',
      cache: false,
      hash: true,
    }),
    new ModuleFederationPlugin(moduleFederationConfig),
    NativeFederationTypeScriptRemote({
      moduleFederationConfig,
    }),
    NativeFederationTestsRemote({
      moduleFederationConfig: {
        ...moduleFederationConfig,
      },
      distFolder: path,
      deleteTestsFolder: true,
      additionalBundlerConfig: { format: 'esm', sourcemap: true },
    }),
  ],
  infrastructureLogging: { level: 'verbose', colors: true },
};

once i build i get the message from NativeFederationTestsRemote

ESM Build failed
Unable to build federated mocks: Error: Build failed with 1 error:
error: The entry point "/Users/belfoer1/Documents/platform-ui/login/packages/client/src/reactAdminAuth/index.ts" cannot be marked as external

here's the barrel file:

export * from './authProvider/authProvider';
export * from './RaLogin';
export * from './RaResetPassword';
export * from './Admin';
export * from './dataProvider';
export * from './components';
export { tokenExchange } from './services';
export { Title, ListToolbar, List, PlatformLayout, Sidebar, FooterMenu } from './Layout';

if i comment it out the ./reactAdminAuth it works just fine, is there a way to check verbose logs? i can't see anything meaningful that could help me to debug this scenario.

ilteoood commented 1 year ago

Hi @erickbelfy, may I ask you which version of esbuild you have on your repo? Could you try to update it to the latest available?

That's a strange behavior because your exposed module is not defined in remotes or in shared, so it should not be externalized.

Are you able to provide a minimal repro?

erickbelfy commented 1 year ago

we arent using esbuild dependency in our projects, if you think it worth trying i can add it and test it out, we are using babel-loader to generate the chunks for us. i will try to build a repository containing my use case later today.

would you mind explaining to me the real usage of the esbuild package? is there a particular reason why I should use it instead of babel-loader?

Thanks!

EDIT: looking over the yarn.lock some dependencies are using 0.17.16version of esbuild

erickbelfy commented 1 year ago

here's the yarn.lock manifest related to esbuild

"@esbuild/android-arm64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/android-arm64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fandroid-arm64%2F-%2Fandroid-arm64-0.17.16.tgz"
  conditions: os=android & cpu=arm64
  languageName: node
  linkType: hard

"@esbuild/android-arm@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/android-arm@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fandroid-arm%2F-%2Fandroid-arm-0.17.16.tgz"
  conditions: os=android & cpu=arm
  languageName: node
  linkType: hard

"@esbuild/android-x64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/android-x64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fandroid-x64%2F-%2Fandroid-x64-0.17.16.tgz"
  conditions: os=android & cpu=x64
  languageName: node
  linkType: hard

"@esbuild/darwin-arm64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/darwin-arm64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fdarwin-arm64%2F-%2Fdarwin-arm64-0.17.16.tgz"
  conditions: os=darwin & cpu=arm64
  languageName: node
  linkType: hard

"@esbuild/darwin-x64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/darwin-x64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fdarwin-x64%2F-%2Fdarwin-x64-0.17.16.tgz"
  conditions: os=darwin & cpu=x64
  languageName: node
  linkType: hard

"@esbuild/freebsd-arm64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/freebsd-arm64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Ffreebsd-arm64%2F-%2Ffreebsd-arm64-0.17.16.tgz"
  conditions: os=freebsd & cpu=arm64
  languageName: node
  linkType: hard

"@esbuild/freebsd-x64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/freebsd-x64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Ffreebsd-x64%2F-%2Ffreebsd-x64-0.17.16.tgz"
  conditions: os=freebsd & cpu=x64
  languageName: node
  linkType: hard

"@esbuild/linux-arm64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-arm64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-arm64%2F-%2Flinux-arm64-0.17.16.tgz"
  conditions: os=linux & cpu=arm64
  languageName: node
  linkType: hard

"@esbuild/linux-arm@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-arm@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-arm%2F-%2Flinux-arm-0.17.16.tgz"
  conditions: os=linux & cpu=arm
  languageName: node
  linkType: hard

"@esbuild/linux-ia32@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-ia32@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-ia32%2F-%2Flinux-ia32-0.17.16.tgz"
  conditions: os=linux & cpu=ia32
  languageName: node
  linkType: hard

"@esbuild/linux-loong64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-loong64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-loong64%2F-%2Flinux-loong64-0.17.16.tgz"
  conditions: os=linux & cpu=loong64
  languageName: node
  linkType: hard

"@esbuild/linux-mips64el@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-mips64el@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-mips64el%2F-%2Flinux-mips64el-0.17.16.tgz"
  conditions: os=linux & cpu=mips64el
  languageName: node
  linkType: hard

"@esbuild/linux-ppc64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-ppc64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-ppc64%2F-%2Flinux-ppc64-0.17.16.tgz"
  conditions: os=linux & cpu=ppc64
  languageName: node
  linkType: hard

"@esbuild/linux-riscv64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-riscv64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-riscv64%2F-%2Flinux-riscv64-0.17.16.tgz"
  conditions: os=linux & cpu=riscv64
  languageName: node
  linkType: hard

"@esbuild/linux-s390x@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-s390x@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-s390x%2F-%2Flinux-s390x-0.17.16.tgz"
  conditions: os=linux & cpu=s390x
  languageName: node
  linkType: hard

"@esbuild/linux-x64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/linux-x64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Flinux-x64%2F-%2Flinux-x64-0.17.16.tgz"
  conditions: os=linux & cpu=x64
  languageName: node
  linkType: hard

"@esbuild/netbsd-x64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/netbsd-x64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fnetbsd-x64%2F-%2Fnetbsd-x64-0.17.16.tgz"
  conditions: os=netbsd & cpu=x64
  languageName: node
  linkType: hard

"@esbuild/openbsd-x64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/openbsd-x64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fopenbsd-x64%2F-%2Fopenbsd-x64-0.17.16.tgz"
  conditions: os=openbsd & cpu=x64
  languageName: node
  linkType: hard

"@esbuild/sunos-x64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/sunos-x64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fsunos-x64%2F-%2Fsunos-x64-0.17.16.tgz"
  conditions: os=sunos & cpu=x64
  languageName: node
  linkType: hard

"@esbuild/win32-arm64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/win32-arm64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fwin32-arm64%2F-%2Fwin32-arm64-0.17.16.tgz"
  conditions: os=win32 & cpu=arm64
  languageName: node
  linkType: hard

"@esbuild/win32-ia32@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/win32-ia32@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fwin32-ia32%2F-%2Fwin32-ia32-0.17.16.tgz"
  conditions: os=win32 & cpu=ia32
  languageName: node
  linkType: hard

"@esbuild/win32-x64@npm:0.17.16":
  version: 0.17.16
  resolution: "@esbuild/win32-x64@npm:0.17.16::__archiveUrl=http%3A%2F%2Frepository.dev.corp.onespan.com%2Frepository%2Fnpm-all%2F%40esbuild%2Fwin32-x64%2F-%2Fwin32-x64-0.17.16.tgz"
  conditions: os=win32 & cpu=x64
  languageName: node
  linkType: hard
erickbelfy commented 1 year ago

here's a repository that contains a repro scenario https://github.com/erickbelfy/repro-module-federation

module federation config file https://github.com/erickbelfy/repro-module-federation/blob/master/webpack/mfe/module-federation.config.js

webpack config https://github.com/erickbelfy/repro-module-federation/blob/master/webpack/common.config.js

erickbelfy commented 1 year ago

doing an investigation in your codebase i realized that there's a bug in the Regexes that the external array has.

look the following code extracted from the logs within the index.ts of native-federation-tests

{
  format: 'cjs',
  external: [
    /@emotion\/react/,
    /@emotion\/styled/,
    /@hookform\/error-message/,
    /@hookform\/resolvers/,
    /@mui\/icons-material/,
    /@mui\/material/,
    /@mui\/styles/,
    /@mui\/x-date-pickers/,
    /axios/,
    /axios-hooks/,
    /clsx/,
    /express/,
    /express-http-proxy/,
    /express-pino-logger/,
    /http-status-codes/,
    /immer/,
    /jwt-decode/,
    /lodash/,
    /pluralize/,
    /polished/,
    /ra-data-json-server/,
    /ra-i18n-polyglot/,
    /ra-language-english/,
    /ra-language-french/,
    /react/,
    /react-admin/,
    /react-dom/,
    /react-error-boundary/,
    /react-hook-form/,
" Press ? for help             |⚠   1 {
    /react-intl/,
    /react-router-dom/,
    /source-map-support/,
    /yup/,
>>  1 const { shared } = require('./shared.config');
    /@onespan\/components/
  ],
  entry: {
    './components': '/Users/belfoer1/Documents/repro-module-federation/src/components/index.ts',
    './reactAdminAuth': '/Users/belfoer1/Documents/repro-module-federation/src/reactAdminAuth/index.ts'
  },
  outDir: '/Users/belfoer1/Documents/repro-module-federation/build/@mf-tests',
  silent: false,
  target: 'esnext',
  verbose: true
} buildConfig

here the buildConfig options takes the word react-admin from my code base that is named as reactAdminAuth, somehow the regex identifies that my module is also an external dependency, the solution here is to make sure the external key ignores the src or we make a 100% matching with the folder names to ensure we are not externalizing something that we want to be in the entry

ilteoood commented 1 year ago

Ok, I should fix the regex to check for packages that starts with a certain string. Will fix that tomorrow morning. Thank you so much for the repro!

ilteoood commented 1 year ago

@erickbelfy version 0.1.2 should fix this, please try and let me know 😄 Feel free to reopen the ticket, if necessary