StyleX & React Strict DOM integration with Expo for Web.
Not intended for production for now.
This repository demonstrates how to integrate StyleX / React Strict DOM for Expo, with support for Static CSS Extraction in Expo Web.
The official react-strict-dom repository app does not support extracting css files and injects CSS in runtime, which this repository tries to fix. Please see this issue for more context.
- Production CSS extraction
- Dev mode Fast Refresh
- iOS & Android (does nothing)
yarn install
, then:
- web:
yarn web
for developing web with Fast Refreshyarn expo export -p web
for production builds with static css file in dist.
- native:
yarn ios
oryarn android
.
You can also use yarn start
to develop for multiple platforms simultaneously.
withStyleX
Metro Plugin in configured in metro.config.js
.
You can see the source code for withStyleX
plugin in stylex-metro-config
directory.
Basic explanation:
-
Each JS file containing stylex imports is transformed using
@stylexjs/babel-plugin
instylex-metro-config/transformer.js
and stylex metadata for each file is directly injected in each file withimport 'stylex.virtual.css?filename=...&contents=...'
, where stylex rules and filename are encoded in search params. -
Then, the resolver in
stylex-metro-config/index.js
will look for these imports and store these stylex rules. -
The resulting css is written to
node_modules/.cache/stylex-metro-config/stylex.bundle.css
, while resolving allstylex.virtual.css?
virtual module imports to this file.
There are a few limitations/questions I'm aware of:
- CSS files are written many times in the resolver
- Maybe we can debounce in dev, but in production we may need to resolve synchronously?
- Or, maybe this should be done in the serializer? I'm not too sure either.
- In dev, is it better/faster to use the original babel plugin runtime injection in web rather than writing to .css?
- No bare RN support
- CSS support is implemented in the Expo framework only
- Not sure if this works without Expo Router
- Not sure if this works with bundle-splitting and static/server-rendering (haven't investigated yet).
Follow Expo's guide on monorepos here.
Make sure you pass the projectRoot
to withStylex
. Here's a working metro config:
import { getDefaultConfig } from "expo/metro-config";
import { withStyleX } from "stylex-metro-config";
import path from "path";
// Find the project and workspace directories
const projectRoot = __dirname;
// This can be replaced with `find-yarn-workspace-root`
const monorepoRoot = path.resolve(projectRoot, "../..");
const config = getDefaultConfig(projectRoot);
// 1. Watch all files within the monorepo
config.watchFolders = [monorepoRoot];
// 2. Let Metro know where to resolve packages and in what order
config.resolver!.nodeModulesPaths = [
path.resolve(projectRoot, "node_modules"),
path.resolve(monorepoRoot, "node_modules"),
];
module.exports = withStyleX(config, {
projectRoot, // important
});