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

Always include CSS imports from live JS modules #1458

Closed
wants to merge 1 commit into from

Conversation

jgoz
Copy link
Contributor

@jgoz jgoz commented Jul 18, 2021

Closes #1370.

This change isn't exactly what you described in the linked issue (specifically traversing export * statements to find live .css files), but I think it represents the least surprising behavior when it comes to CSS imported from JS files:

With this change, CSS imported from JS will get included in output bundles if the CSS file itself is live and its direct importing JS file is also live. Previously, a dead ancestor would cause an otherwise live CSS file to be excluded.

This new behavior could potentially lead to unused CSS being included in bundles, but we can't determine that statically based only on the import graph. If and when CSS modules are supported, this behavior would remain valid for bare CSS imports, while CSS module imports could be analyzed for DCE based on their synthesized exports.

One thing to note, and a potential deviation from webpack's behavior, is that even with sideEffects: false, CSS imports will still be included if their parent JS is included. I believe this is because esbuild (correctly) considers all CSS files as having side effects since CSS modules are not currently supported. So even though sideEffects: false is not technically being respected, the resulting behavior is most likely what the user would be expecting.

@sqs
Copy link

sqs commented Aug 28, 2021

I confirmed this PR fixes the issue for me on @sourcegraph's fairly large repo (and does not introduce any other issues as best I can tell). (We use export * from a lot for groups of UI components that themselves import CSS, so we're affected by this issue.)

I wonder, however, if a different approach to the fix would be better. This fix leaves the current markFileLiveForTreeShaking impl unchanged and special-cases the interpretation of its output (IsLive) for CSS. Instead, it might be better to change markFileLiveForTreeShaking to mark files with export * from as live. I.e., markFileLiveForTreeShaking should treat the following 2 files the same when calculating liveness: export * from 'foo' and export { a } from 'foo' (assuming that foo exports a). Currently it deems the former non-live and the latter live, which feels wrong to me.

(I defer to @evanw here, of course. And I'm happy to make a diff for the approach I proposed.)

@jgoz
Copy link
Contributor Author

jgoz commented Aug 28, 2021

@sqs that's a great idea and it might avoid conflicts with any future CSS modules implementation, where CSS files may have non-live parts. I'll see if I can get it working.

@jgoz
Copy link
Contributor Author

jgoz commented Aug 28, 2021

Did some investigation and now I remember why I didn't make the change in markFileLiveForTreeShaking. I think the problem is that parts containing side-effectful imports (in this case import './foo.css') don't track their dependencies within the source graph, unlike other kinds of imports. This means when marking a CSS import statement as being live, it's impossible to mark its parent import/export statements as also being live.

So I think the solution might be even earlier in the pipeline, possibly in scanImportsAndExports, though I'm not quite sure how to approach it.

@sqs
Copy link

sqs commented Dec 21, 2022

I rebased this PR on the latest main branch and confirmed it still works on the large https://github.com/sourcegraph/sourcegraph esbuild project.

main...sqs:esbuild:fix-css-export-star-issue

I am not the PR author, so I can't update this PR, but I'm happy to make another PR for ease of merging.

@evanw: Would you consider merging this? Or do you have another preferred way of solving this? This would let us switch to esbuild at Sourcegraph, which would be a huge improvement because esbuild is awesome.

@jgoz
Copy link
Contributor Author

jgoz commented Dec 21, 2022

@sqs I rebased this branch, but I'm not confident that this is how @evanw would want to approach the issue.

sqs added a commit to sourcegraph/sourcegraph that referenced this pull request Jan 3, 2023
This is essentially blocked on evanw/esbuild#1458 because:

- That PR is needed to make tree-shaking work with esbuild in our app.
- We could just use esbuild for dev (where tree-shaking isn't as necessary) and Webpack in prod, but we don't want to use a different builder in dev vs. prod.
- Using an esbuild fork is cumbersome, since we'd also need to build the `esbuild` binaries for various platforms.
sqs added a commit to sourcegraph/sourcegraph that referenced this pull request Jan 3, 2023
- DEV_WEB_BUILDER_ESBUILD_FORCE_TREESHAKING: forces tree-shaking. Requires using a fork of esbuild (evanw/esbuild#1458) for now, but merging this will make it easier for more people to experiment with that esbuild fork.
- DEV_WEB_BUILDER_UNSAFE_FAST: Setting the env var DEV_WEB_BUILDER_UNSAFE_FAST skips various operations in frontend dev. It's not safe, but if you know what you're doing, go ahead and use it. (CI will catch any issues you forgot about.)
@sqs
Copy link

sqs commented Jan 3, 2023

@jgoz Thank you!

@evanw Happy to pursue alternative approaches to this, if you would be willing to give some input. Thanks!

sqs added a commit to sourcegraph/sourcegraph that referenced this pull request Jan 3, 2023
- DEV_WEB_BUILDER_ESBUILD_FORCE_TREESHAKING: forces tree-shaking. Requires using a fork of esbuild (evanw/esbuild#1458) for now, but merging this will make it easier for more people to experiment with that esbuild fork.
- DEV_WEB_BUILDER_UNSAFE_FAST: Setting the env var DEV_WEB_BUILDER_UNSAFE_FAST skips various operations in frontend dev. It's not safe, but if you know what you're doing, go ahead and use it. (CI will catch any issues you forgot about.)
@evanw evanw closed this in 88e17d8 Feb 9, 2023
sqs added a commit to sourcegraph/sourcegraph that referenced this pull request Feb 10, 2023
This is essentially blocked on evanw/esbuild#1458 because:

- That PR is needed to make tree-shaking work with esbuild in our app.
- We could just use esbuild for dev (where tree-shaking isn't as necessary) and Webpack in prod, but we don't want to use a different builder in dev vs. prod.
- Using an esbuild fork is cumbersome, since we'd also need to build the `esbuild` binaries for various platforms.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unexpected (CSS) import removal with glob pattern in sideEffects array
2 participants