embroider-build / ember-auto-import

Zero config import from npm packages
Other
360 stars 109 forks source link

Webpack 5 Module Federation #455

Open billyjov opened 3 years ago

billyjov commented 3 years ago

Hi, Does anyone got Webpack 5 Module federation with Ember works together? i tried it so far and I get following errors when it come to integrate with the host app:

wrapper.component.ts:23 error loading ember-landscapes-app: TypeError: Cannot read properties of undefined (reading 'length')
    at includes (should-preserve-symlinks.js:1)
    at module.exports (should-preserve-symlinks.js:1)
    at eval (resolve-package-path.js:17)
    at Object../node_modules/resolve-package-path/lib/resolve-package-path.js (chunk.vendors-node_modules_ember-resolver_index_js.59ad9791bbda2580268b.js:212)
    at __webpack_require__ (remoteEntry.js:44)
    at eval (index.js:1)
    at Object../node_modules/resolve-package-path/index.js (chunk.vendors-node_modules_ember-resolver_index_js.59ad9791bbda2580268b.js:179)
    at __webpack_require__ (remoteEntry.js:44)
    at eval (dependency-version-checker.js:1)
    at Object../node_modules/ember-cli-version-checker/src/dependency-version-checker.js (chunk.vendors-node_modules_ember-resolver_index_js.59ad9791bbda2580268b.js:49)

Here is my Webpack config (inside the ember-cli-build.js):

webpack: {
        resolve: {
          // https://stackoverflow.com/a/47665710/6432698
          symlinks: false,
          modules: ['node_modules'],
          alias: {
            landscape: path.resolve(__dirname, 'app/'),
          },
          fallback: {
            path: require.resolve('path-browserify'),
            os: false,
            fs: false,
            tls: false,
            net: false,
            zlib: false,
            http: false,
            https: false,
            stream: false,
            process: require.resolve('process/browser'),
          },
        },
        // entry: './app/controllers/landscapes.ts',
        entry: './app/app.js',
        output: {
          filename: 'landscapes.js',
          publicPath: 'http://localhost:4500/assets/',
          uniqueName: 'landscapes',
        },
        optimization: {
          // Only needed to bypass a temporary bug
          // runtimeChunk: false,
        },
        // node: {
        //   global: true,
        // },
        plugins: [
          new ModuleFederationPlugin({
            name: 'bundle',
            library: { type: 'var', name: 'landscapes' },
            filename: 'remoteEntry.js',
            exposes: {
              './web-components': './app/app.js',
            },
            shared: [
              'ember-fetch',
              '@glimmer/component',
              '@glimmer/tracking',
              '@ember/optional-features',
              'ember-bootstrap',
              'ember-data',
              'ember-export-application-global',
              'ember-fetch',
              'ember-resolver',
              'ember-source',
              'ember-svg-jar',
            ],
          }),
          // new HtmlWebpackPlugin({
          //   template: './app/index.html',
          // }),
          // //https://newbedev.com/webpack-bundle-js-uncaught-referenceerror-process-is-not-defined
          new webpack.ProvidePlugin({
            process: 'process/browser',
          }),
        ],
      },

The demo repository can be found here : https://github.com/billyjov/ember-webpack-issue . Any Idea what i'm doing wrong ? Thanks

ef4 commented 2 years ago

There's a lot going on in that example (and I think it has a broken lerna config and misleading instructions about npm vs yarn since it has a package-lock.json and not a yarn.lock). In general, your example probably has way too much in its autoImport.webpack config. For example, it doesn't really make sense to try to override all of entry and output. ember-auto-import is already using those to manage the boundary between webpack and the classic ember build pipeline. You're allowed to create additional entrypoints, but replacing the stock ones is going to break.

Stepping back to the high level: first, it's important to distinguish between pulling federated code into an ember app and sending federated code out of an ember app. I'm not exactly sure which of those you're trying to do, because the ModuleFederationPlugin docs don't document some of the options you're using.

If you're trying to pull code into the ember app, I would expect that to work without any particular trouble. For example, consuming federated web components that render inside the ember app seems like a good use case for federation. If this isn't working, try making a much smaller reproduction of an empty ember app with just ModuleFederationPlugin consuming a trivial module via federation, with a plain webpack project serving the trivial federated module.

On the other hand, if you're trying to send code out of the ember app, that's not going to work because ember-auto-import doesn't handle the app's own code at all. This is the big difference between ember-auto-import and embroider. ember-auto-import uses a webpack build only for the third-party dependencies and manages linking them into the classic non-webpack build pipeline that builds the app. Whereas embroider builds the whole app and dependencies with webpack.

And if you're trying to make some of the components in the ember app into federated web components, more is going to be required than just getting the build system to package them up for you. Typical components in an ember app depend implicitly on many things that aren't visible as module imports. They rely on runtime resolution of the other components, helpers, modifiers, and services that they use. And they implicitly depend on glimmer's rendering engine being present.

It's possible to write shared ember components that are much more portable, but it's not how today's typical apps do it. A big part of why we're investing heavily in Embroider as well as core features like strict mode templates is precisely to streamline how components work in ember so they're much less magical and more legible to generic Javascript tooling.

billyjov commented 2 years ago

Thanks @ef4 and sorry for my late answer.

What I wanted to achieve was to make a complete Ember application visible from the outside. In principle, I would have thought that certain components in the Ember could be made available (as remote) for a host application with the help of module federation. I now realize that it would be difficult to achieve with ember-auto-import, as it only takes care of third-party dependencies.

If you're trying to pull code into the ember app, I would expect that to work without any particular trouble.

Do you mean that, for example, a React application that is activated as a remore app with module federation can be consumed by an Ember app? Because according to your statement it would not work with two ember apps (where one consumes the other)

ember-auto-import uses a webpack build only for the third-party dependencies and manages linking them into the classic non-webpack build pipeline that builds the app. Whereas embroider builds the whole app and dependencies with webpack.

Will it be in the near future to use Embroider completely for the use case. i.e. to consume a complete application as a remote federated module per runtime? I could read from the documentation from Embroier that a current migration from apps to Embroider could be problematic in some places, that some add-ons would not be compatible as a result?

ef4 commented 2 years ago

Do you mean that, for example, a React application that is activated as a remore app with module federation can be consumed by an Ember app?

Yes, as long as you know which modules to import out of the react app and how to pass them a Dom element to render into, you could do it all as a custom modifier in an ember app, like:

<div {{render-react-component this.thing }} />

Will it be in the near future to use Embroider completely for the use case

Apps are definitely already going to production with Embroider, if that's what you mean. I don't know of anybody who is experimenting with module federation, but since an Embroider app is just using webpack and webpack supports federation, I think federation should work.

billyjov commented 2 years ago

Thanks @ef4. I will give a try with a small ember app + Embroider and see how this can be exposed to be consume in another app as remote app.

alexmorrise commented 2 years ago

@ef4 @billyjov Has anyone been able to get Module Federation to work in Ember (i.e. with Ember as the Host application)? I've tried it using both Broccoli/ember-auto-import and Embroider and while both of them get mad at me if the ModuleFederationPlugin is incorrectly configured, neither has any mention of the remotes in any of the dist files.

miketervela commented 2 years ago

@billyjov Did you ever make progress consuming Ember as a remote app?

ef4 commented 2 years ago

There is an active project right now to spike out module-federation for independently deploying different parts (probably engines) of a big ember app: https://github.com/wycats/rsg-federation-spike

miketervela commented 2 years ago

@ef4 Do you know if it's currently possible to pull an Ember app into another app as local modules or is that part of the effort for mod fed? I was playing around with stage 2 of embroider but couldn't resolve the modules in vendor.js. Keep meaning to go back and look at the custom webpack stage.

Edit: Nevermind, looks like the current effort is Ember->Ember mod fed

rchrdschfr commented 1 year ago

Has anyone been able to successfully use an Ember app as a host to pull in federated modules from other apps? I have attempted to use ModuleFederationPlugin in the webpackConfig plugins, specifying the remotes which I want to pull in. However when I hit the import() statement, I get an error in the console saying that the module could not be found, which tells me that my Ember host is not registering the remotes I am specifying.

I get the same module not found error when running the project in https://github.com/wycats/rsg-federation-spike. @ef4

mikah1337 commented 1 year ago

Has anyone been able to successfully use an Ember app as a host to pull in federated modules from other apps? I have attempted to use ModuleFederationPlugin in the webpackConfig plugins, specifying the remotes which I want to pull in. However when I hit the import() statement, I get an error in the console saying that the module could not be found, which tells me that my Ember host is not registering the remotes I am specifying.

I get the same module not found error when running the project in https://github.com/wycats/rsg-federation-spike. @ef4

Anyone have a working example of this? Any progress made?

More specifically, where Ember is the host and the remote is a React app from another repository