-
Notifications
You must be signed in to change notification settings - Fork 50
feat: Allow to configure bundleSizeOptimizations
#428
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
Conversation
5c786dc to
c87d6f9
Compare
Lms24
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the API for this! Probably easier to use for the majority of folks than defining a replace plugin themselves.
Do you think there's a way that we could filter out files before reading them? I'm thinking about looking at the file path and checking for a @sentry occurance. But not sure if I'm missing something tough why this wouldn't work.
| renderChunk(code: string) { | ||
| return replaceBooleanFlagsInCode(code, values); | ||
| }, | ||
|
|
||
| transform(code: string) { | ||
| return replaceBooleanFlagsInCode(code, values); | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to call the replace function in two hooks? Shouldn't transform be enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tbh I just copied this behaviour from the rollup replace Plugin 😅 they to it that way there. But I can just remove the chunk hook!
packages/esbuild-plugin/src/index.ts
Outdated
|
|
||
| const contents = replaceBooleanFlagsInCode(source, values); | ||
|
|
||
| if (!contents) { | ||
| return null; | ||
| } | ||
|
|
||
| return { contents: contents.code, loader: "default" }; | ||
| }); | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot do this as it will override any other registered laoder for files that match this filter. Let's do the following instead:
setup({ initialOptions }) {
initialOptions.define = { ...initialOptions.define, ...values };
},
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just to be clear, as I am not an expert at this at all - we do not do this for the other esbuild plugins, which is where I basically copied this from (as well as looking at some esbuild replace plugin). or is this only because we match all files here? E.g. here: https://esbuild.github.io/plugins/#using-plugins they also just return this directly...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the other plugins, we are doing very complex logic to make sure all of the user files are still loaded via the plugins they defined. There we are using a sort of proxy logic.
The onLoad hook is simply the wrong approach for this. The onLoad hook, as it suggests is for "reading" files off a particular location. For example, esbuild doesn't know how to files that lie somewhere on the internet (http) so you can define an onLoad hook that takes care of that for esbuild. A file can only be loaded once. So if our plugin loads it, no other plugin will be able to. Doing this in our case will result in catastrophic behavior for users that use any kind of loader plugin - in the way it is implemented right now this will pretty much result in catastrophic behavior for ALL users since we always define the load hook.
Esbuild doesn't have any sort of transform hook and that is by design to keep it fast. It does all the transpilation and stuff by itself. We need to use the define option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that makes sense, thank you for the in depth explanation! I'll adjust this then according to this 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated this to use define (which is much nicer anyhow!)
| return { | ||
| renderChunk(code: string) { | ||
| return replaceBooleanFlagsInCode(code, values); | ||
| }, | ||
|
|
||
| transform(code: string) { | ||
| return replaceBooleanFlagsInCode(code, values); | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a slight issue but I don't know yet whether it is gonna be a problem.
We generally instruct people to put our plugin as late as possible, this is necessary for debugID injection. However, in order for minification plugins to be able to properly tree shake the dead code we introduce here, we need to be as early as possible...
I think this is fine with the transform hook, assuming that it is early enough. The render chunk hook is probably too late. I think we can just remove the render chunk hook in general. If we don't catch the statements in transform, we're too late anyhow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will try removing renderChunk and see how it goes. we can always revisit this and add it again later!
| } | ||
| }); | ||
|
|
||
| if (ms.hasChanged()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is nice!
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore webpack version compatibility shenanigans | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access | ||
| const DefinePlugin = | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore webpack version compatibility shenanigans | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access | ||
| compiler?.webpack?.DefinePlugin || | ||
| webback4or5?.DefinePlugin || | ||
| webback4or5?.default?.DefinePlugin; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beautiful :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎨
Not a bad idea. we could do Counterargument, it would not be the same behavior for all bundlers and why should we make this unnecessarily fragile? |
Also a good point. My concern is mostly that the plugin having to read every file might have a performance impact. But I'm totally fine if we just go with this first and optimize later if necessary. |
Yeah we can for sure revisit this, since this is opt in I think we can tweak this more later if needed! |
|
OK so I fixed the tests and tried to address the feedback - is this ready to go? :) I did not add any file filtering for now, I think we can still add this at a later stage if we find out this is too slow! This does not run at all if no |
|
This concern is critical and we need to address it before merging this. |
packages/esbuild-plugin/src/index.ts
Outdated
| setup({ initialOptions }) { | ||
| const replacementStringValues: Record<string, string> = Object.entries( | ||
| replacementValues | ||
| ).reduce((acc, [key, value]) => { | ||
| return { ...acc, [key]: JSON.stringify(value) }; | ||
| }, {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is an accidental O(n^2) because of the spread in a loop, I don't think it matters a lot but since this is an easy fix we should just fix it.
This introduces a new option for the plugins:
When set, this will replace the relevant build time flags with a boolean, allow bundlers to treeshake code out and reduce the shipped bundle size.
Closes #425