embroider-build / ember-auto-import

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

Support the node conditional export for fastboot #338

Open asakusuma opened 3 years ago

asakusuma commented 3 years ago

This is a feature request to use the "node" conditional export for the fastboot build.

https://nodejs.org/api/packages.html#packages_conditional_exports

I ran into this problem while using the uuid npm module, which has a different export for node vs the browser: https://github.com/uuidjs/uuid/blob/master/package.json#L23

ef4 commented 1 year ago

This is still an issue.

It's not impossible to implement, but it's not easy to do without doubling build times, given how fastboot and webpack work. The simple implementation is to do the whole build twice, once for browser and once for fastboot, but that is very expensive.

Embroider does take that double-build approach, but only in production builds. I was able to confirm that in an embroider production build, this patch is all that's required to make the reproduction from #555 work:

diff --git a/packages/webpack/src/ember-webpack.ts b/packages/webpack/src/ember-webpack.ts
index 31d3d320..9fb4fe19 100644
--- a/packages/webpack/src/ember-webpack.ts
+++ b/packages/webpack/src/ember-webpack.ts
@@ -269,6 +269,13 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager
       },
       resolve: {
         extensions: resolvableExtensions,
+        ...(() => {
+          if (variant.runtime === 'fastboot') {
+            return { conditionNames: ['node'] };
+          } else {
+            return {};
+          }
+        })(),
       },
       resolveLoader: {
         alias: {

The problem is, even in Embroider we only do the double build for production, because it's so expensive. In development we layer fastboot-only and browser-only features into a single build with runtime switching between them. And since this change of conditionNames has global effects in webpack, we couldn't make it work correctly in our development builds without some much more complicated solution.

The root assumption here that is making this hard is that early on in the design of fastboot it was decided that we don't directly run your modules in fastboot. Instead they go through the entire build process, and we run the output of the build process in node. Like many of the things I'm trying to fix via embroider, this was the outcome of giving addons way too much power to use arbitrary code to emit more code. I think an app with only v2 addons is much closer to being able to just evaluate directly in node, with only some thin transformation.