This repository demonstrates how to integrate StyleX and React Strict DOM with Expo Web, enabling Static CSS Extraction through a custom PostCSS plugin using postcss-react-strict-dom.
- Bypassing Metro for CSS extraction in Web: Works seamlessly on both web and native platforms.
- Fast Refresh: Fully supported across platforms.
- Transpiling External Modules: Partially supported by specifying the files to transpile in the
include
option inpostcss.config.js
. - PostCSS Plugin Flexibility: Easily generate StyleX CSS bundles for other bundlers via the PostCSS CLI or integrate into Expo and Next.js.
To integrate with Expo Web:
- Install postcss-react-strict-dom
Install the plugin:
bun add postcss-react-strict-dom --dev
- Update
babel.config.js
:
// Based on:
// https://github.com/facebook/react-strict-dom/blob/13f3958ae876b871250b893bd6d71aae4eb38310/apps/examples/babel.config.js
const reactStrictPreset = require('react-strict-dom/babel-preset')
function getPlatform(caller) {
return caller && caller.platform
}
function getIsDev(caller) {
if (caller?.isDev != null) return caller.isDev
// https://babeljs.io/docs/options#envname
return (
process.env.BABEL_ENV === 'development' ||
process.env.NODE_ENV === 'development'
)
}
module.exports = function (api) {
//api.cache(true);
const platform = api.caller(getPlatform)
const isDev = api.caller(getIsDev)
const presets = ['babel-preset-expo']
const plugins = []
if (platform === 'web') {
presets.push([
reactStrictPreset,
{
debug: true,
dev: false, // This should be set `false` to disable runtime injection
rootDir: __dirname,
},
])
}
return {
plugins,
presets,
}
}
- Update
postcss.config.js
:
module.exports = {
plugins: {
'postcss-react-strict-dom': {
include: [
'src/**/*.{js,jsx,ts,tsx}',
'node_modules/react-strict-dom/dist/**/*.{js,jsx,ts,tsx}',
],
},
autoprefixer: {},
},
}
- Create
src/global.css
:
@stylex;
- Import
src/global.css
in your root layout (src/app/layout.tsx
):
import '@/global.css'
import { Stack } from 'expo-router'
export default Stack
-
Install dependencies:
bun install
-
Start development mode for web:
bun web # or bun start
-
For native platforms (iOS/Android):
bun ios bun android
On native platforms, StyleX integration is skipped, because it requires no configuration.
This repository uses:
babel.config.js
for JavaScript/TypeScript compilation.postcss.config.js
for Static CSS extraction.
This approach simplifies integration across bundlers like Metro and Turbopack, allowing easy configuration without complex bundler-specific integration.
Unlike my previous Metro-based solution (stylex-expo
), this PostCSS-based approach avoids Metro’s side-effect issues, particularly cache invalidation problems as discussed here.
- Tree Shaking: Since the PostCSS plugin processes all files matching the glob patterns, unused code may affect CSS output. This issue is similar to CLI-based tools like Tailwind CLI/StyleX CLI and should be addressed with deeper bundler integration.