Skip to content

feat: add support for expo example in native libraries #725

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import https from 'https';
import { spawn } from '../utils/spawn';
import sortObjectKeys from '../utils/sortObjectKeys';
import type { TemplateConfiguration } from '../template';
import dedent from 'dedent';

const FILES_TO_DELETE = [
'__tests__',
@@ -35,20 +36,24 @@ const PACKAGES_TO_REMOVE = [
'typescript',
];

const PACKAGES_TO_ADD_WEB = {
const PACKAGES_TO_ADD_EXPO_WEB = {
'@expo/metro-runtime': '~3.2.1',
'react-dom': '18.2.0',
'react-native-web': '~0.18.10',
};

const PACKAGES_TO_ADD_DEV_EXPO_NATIVE = {
'expo-dev-client': '~5.0.3',
};

export default async function generateExampleApp({
config,
destination,
reactNativeVersion = 'latest',
}: {
config: TemplateConfiguration;
destination: string;
reactNativeVersion?: string;
reactNativeVersion: string | undefined;
}) {
const directory = path.join(destination, 'example');

@@ -219,14 +224,39 @@ export default async function generateExampleApp({
bundledNativeModules = {};
}

Object.entries(PACKAGES_TO_ADD_WEB).forEach(([name, version]) => {
dependencies[name] = bundledNativeModules[name] || version;
});
if (config.project.native) {
Object.entries(PACKAGES_TO_ADD_DEV_EXPO_NATIVE).forEach(
([name, version]) => {
devDependencies[name] = bundledNativeModules[name] || version;
}
);

scripts.start = 'expo start --dev-client';
scripts.android = 'expo run:android';
scripts.ios = 'expo run:ios';

delete scripts.web;

scripts.web = 'expo start --web';
await fs.writeFile(
path.join(directory, '.gitignore'),
dedent`
# These folders are generated with prebuild (CNG)
android/
ios/
`
);
} else {
Object.entries(PACKAGES_TO_ADD_EXPO_WEB).forEach(([name, version]) => {
dependencies[name] = bundledNativeModules[name] || version;
});

scripts.web = 'expo start --web';
}

const app = await fs.readJSON(path.join(directory, 'app.json'));

app.expo.name = `${config.project.name} Example`;
app.expo.slug = `${config.project.slug}-example`;
app.expo.android = app.expo.android || {};
app.expo.android.package = `${config.project.package}.example`;
app.expo.ios = app.expo.ios || {};
2 changes: 1 addition & 1 deletion packages/create-react-native-library/src/index.ts
Original file line number Diff line number Diff line change
@@ -103,9 +103,9 @@ async function create(_argv: yargs.Arguments<Args>) {
spinner.text = 'Generating example app';

await generateExampleApp({
config,
destination: folder,
reactNativeVersion: answers.reactNativeVersion,
config,
});
}

25 changes: 15 additions & 10 deletions packages/create-react-native-library/src/input.ts
Original file line number Diff line number Diff line change
@@ -57,6 +57,12 @@ const LANGUAGE_CHOICES: {

const EXAMPLE_CHOICES = (
[
{
title: 'App with Expo CLI',
value: 'expo',
description: 'managed expo app for easier upgrades',
disabled: false,
},
{
title: 'App with Community CLI',
value: 'vanilla',
@@ -71,12 +77,6 @@ const EXAMPLE_CHOICES = (
// Codegen spec shipping is implemented
disabled: !process.env.CRNL_ENABLE_TEST_APP,
},
{
title: 'App with Expo CLI',
value: 'expo',
description: 'managed expo app with web support',
disabled: false,
},
] as const
).filter((choice) => !choice.disabled);

@@ -304,10 +304,15 @@ export async function createQuestions({
}

return EXAMPLE_CHOICES.filter((choice) => {
if (values.type) {
return values.type === 'library'
? choice.value === 'expo'
: choice.value !== 'expo';
if (values.type === 'library') {
return choice.value === 'expo';
}

if (
values.type === 'legacy-module' ||
values.type === 'legacy-view'
) {
return choice.value !== 'expo';
}

return true;
8 changes: 6 additions & 2 deletions packages/create-react-native-library/src/template.ts
Original file line number Diff line number Diff line change
@@ -71,9 +71,9 @@ const EXAMPLE_MODULE_NEW_FILES = path.resolve(
'../templates/example-module-new'
);
const EXAMPLE_VIEW_FILES = path.resolve(__dirname, '../templates/example-view');
const EXAMPLE_EXPO_FILES = path.resolve(__dirname, '../templates/example-expo');

const JS_FILES = path.resolve(__dirname, '../templates/js-library');
const EXPO_FILES = path.resolve(__dirname, '../templates/expo-library');
const CPP_FILES = path.resolve(__dirname, '../templates/cpp-library');
const NATIVE_COMMON_FILES = path.resolve(
__dirname,
@@ -228,14 +228,18 @@ export async function applyTemplates(

if (answers.languages === 'js') {
await applyTemplate(config, JS_FILES, folder);
await applyTemplate(config, EXPO_FILES, folder);
await applyTemplate(config, EXAMPLE_EXPO_FILES, folder);
} else {
await applyTemplate(config, NATIVE_COMMON_FILES, folder);

if (config.example !== 'none') {
await applyTemplate(config, NATIVE_COMMON_EXAMPLE_FILES, folder);
}

if (config.example === 'expo') {
await applyTemplate(config, EXAMPLE_EXPO_FILES, folder);
}

if (config.project.moduleConfig === 'nitro-modules') {
await applyTemplate(config, NATIVE_FILES['module_nitro'], folder);
return;
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ module.exports = {
automaticPodsInstallation: true,
},
}),
<% } else { -%>
<% } else if (example === 'vanila') { -%>
project: {
ios: {
automaticPodsInstallation: true,
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
<% } -%>

<% if (project.arch === 'new') { -%>
#import "generated/RN<%- project.name -%>Spec/RN<%- project.name -%>Spec.h"
#import "RN<%- project.name -%>Spec/RN<%- project.name -%>Spec.h"

@interface <%- project.name -%> : NSObject <Native<%- project.name -%>Spec>
<% } else { -%>
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#import "<%- project.name -%>View.h"

#import "generated/RN<%- project.name -%>ViewSpec/ComponentDescriptors.h"
#import "generated/RN<%- project.name -%>ViewSpec/EventEmitters.h"
#import "generated/RN<%- project.name -%>ViewSpec/Props.h"
#import "generated/RN<%- project.name -%>ViewSpec/RCTComponentViewHelpers.h"
#import "RN<%- project.name -%>ViewSpec/ComponentDescriptors.h"
#import "RN<%- project.name -%>ViewSpec/EventEmitters.h"
#import "RN<%- project.name -%>ViewSpec/Props.h"
#import "RN<%- project.name -%>ViewSpec/RCTComponentViewHelpers.h"

#import "RCTFabricComponentsPlugins.h"