Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 5 commits into from
Aug 29, 2023

Conversation

markdalgleish
Copy link
Member

@markdalgleish markdalgleish commented Aug 27, 2023

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!)

@markdalgleish markdalgleish added package:dev v2 Issues related to v2 apis labels Aug 27, 2023
@markdalgleish markdalgleish self-assigned this Aug 27, 2023
@changeset-bot
Copy link

changeset-bot bot commented Aug 27, 2023

🦋 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
@@ -156,11 +149,12 @@ export const create = async (
): Promise<Compiler> => {
let compiler = await esbuild.context({
...createEsbuildConfig(ctx, refs),
write: false,
Copy link
Member Author

@markdalgleish markdalgleish Aug 27, 2023

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

@@ -100,7 +101,8 @@ export let create = async (ctx: Context): Promise<Compiler> => {
// js compilation (implicitly writes artifacts/js)
let js = await tasks.js;
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
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 }),
Copy link
Member Author

@markdalgleish markdalgleish Aug 28, 2023

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 }) {
Copy link
Member Author

@markdalgleish markdalgleish Aug 28, 2023

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",
Copy link
Member Author

@markdalgleish markdalgleish Aug 28, 2023

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

@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
9 checks passed
@markdalgleish markdalgleish deleted the markdalgleish/browser-node-polyfills branch August 29, 2023 01:57
@github-actions
Copy link
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
Labels
CLA Signed package:dev v2 Issues related to v2 apis
Projects
No open projects
Status: Merged
Development

Successfully merging this pull request may close these issues.

3 participants