Skip to content

Commit ab0c2ff

Browse files
committed
Load react-native-web helpers with static imports
Import the react-native-web style helpers statically instead of a runtime require() with an async import() fallback. Static imports resolve at build time, so the helpers are always defined synchronously: styles apply on the first frame, with no async gap and no case where they silently aren't applied. The dist/cjs build with .js extensions resolves under Metro, strict-ESM bundlers (webpack, Rollup, esbuild) and Node's ESM resolver (SSR). createReactDOMStyle is a CJS default export so it is unwrapped; the preprocess helpers are named exports read directly (not from `.default`), which is what makes them resolve under both Babel and non-Babel toolchains.
1 parent 7b708fc commit ab0c2ff

2 files changed

Lines changed: 27 additions & 58 deletions

File tree

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
'use strict';
2-
declare module 'react-native-web/dist/exports/StyleSheet/compiler/createReactDOMStyle';
3-
declare module 'react-native-web/dist/exports/StyleSheet/preprocess';
42
declare module 'react-native-web/dist/cjs/exports/StyleSheet/compiler/createReactDOMStyle.js';
53
declare module 'react-native-web/dist/cjs/exports/StyleSheet/preprocess.js';
Lines changed: 27 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,35 @@
11
'use strict';
22

3-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4-
export let createReactDOMStyle: (style: any) => any;
3+
// react-native-web exposes these style helpers only through internal modules.
4+
// They're imported statically so strict-ESM bundlers (webpack, Rollup, esbuild)
5+
// and SSR resolve them at build time and they're always defined synchronously - a
6+
// runtime require() isn't available in ESM there, which left them undefined and
7+
// crashed _updatePropsJS (#9844). The dist/cjs build (with explicit .js extensions)
8+
// is used because SSR frameworks load an externalized react-native-web with Node's
9+
// ESM resolver, which rejects the extensionless relative imports in dist/exports.
10+
// eslint-disable-next-line n/no-unpublished-import
11+
import * as createReactDOMStyleModule from 'react-native-web/dist/cjs/exports/StyleSheet/compiler/createReactDOMStyle.js';
12+
// eslint-disable-next-line n/no-unpublished-import
13+
import * as preprocessModule from 'react-native-web/dist/cjs/exports/StyleSheet/preprocess.js';
514

15+
// createReactDOMStyle is a CJS default export (module.exports = fn), so unwrap
16+
// `.default`. createTransformValue / createTextShadowValue are named exports on
17+
// module.exports and are read directly - they're not on `.default`, which is a
18+
// separate `preprocess` function.
619
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7-
export let createTransformValue: (transform: any) => any;
20+
const interopDefault = (moduleExports: any) =>
21+
moduleExports?.default ?? moduleExports;
822

923
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10-
export let createTextShadowValue: (style: any) => void | string;
11-
12-
// react-native-web exposes these style helpers only via internal modules. Metro
13-
// has require() so we load them synchronously; strict-ESM bundlers and SSR don't,
14-
// so require() throws and we fall back to import()ing the dist/cjs build
15-
// (dist/exports' extensionless imports fail Node's ESM resolver). If neither
16-
// resolves, the helpers stay undefined and the DOM update is skipped, so those
17-
// styles just aren't applied (no crash).
18-
//
19-
// Kept as a single top-level try/catch (no top-level `if` or IIFE) so the module
20-
// stays tree-shakable - see the is-tree-shakable check.
21-
try {
22-
createReactDOMStyle =
23-
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, n/no-unpublished-require
24-
require('react-native-web/dist/exports/StyleSheet/compiler/createReactDOMStyle').default;
25-
// React Native Web 0.19+
26-
const preprocess =
27-
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, n/no-unpublished-require
28-
require('react-native-web/dist/exports/StyleSheet/preprocess');
29-
createTransformValue = preprocess.createTransformValue;
30-
createTextShadowValue = preprocess.createTextShadowValue;
31-
} catch (_e) {
32-
// No require() (strict ESM / SSR), or a helper module was missing: load the
33-
// helpers from the dist/cjs build instead.
34-
void (async () => {
35-
// The cjs export may arrive as `.default` (bundler/Node interop) or as the
36-
// namespace itself; handle both.
37-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
38-
const interopDefault = (moduleExports: any) =>
39-
moduleExports?.default ?? moduleExports;
24+
export const createReactDOMStyle: (style: any) => any = interopDefault(
25+
createReactDOMStyleModule
26+
);
4027

41-
try {
42-
const styleModule = await import(
43-
// eslint-disable-next-line n/no-unpublished-import
44-
'react-native-web/dist/cjs/exports/StyleSheet/compiler/createReactDOMStyle.js'
45-
);
46-
createReactDOMStyle = interopDefault(styleModule);
47-
} catch (_e2) {
48-
// Unresolved: the DOM update is skipped, so these styles aren't applied.
49-
}
28+
// React Native Web 0.19+
29+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
30+
export const createTransformValue: (transform: any) => any =
31+
preprocessModule.createTransformValue;
5032

51-
try {
52-
const preprocessModule = await import(
53-
// eslint-disable-next-line n/no-unpublished-import
54-
'react-native-web/dist/cjs/exports/StyleSheet/preprocess.js'
55-
);
56-
// React Native Web 0.19+
57-
const preprocess = interopDefault(preprocessModule);
58-
createTransformValue = preprocess.createTransformValue;
59-
createTextShadowValue = preprocess.createTextShadowValue;
60-
} catch (_e2) {
61-
// Optional: leaving them undefined just skips transform/textShadow.
62-
}
63-
})();
64-
}
33+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34+
export const createTextShadowValue: (style: any) => void | string =
35+
preprocessModule.createTextShadowValue;

0 commit comments

Comments
 (0)