Replies: 2 comments 2 replies
-
So far I am having success. I have a follow up after, but first I will share what is working for me in case anyone is looking to do the same thing. // eslint-disable-next-line @typescript-eslint/no-require-imports
const babel = require('@babel/core');
// eslint-disable-next-line @typescript-eslint/no-require-imports
const stylexPlugin = require('@stylexjs/babel-plugin');
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { processStylexRules } = require('@stylexjs/babel-plugin');
// Design System components use StyleX for styling. StyleX generates atomic CSS classes at build time
// and compiles away stylex.create() calls, replacing them with generated classnames.
// The CSS is extracted here and inlined into the JS bundle for Shadow DOM injection.
// Process: transformWithStyleX() extracts CSS → babel-stylex-transform plugin applies it → cssInjectionCode inlines it
// → Runtime: acme-agent.js applies CSS to Shadow DOM via constructable stylesheets
// StyleX CSS collection
let collectedCSS = '';
// Babel transformation for StyleX - processes all files and extracts CSS from StyleX code
function transformWithStyleX(code, filename) {
try {
const result = babel.transformSync(code, {
filename,
plugins: [
[stylexPlugin, {
dev: process.argv.includes('--dev'),
genConditionalClasses: false,
treeshakeCompensation: true,
unstable_moduleResolution: {
type: 'commonJS',
rootDir: path.resolve(__dirname, '../../../..'), // Project root
},
}],
'@babel/plugin-syntax-jsx',
],
presets: [
['@babel/preset-react', {
runtime: 'automatic'
}],
['@babel/preset-typescript', {
isTSX: true,
allExtensions: true
}]
],
});
// Extract and accumulate StyleX CSS from compiled components
if (result?.metadata && 'stylex' in result.metadata) {
const stylexRules = result.metadata.stylex;
if (Array.isArray(stylexRules) && stylexRules.length > 0) {
const processedCSS = processStylexRules(stylexRules, false);
collectedCSS += processedCSS;
}
}
// ...
return result?.code || code;
} catch (error) {
console.error(`Babel transformation failed for ${filename}:`, error);
throw error; // Let the build fail completely
}
}
// ...
await esbuild.build({
// ...
plugins: [
{
name: 'babel-stylex-transform',
setup(build) {
// Transform JS/JSX/TS/TSX files with Babel + StyleX
// Note: Currently processes all files - could be optimized to target only Design System files and app files
build.onLoad({ filter: /\.(js|jsx|ts|tsx)$/ }, async (args) => {
console.log(`Transforming: ${args.path}`);
const code = await fs.promises.readFile(args.path, 'utf8');
const transformedCode = transformWithStyleX(code, args.path);
return {
contents: transformedCode,
loader: args.path.endsWith('.tsx') || args.path.endsWith('.ts') ? 'tsx' : 'jsx',
};
});
},
},
],
// ...
// Inject StyleX CSS into the bundle
if (collectedCSS) {
const cssInjectionCode = `
// StyleX CSS injection
window.__ACMEAGENT_STYLEX_CSS__ = ${JSON.stringify(collectedCSS)};
`;
bundledCode = cssInjectionCode + bundledCode;
} and the runtime part of it // Apply StyleX CSS using constructable stylesheets (supported in all modern browsers except IE11)
if (typeof CSSStyleSheet !== 'undefined' && window.__ACMEAGENT_STYLEX_CSS__) {
const sheet = new CSSStyleSheet();
sheet.replaceSync(window.__ACMEAGENT_STYLEX_CSS__);
this.shadowRoot.adoptedStyleSheets = [sheet];
} else {
console.log('CSS not found or CSSStyleSheet not supported');
} |
Beta Was this translation helpful? Give feedback.
-
Atomic CSS is a bad fit for shadow DOM.
The Rollup plugin should work with ESBuild. You're on your own to make it work in development. If you don't have server components involved, you could probably just use
You should be able to add a placeholder string in your original JS, and then patch it with the final CSS with a custom ESBuild plugin. The build process for StyleX is conceptually very simple:
If you look at the Rollup plugin, it writes that CSS string to a file. You should instead be able to find and replace the placeholder string in your JS bundle with the CSS string instead. The PostCSS plugin was created because existing bundlers don't make this process easy, except for Rollup.
The find and replace is a decent solution, but you can just If you want to make the same CSS usable both inside a shadow DOM and not, you can use: Overall you already seem to be on the right path, so hopefully all this makes sense. Just another headsup that since atomic CSS is not a good fit for shadow DOM, I'm not sure it's a good idea to use StyleX for small web component at all. Only do so, if this shadow DOM contains something large enough to be considered a "mini app". |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi everyone,
I'm hoping to get some expert advice on the best practice for a specific build scenario.
The Challenge:
I am integrating my StyleX-based design system into a pre-existing, drop-in widget. I have to work within the project's established architecture, which has two firm requirements:
The widget itself is a web component that uses a Shadow DOM, so the CSS must be bundled inside the final JS file to be injected at runtime. An earlier attempt to convert the build to Vite was unsuccessful due to fundamental conflicts between Vite's ESM-first approach and the IIFE output requirement.
My Proposed Solution:
Since StyleX plugins like the PostCSS one is designed to output a separate
.css
file, (and I can't use that approach) I'm planning a custom build script.The theory is:
babelResult.metadata.stylex
array.define
option to make the CSS available as a global constant, which is then injected into a<style>
tag within the component.My Question:
Given that my project absolutely requires a single-file output and must use ESBuild, is this programmatic approach of capturing the styles from Babel's metadata the recommended best practice?
It seems to be the only viable path, but I wanted to run it by the experts here to ensure I'm not missing a more official or robust method for this kind of integration.
Thanks so much for your time!
Beta Was this translation helpful? Give feedback.
All reactions