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
5 changes: 5 additions & 0 deletions .changeset/fluffy-mice-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@callstack/repack-plugin-expo": minor
---

Add Expo Router + CNG Plugin
5 changes: 5 additions & 0 deletions .changeset/full-nails-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@callstack/repack-plugin-expo": minor
---

Add Expo Managed tester application
7 changes: 7 additions & 0 deletions apps/tester-expo-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Build artifacts
.expo
build

# Native directories
/android
/ios
16 changes: 16 additions & 0 deletions apps/tester-expo-app/app.json
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran into some issues here when building Android, I think we are missing from fields like in the other tester app

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "tester-expo-app",
"slug": "tester-expo-app",
"scheme": "testerexpoapp",
"version": "0.0.1",
"android": {
"package": "com.testerexpoapp"
},
"ios": {
"bundleIdentifier": "com.testerexpoapp"
},
"plugins": [
["expo-router", { "root": "./src/screens" }],
"@callstack/repack-plugin-expo/plugin"
]
}
4 changes: 4 additions & 0 deletions apps/tester-expo-app/index.js
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we use registerRootComponent from expo here?

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { AppRegistry } from 'react-native';
import Application from './src/App.tsx';

AppRegistry.registerComponent('main', () => Application);
37 changes: 37 additions & 0 deletions apps/tester-expo-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "tester-expo-app",
"version": "0.0.1",
"private": true,
"main": "./index.js",
"scripts": {
"start": "react-native start",
"ios": "react-native run-ios --no-packager",
"android": "react-native run-android --no-packager",
"prebuild": "expo prebuild"
},
"dependencies": {
"expo": "catalog:",
"expo-linking": "~7.1.7",
"expo-router": "~5.1.5",
"react": "19.0.0",
"react-native": "0.79.5",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "~4.11.1"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@callstack/repack": "workspace:*",
"@callstack/repack-plugin-expo": "workspace:*",
"@react-native-community/cli": "catalog:testers",
"@react-native-community/cli-platform-android": "catalog:testers",
"@react-native-community/cli-platform-ios": "catalog:testers",
"@react-native/babel-preset": "catalog:testers",
"@react-native/typescript-config": "catalog:testers",
"@rspack/core": "catalog:",
"@swc/core": "^1.13.3",
"@swc/helpers": "catalog:",
"@types/react": "catalog:testers",
"react-native-test-app": "catalog:testers",
"typescript": "catalog:"
}
}
17 changes: 17 additions & 0 deletions apps/tester-expo-app/react-native.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const { configureProjects } = require('react-native-test-app');

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

module.exports = {
project: configureProjects({
android: {
sourceDir: 'android',
},
ios: {
sourceDir: 'ios',
},
}),
commands: useWebpack
? require('@callstack/repack/commands/webpack')
: require('@callstack/repack/commands/rspack'),
};
46 changes: 46 additions & 0 deletions apps/tester-expo-app/rspack.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { createRequire } from 'node:module';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

import * as Repack from '@callstack/repack';
import { ExpoPlugin } from '@callstack/repack-plugin-expo';
import { IgnorePlugin } from '@rspack/core';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const require = createRequire(import.meta.url);

export default Repack.defineRspackConfig({
context: __dirname,
entry: './index.js',
resolve: {
...Repack.getResolveOptions({ enablePackageExports: true }),
alias: {
// Alias both react and react-native to ensure that we don't end up with multiple versions
// of these libraries in the bundle.
//
// This is needed in these monorepo setups where there are multiple copies of react
// and react-native in the node_modules.
react: require.resolve('react'),
'react-native': require.resolve('react-native'),
Comment on lines +20 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this an issue here with pnpm? Sounds like this should happen in setups with hoisting 🤔

},
},
module: {
rules: [
...Repack.getJsTransformRules(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets use babel-swc-loader here instead (take a look at config for other tester)

...Repack.getAssetTransformRules(),
],
},
plugins: [
new Repack.RepackPlugin(),
new ExpoPlugin({
router: {
root: resolve('./src/screens'),
},
}),

// Ignore @react-native-masked-view warnings
new IgnorePlugin({ resourceRegExp: /^@react-native-masked-view/ }),
],
});
8 changes: 8 additions & 0 deletions apps/tester-expo-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ExpoRoot } from 'expo-router';
import { ctx } from 'expo-router/_ctx';

console.log(ctx.keys());

export default function Application() {
return <ExpoRoot context={ctx} />;
}
10 changes: 10 additions & 0 deletions apps/tester-expo-app/src/screens/_layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Stack } from 'expo-router';

export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ headerTitle: 'Home' }} />
<Stack.Screen name="about" options={{ headerTitle: 'About' }} />
</Stack>
);
}
18 changes: 18 additions & 0 deletions apps/tester-expo-app/src/screens/about.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useRouter } from 'expo-router';
import { Button, ScrollView } from 'react-native';

export default function AboutScreen() {
const router = useRouter();

return (
<ScrollView
contentContainerStyle={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Button title="Go back" onPress={router.back} />
</ScrollView>
);
}
18 changes: 18 additions & 0 deletions apps/tester-expo-app/src/screens/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Link } from 'expo-router';
import { Button, ScrollView } from 'react-native';

export default function IndexScreen() {
return (
<ScrollView
contentContainerStyle={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Link href="/about" asChild>
<Button title="Go to About" />
</Link>
</ScrollView>
);
}
8 changes: 8 additions & 0 deletions apps/tester-expo-app/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "@react-native/typescript-config",
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["**/node_modules", "**/Pods"],
"compilerOptions": {
"module": "ES2022" // for dynamic imports & top-level await
}
}
75 changes: 75 additions & 0 deletions packages/plugin-expo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<div align="center">
<img src="https://raw.githubusercontent.com/callstack/repack/HEAD/logo.png" width="650" alt="Re.Pack logo" />
<h3>A toolkit to build your React Native application with Rspack or Webpack.</h3>
</div>
<div align="center">

[![mit licence][license-badge]][license]
[![npm downloads][npm-downloads-badge]][npm-downloads]
[![Chat][chat-badge]][chat]
[![PRs Welcome][prs-welcome-badge]][prs-welcome]

</div>

`@callstack/repack-plugin-expo` is a plugin for [`@callstack/repack`](https://github.com/callstack/repack) that compliments the integration of Expo Router and Expo CNG into your React Native projects.

## About

This plugin helps and compliments the process of enabling Expo Router and Expo CNG in Re.Pack projects by defining necessary globals that are expected by Expo Router at runtime. However, it is not sufficient on its own for a complete setup. For comprehensive guidance on using Expo Router and Expo CNG with Re.Pack, please refer to our [official documentation](https://re-pack.dev/).

## Installation

```sh
npm install -D @callstack/repack-plugin-expo
```

## Usage

### Plugin

To add the plugin to your Re.Pack configuration, update your `rspack.config.js` or `webpack.config.js` as follows:

```js
import { ExpoPlugin } from "@callstack/repack-plugin-expo";

export default (env) => {
// ...
return {
// ...
plugins: [
// ...
new ExpoPlugin(),
],
};
};
```

### CNG Configuration Plugin

To add the configuration plugin to your Expo CNG configuration update your `app.json` or `app.config.js` as follows:

```jsonc
{
// ...
"plugins": [
// ...
"expo-router",
"@callstack/repack-plugin-expo/plugin"
]
}
```

---

Check out our website at https://re-pack.dev for more info and documentation or our GitHub: https://github.com/callstack/repack.

<!-- badges -->

[license-badge]: https://img.shields.io/npm/l/@callstack/repack?style=for-the-badge
[license]: https://github.com/callstack/repack/blob/main/LICENSE
[npm-downloads-badge]: https://img.shields.io/npm/dm/@callstack/repack?style=for-the-badge
[npm-downloads]: https://www.npmjs.com/package/@callstack/repack
[prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
[prs-welcome]: ./CONTRIBUTING.md
[chat-badge]: https://img.shields.io/discord/426714625279524876.svg?style=for-the-badge
[chat]: https://discord.gg/Q4yr2rTWYF
58 changes: 58 additions & 0 deletions packages/plugin-expo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@callstack/repack-plugin-expo",
"version": "5.1.3",
"description": "A plugin for @callstack/repack that integrates Expo CNG and Router",
"author": "Carlos Eduardo <[email protected]>",
"contributors": ["Jakub Romańczyk <[email protected]>"],
"license": "MIT",
"homepage": "https://github.com/callstack/repack",
"repository": "github:callstack/repack",
"type": "commonjs",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist", "plugin"],
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./plugin": {
"types": "./plugin/index.d.ts",
"default": "./plugin/index.js"
}
},
"keywords": [
"repack",
"re.pack",
"plugin",
"repack-plugin",
"expo-router",
"expo-cng",
"expo"
],
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"engineStrict": true,
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@callstack/repack": "workspace:*",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets define those explicitly as a starting point for this plugin 👍

from my experience its best to define versions with open upper boundary, like >=53.0.0

"@callstack/repack-plugin-expo-modules": "workspace:*",
"expo": "catalog:"
},
"devDependencies": {
"@callstack/repack": "workspace:*",
"@callstack/repack-plugin-expo-modules": "workspace:*",
"expo": "catalog:",
"@rspack/core": "catalog:",
"@types/node": "catalog:",
"webpack": "catalog:"
},
"scripts": {
"build": "tsc -p tsconfig.build.json",
"typecheck": "tsc --noEmit"
}
}
1 change: 1 addition & 0 deletions packages/plugin-expo/plugin/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../dist/config-plugin.js';
1 change: 1 addition & 0 deletions packages/plugin-expo/plugin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../dist/config-plugin.js');
Loading