Skip to content

feat(dev): make browser Node polyfills opt-in - #7269

Merged
markdalgleish merged 5 commits into
release-nextfrom
markdalgleish/browser-node-polyfills
Aug 29, 2023
Merged

markdalgleish merged 5 commits into
release-nextfrom
markdalgleish/browser-node-polyfills

Conversation

@markdalgleish

@markdalgleish markdalgleish commented Aug 27, 2023 •

Copy link
Copy Markdown
Member

This PR makes it so we no longer polyfill built-in Node modules by default. To allow consumers to opt back in to polyfills, this also adds a new browserNodeBuiltinsPolyfill option that mirrors the existing serverNodeBuiltinsPolyfill.

This also adds a globals property to both of these options so Node globals like Buffer can be enabled with a simple flag rather than needing to manually change production code to modify the global environment.

A couple of the tests have been updated since they were relying on Node builtins in the browser.

I originally planned on making the browserNodeBuiltinsPolyfill default to the value of serverNodeBuiltinsPolyfill if it was provided, but in practice I found it confusing that a Remix config with just serverNodeBuiltinsPolyfill defined would also have browser polyfills. It does mean there's a bit more boilerplate if you want to use the same polyfills across both, but I think it's better to be explicit, and it's easy to share a single config object across both since the Remix config is a JS file anyway.

✨ This PR also adds a bonus feature where the dev server restarts when the Remix config changes. (Thanks @pcattori!)

@changeset-bot

changeset-bot Bot commented Aug 27, 2023 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a837a9e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@remix-run/dev Major
create-remix Major
remix Major
@remix-run/architect Major
@remix-run/cloudflare Major
@remix-run/cloudflare-pages Major
@remix-run/cloudflare-workers Major
@remix-run/css-bundle Major
@remix-run/deno Major
@remix-run/eslint-config Major
@remix-run/express Major
@remix-run/node Major
@remix-run/react Major
@remix-run/serve Major
@remix-run/server-runtime Major
@remix-run/testing Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@markdalgleish
markdalgleish marked this pull request as ready for review August 27, 2023 23:52
): Promise<Compiler> => {
let compiler = await esbuild.context({
...createEsbuildConfig(ctx, refs),
write: false,

@markdalgleish markdalgleish Aug 27, 2023 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to manually write the result of the browser build to disk so that esbuild-plugins-node-modules-polyfill can check the build output in memory for any missing/unconfigured polyfills after tree-shaking has occured. This is important in the context of Remix since route files often depend on Node builtins regardless of whether they're used in browser code. If write is enabled, the outputFiles are not kept in memory and are not passed to the onEnd callback of the esbuild plugin.

If you're interested, here's the PR where I implemented this: imranbarbhuiya/esbuild-plugins-node-modules-polyfill#152

if (!js.ok) throw error ?? js.error;
let { metafile, hmr } = js.value;
let { metafile, outputFiles, hmr } = js.value;
writes.js = JS.write(ctx.config, outputFiles);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As explained in my other comment, we now need to manage writing the output of the JS build to disk.

// rely on tree-shaking to remove all unused polyfills and fallbacks.
fallback: "empty",
}),
externalPlugin(/^node:.*/, { sideEffects: false }),

@markdalgleish markdalgleish Aug 28, 2023 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since esbuild-plugins-node-modules-polyfill is configured to manage fallbacks, this usage of externalPlugin was redundant.

globals: ctx.config.browserNodeBuiltinsPolyfill?.globals ?? {},
// Mark any unpolyfilled Node builtins in the build output as errors.
fallback: "error",
formatError({ moduleName, importer, polyfillExists }) {

@markdalgleish markdalgleish Aug 28, 2023 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that we could customise errors for Remix consumers who don't have direct access to the esbuild plugin, I added support for custom error formatting here: imranbarbhuiya/esbuild-plugins-node-modules-polyfill#153.

modules: ctx.config.browserNodeBuiltinsPolyfill?.modules ?? {},
globals: ctx.config.browserNodeBuiltinsPolyfill?.globals ?? {},
// Mark any unpolyfilled Node builtins in the build output as errors.
fallback: "error",

@markdalgleish markdalgleish Aug 28, 2023 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added support for built-time errors for unpolyfilled/unconfigured modules here: imranbarbhuiya/esbuild-plugins-node-modules-polyfill#152

Comment thread packages/remix-dev/compiler/js/write.ts Outdated
Comment thread packages/remix-dev/compiler/js/write.ts Outdated
@markdalgleish
markdalgleish changed the base branch from dev to release-next August 29, 2023 00:46
@markdalgleish
markdalgleish force-pushed the markdalgleish/browser-node-polyfills branch from 8e3540e to 6aac9e0 Compare August 29, 2023 00:55
@markdalgleish
markdalgleish merged commit fda1df5 into release-next Aug 29, 2023
@markdalgleish
markdalgleish deleted the markdalgleish/browser-node-polyfills branch August 29, 2023 01:57
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Hello there,

We just published version 2.0.0-pre.1 which includes this pull request. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects
Status: Merged

Development

Successfully merging this pull request may close these issues.

3 participants