Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Re.Pack is a toolkit for building and developing React Native applications with
- `apps/tester-federation/`: Module Federation v1 validation app.
- `apps/tester-federation-v2/`: Module Federation v2 validation app.

Rozenite DevTools in the tester apps are opt-in (`WITH_ROZENITE=true`); keep plugin imports in each tester's `rozenitePlugins.ts` so default and E2E runs never load them (see `CONTRIBUTING.md`).

### Tests

- `tests/integration/`: Integration-level automated coverage.
Expand Down
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ All development is done directly on GitHub, and all work is public.
2. Run `pnpm install` to install & set up the development environment.
3. Do the changes you want and test them out in the TesterApp (`apps/tester-app`) before sending a pull request.

To get extra [Rozenite](https://www.rozenite.dev) panels (network activity, plus navigation and storage in the Module Federation hosts) in React Native DevTools while testing, start a tester app's dev server with `WITH_ROZENITE=true`, e.g. `WITH_ROZENITE=true pnpm start`.

Without the flag, nothing Rozenite-related is loaded by the dev server or bundled into the app, so default runs and E2E tests are unaffected. Keep it that way when adding a plugin: import it only from the tester's `rozenitePlugins.ts`, which is required only when `__WITH_ROZENITE__` is true.

### Commit message convention

We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages:
Expand Down
3 changes: 3 additions & 0 deletions apps/tester-app/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import App from './src/App';
import { startDevTools } from './src/rozenite';

// ScriptManager setup
import './src/setup';

startDevTools();

AppRegistry.registerComponent(appName, () => App);
2 changes: 2 additions & 0 deletions apps/tester-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
"@react-native/babel-preset": "catalog:testers",
"@react-native/metro-config": "catalog:testers",
"@react-native/typescript-config": "catalog:testers",
"@rozenite/network-activity-plugin": "catalog:testers",
"@rozenite/repack": "catalog:testers",
"@rsdoctor/rspack-plugin": "1.6.4",
"@rspack/core": "catalog:",
"@svgr/webpack": "^8.1.0",
Expand Down
11 changes: 10 additions & 1 deletion apps/tester-app/rspack.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import path from 'node:path';
import * as Repack from '@callstack/repack';
import { NativeWindPlugin } from '@callstack/repack-plugin-nativewind';
import { ReanimatedPlugin } from '@callstack/repack-plugin-reanimated';
import { DefinePlugin } from '@rspack/core';

// Rsdoctor (through rslog) throws on import under Node < 20, so only load it
// when it's actually enabled to keep the Node 18 test matrix working.
const { RsdoctorRspackPlugin } = process.env.RSDOCTOR
? await import('@rsdoctor/rspack-plugin')
: {};

const withDevTools = process.env.WITH_ROZENITE === 'true';

const dirname = Repack.getDirname(import.meta.url);

export default Repack.defineRspackConfig((env) => {
const config = Repack.defineRspackConfig((env) => {
const {
mode = 'development',
context = dirname,
Expand Down Expand Up @@ -130,7 +133,13 @@ export default Repack.defineRspackConfig((env) => {
unstable_disableTransform: true,
}),
new NativeWindPlugin({ cssInteropOptions: { inlineRem: 16 } }),
new DefinePlugin({ __WITH_ROZENITE__: withDevTools }),
process.env.RSDOCTOR && new RsdoctorRspackPlugin(),
].filter(Boolean),
};
});

// Rozenite is only loaded with WITH_ROZENITE=true (see CONTRIBUTING.md).
export default withDevTools
? (await import('@rozenite/repack')).withRozenite(config, { enabled: true })
: config;
3 changes: 3 additions & 0 deletions apps/tester-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import { MiniAppsContainer } from './miniapp/MiniAppsContainer';
import { NativeWindView } from './nativewind/NativeWindView';
import { ReanimatedBox } from './reanimated/ReanimatedBox';
import { RemoteContainer } from './remoteChunks/RemoteContainer';
import { useDevTools } from './rozenite';
import { AppContainer } from './ui/AppContainer';
import { Section } from './ui/Section';
import { SectionContainer } from './ui/SectionContainer';

Appearance.setColorScheme('light');

const App = () => {
useDevTools();

return (
<AppContainer>
<SectionContainer>
Expand Down
2 changes: 2 additions & 0 deletions apps/tester-app/src/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
declare module '*.png';
declare module '*.svg';

declare const __WITH_ROZENITE__: boolean;
8 changes: 8 additions & 0 deletions apps/tester-app/src/rozenite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Rozenite DevTools plugins are opt-in. `__WITH_ROZENITE__` is only true when
// the dev server runs with WITH_ROZENITE=true; otherwise the bundler drops the
// require below and the app (including E2E runs) contains no DevTools code.
const plugins: typeof import('./rozenitePlugins') | undefined =
__WITH_ROZENITE__ ? require('./rozenitePlugins') : undefined;

export const startDevTools = plugins?.startDevTools ?? (() => {});
export const useDevTools = plugins?.useDevTools ?? (() => {});
12 changes: 12 additions & 0 deletions apps/tester-app/src/rozenitePlugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {
useNetworkActivityDevTools,
withOnBootNetworkActivityRecording,
} from '@rozenite/network-activity-plugin';

export function startDevTools() {
withOnBootNetworkActivityRecording();
}

export function useDevTools() {
useNetworkActivityDevTools();
}
11 changes: 10 additions & 1 deletion apps/tester-app/webpack.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import * as Repack from '@callstack/repack';
import { NativeWindPlugin } from '@callstack/repack-plugin-nativewind';
import { ReanimatedPlugin } from '@callstack/repack-plugin-reanimated';
import TerserPlugin from 'terser-webpack-plugin';
import webpack from 'webpack';

const withDevTools = process.env.WITH_ROZENITE === 'true';

const dirname = Repack.getDirname(import.meta.url);

export default Repack.defineWebpackConfig((env) => {
const config = Repack.defineWebpackConfig((env) => {
const {
mode = 'development',
context = dirname,
Expand Down Expand Up @@ -130,6 +133,12 @@ export default Repack.defineWebpackConfig((env) => {
}),
new ReanimatedPlugin(),
new NativeWindPlugin(),
new webpack.DefinePlugin({ __WITH_ROZENITE__: withDevTools }),
],
};
});

// Rozenite is only loaded with WITH_ROZENITE=true (see CONTRIBUTING.md).
export default withDevTools
? (await import('@rozenite/repack')).withRozenite(config, { enabled: true })
: config;
3 changes: 3 additions & 0 deletions apps/tester-expo/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Stack } from 'expo-router';
import { useDevTools } from '../components/rozenite';

export default function RootLayout() {
useDevTools();

return <Stack />;
}
7 changes: 7 additions & 0 deletions apps/tester-expo/components/rozenite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Rozenite DevTools plugins are opt-in. `__WITH_ROZENITE__` is only true when
// the dev server runs with WITH_ROZENITE=true; otherwise the bundler drops the
// require below and the app contains no DevTools code.
const plugins: typeof import('./rozenitePlugins') | undefined =
__WITH_ROZENITE__ ? require('./rozenitePlugins') : undefined;

export const useDevTools = plugins?.useDevTools ?? (() => {});
5 changes: 5 additions & 0 deletions apps/tester-expo/components/rozenitePlugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { useNetworkActivityDevTools } from '@rozenite/network-activity-plugin';

export function useDevTools() {
useNetworkActivityDevTools();
}
2 changes: 2 additions & 0 deletions apps/tester-expo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
"@react-native-community/cli-platform-ios": "catalog:testers",
"@react-native/babel-preset": "catalog:testers",
"@react-native/community-cli-plugin": "catalog:testers",
"@rozenite/network-activity-plugin": "catalog:testers",
"@rozenite/repack": "catalog:testers",
"@rspack/core": "catalog:",
"@types/react": "catalog:testers",
"babel-preset-expo": "catalog:expo58",
Expand Down
15 changes: 14 additions & 1 deletion apps/tester-expo/rspack.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { fileURLToPath } from 'node:url';
import * as Repack from '@callstack/repack';
import { ExpoPlugin } from '@callstack/repack-expo/rspack';
import { ReanimatedPlugin } from '@callstack/repack-plugin-reanimated';
import { DefinePlugin } from '@rspack/core';

const require = createRequire(import.meta.url);
const withDevTools = process.env.WITH_ROZENITE === 'true';
const projectRoot = path.dirname(fileURLToPath(import.meta.url));

// Must match the widget's shared list. Versions come from the installed
Expand All @@ -18,7 +20,7 @@ const SHARED_SINGLETONS = [
'expo-font',
];

export default (env) => {
const config = (env) => {
const {
mode = 'development',
platform = process.env.PLATFORM,
Expand All @@ -43,6 +45,7 @@ export default (env) => {
plugins: [
new ReanimatedPlugin({ unstable_disableTransform: true }),
new ExpoPlugin({ platform }),
new DefinePlugin({ __WITH_ROZENITE__: withDevTools }),
new Repack.plugins.ModuleFederationPluginV2({
name: 'ExpoHost',
dts: false,
Expand All @@ -64,3 +67,13 @@ export default (env) => {
],
};
};

// Rozenite is only loaded with WITH_ROZENITE=true (see CONTRIBUTING.md).
export default withDevTools
? (await import('@rozenite/repack')).withRozenite(config, {
enabled: true,
// Re.Pack serves DevTools through React Native's dev-middleware, not the
// copy bundled with Expo's CLI, so Rozenite has to patch that one.
projectType: 'react-native-cli',
})
: config;
1 change: 1 addition & 0 deletions apps/tester-expo/types/globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare const __WITH_ROZENITE__: boolean;
7 changes: 6 additions & 1 deletion apps/tester-federation-v2/config.host-app.mts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ const __dirname = path.dirname(__filename);

const useWebpack = Boolean(process.env.USE_WEBPACK);

export default (env: Repack.EnvOptions) => {
const config = (env: Repack.EnvOptions) => {
env.context = __dirname;

return useWebpack ? webpackConfig(env) : rspackConfig(env);
};

// Rozenite is only loaded with WITH_ROZENITE=true (see CONTRIBUTING.md).
export default process.env.WITH_ROZENITE === 'true'
? (await import('@rozenite/repack')).withRozenite(config, { enabled: true })
: config;
1 change: 1 addition & 0 deletions apps/tester-federation-v2/configs/rspack.host-app.mts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default Repack.defineRspackConfig((env) => {
resourceRegExp: /^@react-native-masked-view/,
}),
new rspack.DefinePlugin({
__WITH_ROZENITE__: process.env.WITH_ROZENITE === 'true',
__WITH_PRELOAD__:
process.env.WITH_PRELOAD === 'true' ||
process.env.WITH_PRELOAD === '1',
Expand Down
1 change: 1 addition & 0 deletions apps/tester-federation-v2/configs/webpack.host-app.mts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default Repack.defineWebpackConfig((env) => {
resourceRegExp: /^@react-native-masked-view/,
}),
new webpack.DefinePlugin({
__WITH_ROZENITE__: process.env.WITH_ROZENITE === 'true',
__WITH_PRELOAD__:
process.env.WITH_PRELOAD === 'true' ||
process.env.WITH_PRELOAD === '1',
Expand Down
4 changes: 4 additions & 0 deletions apps/tester-federation-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
"@react-native/community-cli-plugin": "catalog:testers",
"@react-native/metro-config": "catalog:testers",
"@react-native/typescript-config": "catalog:testers",
"@rozenite/network-activity-plugin": "catalog:testers",
"@rozenite/react-navigation-plugin": "catalog:testers",
"@rozenite/repack": "catalog:testers",
"@rozenite/storage-plugin": "catalog:testers",
"@rsdoctor/rspack-plugin": "1.6.4",
"@rspack/core": "catalog:",
"@swc/helpers": "catalog:",
Expand Down
1 change: 1 addition & 0 deletions apps/tester-federation-v2/src/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ declare module 'MiniApp/MiniAppNavigator' {
const MiniAppNavigator: ComponentType;
export default MiniAppNavigator;
}
declare const __WITH_ROZENITE__: boolean;
12 changes: 10 additions & 2 deletions apps/tester-federation-v2/src/host/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { NavigationContainer } from '@react-navigation/native';
import {
NavigationContainer,
useNavigationContainerRef,
} from '@react-navigation/native';
import MainNavigator from './navigation/MainNavigator';
import { useDevTools } from './rozenite';

const App = () => {
const navigationRef = useNavigationContainerRef();

useDevTools(navigationRef);

return (
<NavigationContainer>
<NavigationContainer ref={navigationRef}>
<MainNavigator />
</NavigationContainer>
);
Expand Down
3 changes: 3 additions & 0 deletions apps/tester-federation-v2/src/host/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { AppRegistry } from 'react-native';

import { components } from '../../app.json';
import App from './App';
import { startDevTools } from './rozenite';

startDevTools();

if (__WITH_PRELOAD__) {
// enable caching of scripts in the AsyncStorage
Expand Down
8 changes: 8 additions & 0 deletions apps/tester-federation-v2/src/host/rozenite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Rozenite DevTools plugins are opt-in. `__WITH_ROZENITE__` is only true when
// the dev server runs with WITH_ROZENITE=true; otherwise the bundler drops the
// require below and the app (including E2E runs) contains no DevTools code.
const plugins: typeof import('./rozenitePlugins') | undefined =
__WITH_ROZENITE__ ? require('./rozenitePlugins') : undefined;

export const startDevTools = plugins?.startDevTools ?? (() => {});
export const useDevTools = plugins?.useDevTools ?? (() => {});
28 changes: 28 additions & 0 deletions apps/tester-federation-v2/src/host/rozenitePlugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import type { NavigationContainerRefWithCurrent } from '@react-navigation/native';
import {
useNetworkActivityDevTools,
withOnBootNetworkActivityRecording,
} from '@rozenite/network-activity-plugin';
import { useReactNavigationDevTools } from '@rozenite/react-navigation-plugin';
import {
createAsyncStorageAdapter,
useRozeniteStoragePlugin,
} from '@rozenite/storage-plugin';

// ScriptManager caches remote scripts in AsyncStorage (see index.js).
const storages = [
createAsyncStorageAdapter({ storages: { ScriptManager: AsyncStorage } }),
];

export function startDevTools() {
withOnBootNetworkActivityRecording();
}

export function useDevTools(
navigationRef: NavigationContainerRefWithCurrent<ReactNavigation.RootParamList>
) {
useNetworkActivityDevTools();
useReactNavigationDevTools({ ref: navigationRef });
useRozeniteStoragePlugin({ storages });
}
7 changes: 6 additions & 1 deletion apps/tester-federation/config.host-app.mts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ const __dirname = path.dirname(__filename);

const useWebpack = Boolean(process.env.USE_WEBPACK);

export default (env: Repack.EnvOptions) => {
const config = (env: Repack.EnvOptions) => {
env.context = __dirname;

return useWebpack ? webpackConfig(env) : rspackConfig(env);
};

// Rozenite is only loaded with WITH_ROZENITE=true (see CONTRIBUTING.md).
export default process.env.WITH_ROZENITE === 'true'
? (await import('@rozenite/repack')).withRozenite(config, { enabled: true })
: config;
3 changes: 3 additions & 0 deletions apps/tester-federation/configs/rspack.host-app.mts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export default Repack.defineRspackConfig((env) => {
],
},
plugins: [
new rspack.DefinePlugin({
__WITH_ROZENITE__: process.env.WITH_ROZENITE === 'true',
}),
new Repack.RepackPlugin({
extraChunks: [
{
Expand Down
3 changes: 3 additions & 0 deletions apps/tester-federation/configs/webpack.host-app.mts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export default Repack.defineWebpackConfig((env) => {
],
},
plugins: [
new webpack.DefinePlugin({
__WITH_ROZENITE__: process.env.WITH_ROZENITE === 'true',
}),
// @ts-expect-error
new Repack.RepackPlugin({
extraChunks: [
Expand Down
4 changes: 4 additions & 0 deletions apps/tester-federation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
"@react-native/babel-preset": "catalog:testers",
"@react-native/metro-config": "catalog:testers",
"@react-native/typescript-config": "catalog:testers",
"@rozenite/network-activity-plugin": "catalog:testers",
"@rozenite/react-navigation-plugin": "catalog:testers",
"@rozenite/repack": "catalog:testers",
"@rozenite/storage-plugin": "catalog:testers",
"@rsdoctor/rspack-plugin": "1.6.4",
"@rspack/core": "catalog:",
"@swc/helpers": "catalog:",
Expand Down
1 change: 1 addition & 0 deletions apps/tester-federation/src/globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare const __WITH_ROZENITE__: boolean;
Loading
Loading