Open nmn opened 6 months ago
@nmn FYI, here is currently my implementation (kinda like approach 1 and 2 combined)
stylex-loader
collects style rules from jsx/tsx files and append noop css imports to them:import '/path/to/stylex-noop.css?rules=[serialized and encoded stylex rules]'
cacheGroup
) targets all stylex-noop.css
and merge them into a single file.buildInfo
, we can just use module identifier. Inside the processAssets
hook (phase PROCESS_ASSETS_STAGE_PRE_PROCESS
), we find the stylex chunk (it should contain many stylex-noop.css?rules=
modules) and iterates through modules of the chunk, collect and deserialize stylex rules from modules' _identifier
.Actual implementation: stylex-webpack. This works with Next.js as well, since stylex-loader
generated CSS imports can be handled by Next.js.
@SukkaW If your implementation works more reliably than the hacky plugin we have currently, I would love a PR to make it the official implementation going forward.
In the meantime, I'm going to do some testing with it and see how you got around some of the problems I encountered while trying to use that approach.
If your implementation works more reliably than the hacky plugin we have currently, I would love a PR to make it the official implementation going forward. In the meantime, I'm going to do some testing with it and see how you got around some of the problems I encountered while trying to use that approach.
Sure! IMHO we could do some experiments based on the stylex-webpack
project before merging it back to stylex.
Problem
The Webpack plugin and Next JS plugin have a bunch of issues at the moment. Thanks to help from Tobias Koppers, I have some ideas on how to fix these problems.
179, #197, #209, #288
Background
StyleX compilation is essentially two steps:
We haven't done this right within Webpack and caching doesn't work at all. But we now have some pointers on how to do this right.
Approach 1: Using CSS data imports
We can take the generated metadata from each JS file and convert that in the CSS data file import within the file itself.
Instead of generating:
We would insert this import within the file itself:
Then, the usual plugins will collect all the CSS from all the files combine them in a CSS file. (We need to ensure that there is only ever 1 CSS file. Figure out how to avoid bundle splitting for CSS)
This generated CSS file will then need to be processed with a custom PostCSS or LightningCSS plugin to do all the work that is currently done while generating the CSS file. (sorting rules, renaming layers. Removing unused styles etc.)
Challenges
Possible solutions:
__stylex__
prefix and encode priority information in a suffix.@layer __stylex__priority__3008 {...}
.__stylex__VAR_USED {--variable-name: 1}
Approach 2: Write module metadata and combine it
This is the approach we use with the Rollup plugin today but we haven't done things in Webpack correctly.
The approach is similar to the first one, but here we can use a custom mime type to keep the metadata in JSON format.
We would insert an import into the source JS file that looks like this:
A webpack loader can be configured:
This loader will need to read and attach the metadata to the module being processed:
NOTE: the
buildInfo
is cached and needs to be serialisable.Finally a Webpack plugin will need to iterate all the modules from
compilation.modules
to read the styles and combine them, generate a CSS file and useemitAsset
to generate the CSS file.In the case of HTML files being used, we would need to add the generated CSS to every entrypoint:
compilation.entrypoints
/entrypoint.files
.NextJS challenges
Even after all of this, there is a challenge with NextJS generating separate server and client bundles. The current approach handles this in a hacky unreliable way that can't be cached. Both of these approaches may be stuck with separate server and client CSS files which is not what we want. There was a mention of a "manifest" file as a possible way to get around this issue.
Workaround: Pre-compile everything
A third and final solution might be to build a CLI that can take a folder or "source" files and transforms them all along with a CSS file to a "src" folder. This would happen while you program rather than a part of bundling.
In more detail:
A
pre-app
orpre-src
folder with your actual source code. Ababel-watch
command will transform this folder intoapp
orsrc
, respectively. Which runs in parallel with a standardswc
-basednext dev
command combined with a single PostCSS or LightningCSS plugin.Initially this won't support importing styles from
node_modules
, but we will be able to fix that with some import re-writing and configuration as well.