Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a87d785
fix(🧪): update timeout in e2e
wcandillon Oct 15, 2025
e638787
Merge branch 'main' into main
wcandillon Oct 15, 2025
838c133
Merge branch 'Shopify:main' into main
wcandillon Oct 15, 2025
467f6ea
Merge branch 'Shopify:main' into main
wcandillon Oct 16, 2025
f2f59d4
Merge branch 'Shopify:main' into main
wcandillon Oct 18, 2025
8081a7e
Merge branch 'Shopify:main' into main
wcandillon Oct 21, 2025
e5251f9
Merge branch 'Shopify:main' into main
wcandillon Oct 22, 2025
6543f07
Merge branch 'Shopify:main' into main
wcandillon Oct 23, 2025
8a6f372
Merge branch 'Shopify:main' into main
wcandillon Oct 23, 2025
aaea6a9
Merge branch 'Shopify:main' into main
wcandillon Oct 27, 2025
c766b77
Merge branch 'Shopify:main' into main
wcandillon Oct 30, 2025
d7123af
Merge branch 'Shopify:main' into main
wcandillon Oct 31, 2025
e9ee662
Merge branch 'Shopify:main' into main
wcandillon Oct 31, 2025
07483f9
Merge branch 'Shopify:main' into main
wcandillon Oct 31, 2025
6021dab
:wrench:
wcandillon Nov 3, 2025
5277c9c
:wrench:
wcandillon Nov 4, 2025
2998d94
:green_heart:
wcandillon Nov 4, 2025
923760b
:wrench:
wcandillon Nov 4, 2025
f1e2bd9
:wrench:
wcandillon Nov 4, 2025
e2d87c3
Merge branch 'main' into rn-web
wcandillon Nov 4, 2025
cbb372b
:wrench:
wcandillon Nov 4, 2025
89c151a
Merge branch 'rn-web' of https://github.com/wcandillon/react-native-s…
wcandillon Nov 4, 2025
42b855f
Remove project specification from Playwright test command
wcandillon Nov 4, 2025
96ac628
Remove specific test target from CI workflow
wcandillon Nov 4, 2025
b8abb79
:wrench:
wcandillon Nov 4, 2025
1ecf38b
Merge branch 'rn-web' of https://github.com/wcandillon/react-native-s…
wcandillon Nov 4, 2025
59db3c9
Merge branch 'main' into rn-web
wcandillon Nov 12, 2025
35f2739
Update ci.yml
wcandillon Nov 12, 2025
95c3cde
Update APK path in CI workflow for Android
wcandillon Nov 12, 2025
28628b3
Add step to locate APK files in CI workflow
wcandillon Nov 12, 2025
0c07bc0
Merge branch 'main' into rn-web
wcandillon Nov 12, 2025
bebc250
remove bogus change
wcandillon Nov 12, 2025
3e92487
remove bogus change
wcandillon Nov 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions apps/example/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<link rel="icon" href="/src/assets/react.png" type="image/png" />
<script src="https://unpkg.com/canvaskit-wasm/bin/full/canvaskit.js"></script>

<title>Example</title>
<!-- The `react-native-web` recommended style reset: https://necolas.github.io/react-native-web/docs/setup/#root-element -->
<style id="react-native-web-reset">
/* These styles make the body full-height */
html,
body {
height: 100%;
}
/* These styles disable body scrolling if you are using <ScrollView> */
body {
overflow: hidden;
}
/* These styles make the root element full-height */
#root {
display: flex;
height: 100%;
flex: 1;
}
</style>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script
src="index.bundle?platform=web&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.routerRoot=app&unstable_transformProfile=hermes-stable"
defer
></script>
</body>
</html>
23 changes: 23 additions & 0 deletions apps/example/index.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { AppRegistry } from "react-native";

import App from "./src/App";
import { name as appName } from "./app.json";

AppRegistry.registerComponent(appName, () => App);

const rootTag = document.getElementById("root");

if (process.env.NODE_ENV !== "production") {
if (!rootTag) {
throw new Error(
'Required HTML element with id "root" was not found in the document HTML.'
);
}
}

CanvasKitInit({
locateFile: (file) => `https://unpkg.com/canvaskit-wasm/bin/full/${file}`,
}).then((CanvasKit) => {
window.CanvasKit = global.CanvasKit = CanvasKit;
AppRegistry.runApplication(appName, { rootTag });
});
48 changes: 47 additions & 1 deletion apps/example/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
const path = require("path");
const { resolve: defaultResolve } = require("metro-resolver");
const { makeMetroConfig } = require("@rnx-kit/metro-config");
module.exports = makeMetroConfig({

const root = path.resolve(__dirname, "../..");
const rnwPath = path.resolve(root, "node_modules/react-native-web");
const assetRegistryPath = path.resolve(
root,
"node_modules/react-native-web/dist/modules/AssetRegistry/index",
);

const metroConfig = makeMetroConfig({
transformer: {
getTransformOptions: async () => ({
transform: {
Expand All @@ -9,3 +19,39 @@ module.exports = makeMetroConfig({
}),
},
});

function getWebMetroConfig(config) {
config.resolver = config.resolver ?? {};
config.resolver.platforms = ["ios", "android", "web"];

const origResolveRequest =
config.resolver.resolveRequest ??
((context, moduleName, platform) =>
defaultResolve(context, moduleName, platform));

config.resolver.resolveRequest = (contextRaw, moduleName, platform) => {
const context = {
...contextRaw,
preferNativePlatform: false,
};

if (moduleName === "react-native") {
return {
filePath: path.resolve(rnwPath, "dist/index.js"),
type: "sourceFile",
};
}

// Let default config handle other modules
return origResolveRequest(context, moduleName, platform);
};

config.transformer = config.transformer ?? {};
config.transformer.assetRegistryPath = assetRegistryPath;

return config;
}

module.exports = !!process.env.IS_WEB_BUILD
? getWebMetroConfig(metroConfig)
: metroConfig;
7 changes: 6 additions & 1 deletion apps/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"pod:install": "cd ios && pod install",
"test": "jest",
"tsc": "tsc --noEmit",
"start": "react-native start"
"start": "react-native start",
"web": "IS_WEB_BUILD=true react-native start"
},
"dependencies": {
"@callstack/react-native-visionos": "^0.75.0",
Expand All @@ -30,13 +31,15 @@
"cdt2d": "^1.0.0",
"its-fine": "^2.0.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-native": "0.78.0",
"react-native-gesture-handler": "^2.24.0",
"react-native-macos": "^0.78.3",
"react-native-reanimated": "3.19.1",
"react-native-safe-area-context": "^5.2.0",
"react-native-screens": "^4.9.1",
"react-native-svg": "^15.11.2",
"react-native-web": "^0.21.2",
"react-native-windows": "^0.75.0"
},
"devDependencies": {
Expand All @@ -54,6 +57,8 @@
"@rnx-kit/metro-config": "^2.0.0",
"@types/jest": "^29.5.13",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@types/react-native-web": "^0.19.2",
"@types/react-test-renderer": "^19.0.0",
"eslint": "9.36.0",
"eslint-config-react-native-wcandillon": "4.0.1",
Expand Down
1 change: 1 addition & 0 deletions apps/example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { HomeScreen } from "./Home";
import type { StackParamList } from "./types";
import { useAssets } from "./Tests/useAssets";
import { Chess } from "./Examples/Chess";
import "./resolveAssetSourcePolyfill";

const linking: LinkingOptions<StackParamList> = {
config: {
Expand Down
57 changes: 57 additions & 0 deletions apps/example/src/resolveAssetSourcePolyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Image, PixelRatio, Platform } from "react-native";
import { getAssetByID } from "react-native-web/dist/modules/AssetRegistry";

// react-native-web does not support resolveAssetSource out of the box
// https://github.com/necolas/react-native-web/issues/1666
if (Platform.OS === "web") {
function resolveAssetUri(source) {
let uri = null;
if (typeof source === "number") {
// get the URI from the packager
const asset = getAssetByID(source);
if (asset == null) {
throw new Error(
`Image: asset with ID "${source}" could not be found. Please check the image source or packager.`,
);
}
// eslint-disable-next-line prefer-destructuring
let scale = asset.scales[0];
if (asset.scales.length > 1) {
const preferredScale = PixelRatio.get();
// Get the scale which is closest to the preferred scale
scale = asset.scales.reduce((prev, curr) =>
Math.abs(curr - preferredScale) < Math.abs(prev - preferredScale)
? curr
: prev,
);
}
const scaleSuffix = scale !== 1 ? `@${scale}x` : "";
uri = asset
? `${asset.httpServerLocation}/${asset.name}${scaleSuffix}.${asset.type}`
: "";
} else if (typeof source === "string") {
uri = source;
} else if (source && typeof source.uri === "string") {
// eslint-disable-next-line prefer-destructuring
uri = source.uri;
}

if (uri) {
const svgDataUriPattern = /^(data:image\/svg\+xml;utf8,)(.*)/;
const match = uri.match(svgDataUriPattern);
// inline SVG markup may contain characters (e.g., #, ") that need to be escaped
if (match) {
const [, prefix, svg] = match;
const encodedSvg = encodeURIComponent(svg);
return `${prefix}${encodedSvg}`;
}
}

return uri;
}

Image.resolveAssetSource = (source) => {
const uri = resolveAssetUri(source) || "";
return { uri };
};
}
3 changes: 2 additions & 1 deletion packages/skia/src/__tests__/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import type { SkSurface, SkImage } from "../skia/types";

export const E2E = process.env.E2E === "true";
export const CI = process.env.CI === "true";
export const WEB = process.env.WEB === "true";
export const itFailsE2e = E2E ? it.failing : it;
export const itRunsE2eOnly = E2E ? it : it.skip;
export const itRunsE2eOnly = E2E && !WEB ? it : it.skip;
export const itRunsNodeOnly = E2E ? it.skip : it;
export const itRunsCIAndNodeOnly = CI || !E2E ? it : it.skip;

Expand Down
Loading
Loading