Skip to content
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

feat(crnl): support nitro modules #721

Merged
merged 67 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
1499260
feat: add script target
atlj Dec 18, 2024
5d87d8b
feat: add clean to the script target
atlj Dec 19, 2024
a616c1a
feat: rename script target to custom
atlj Dec 19, 2024
0e41168
feat: add nitro option to cli
atlj Nov 29, 2024
789f79a
fix: don't print using undefined react native version
atlj Nov 29, 2024
cad25f0
feat: add new arch to nitro modules
atlj Nov 29, 2024
06f7984
feat: apply the nitro template
atlj Nov 29, 2024
0efb509
feat: create index and nitro files
atlj Nov 29, 2024
f6484a2
feat: add required stuff to podspec
atlj Nov 29, 2024
80a0f33
feat: add cmakelist
atlj Nov 29, 2024
9fb5b5e
feat: add cpp adapter
atlj Nov 29, 2024
ac53b27
feat: don't add codegen with nitro
atlj Nov 29, 2024
9b8d769
feat: don't add rnccli for nitro
atlj Nov 29, 2024
a6d0f52
feat: add kotlin files
atlj Nov 29, 2024
1929712
feat: add swift code
atlj Nov 29, 2024
8723891
feat: make the necessary changes on build.gradle
atlj Nov 29, 2024
4459982
feat: don't add codegen prebuild when we ship nitro
atlj Nov 29, 2024
7b87e09
feat: add dependencies for nitro
atlj Nov 29, 2024
3229eb2
feat: add nitro to contributing
atlj Nov 29, 2024
79ba42f
feat: make swift vars public
atlj Nov 29, 2024
4c966b2
feat: print nitro docs prompt
atlj Nov 29, 2024
f2f081e
feat: json is the worst format ever
atlj Nov 29, 2024
dba6258
fix: nitro json expects an array
atlj Nov 29, 2024
a353f39
fix: use correct podspec
atlj Nov 29, 2024
6ab7ad8
feat: add nitrogen script
atlj Nov 29, 2024
5136742
fix: type problems
atlj Nov 29, 2024
824c619
fix: remove newline on swift file
atlj Nov 29, 2024
43a074d
fix: use project name for pod name
atlj Nov 29, 2024
0d64a74
fix: make index a tsx file
atlj Nov 29, 2024
b89a74e
fix: redundant podspec file
atlj Nov 29, 2024
0cc4278
fix: use project package cpp for autolinking
atlj Nov 29, 2024
8f6b3a1
fix: pass args to cmake
atlj Nov 29, 2024
8619de7
docs: add installation steps
atlj Nov 29, 2024
7d7f5bc
fix: move the autolinked package file to correct package
atlj Dec 6, 2024
983a0ed
chore: formatting
atlj Dec 6, 2024
47d8fcd
fix: remove unnecessary package json
atlj Dec 6, 2024
fe6a397
fix: better spacing
atlj Dec 6, 2024
bcae200
fix: correct the nitro paths
atlj Dec 6, 2024
5f319f6
chore: add nitro to CI
atlj Dec 6, 2024
15e4ec0
Update packages/create-react-native-library/templates/common/CONTRIBU…
atlj Dec 6, 2024
b89fd91
Update packages/create-react-native-library/src/inform.ts
atlj Dec 6, 2024
e059088
docs: update comment
atlj Dec 16, 2024
0067944
feat: add newline with nitro
atlj Dec 16, 2024
36fffd7
feat: don't mention the nitro docs when user creates a lib
atlj Dec 16, 2024
7cc2ee3
chore: remove unnecessary $ from file names
atlj Dec 16, 2024
c199ec3
feat: explain why nitro modules are needed as a dependency
atlj Dec 16, 2024
8075719
feat: change nitro description
atlj Dec 16, 2024
0ce079e
refactor: remove package_array
atlj Dec 16, 2024
0caf3e1
feat: remove unnecessary comment
atlj Dec 16, 2024
40b8608
refactor: introduce viewConfig and moduleConfig
atlj Dec 16, 2024
1c89f26
add newline in nitro ts
atlj Dec 17, 2024
6084bf5
fix: use the correct cpp path
atlj Dec 17, 2024
46019fc
feat: only ignore jsi libs on nitro modules
atlj Dec 17, 2024
0a8c374
feat: ignore nitrogen
atlj Dec 17, 2024
95ee4d1
feat: add nitrogen custom target
atlj Dec 19, 2024
adb1fc5
feat: generate codegen code on lib ci
atlj Dec 19, 2024
d3ce21f
fix: remove nitrogen step
atlj Dec 19, 2024
55116bf
feat: only fetch the nitro version when the module type is nitro
atlj Dec 19, 2024
66d25f1
feat: make nitro the second option and add an experimental label
atlj Dec 20, 2024
1313c42
feat: remove one doc link from contributing
atlj Dec 20, 2024
704ad91
feat: pin the nitro modules peer dep
atlj Dec 22, 2024
810d5d4
feat: update ios template with the latest version
atlj Dec 23, 2024
74f3182
update the fallback nitro version
atlj Feb 7, 2025
dd0ba45
change a few words in contributing guide
atlj Feb 7, 2025
fc35623
remove the memory size from hybrid objects
atlj Feb 7, 2025
3411f2c
don't strip the nitro module code when proguard is enabled
atlj Feb 7, 2025
ba17214
fix linting issues
atlj Feb 7, 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
5 changes: 5 additions & 0 deletions .github/workflows/build-templates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
- fabric-view
- legacy-module
- legacy-view
- nitro-module
language:
- kotlin-objc
- kotlin-swift
Expand All @@ -47,6 +48,10 @@ jobs:
language: cpp
- type: legacy-view
language: cpp
- type: nitro-module
language: kotlin-objc
- type: nitro-module
language: cpp
include:
- os: ubuntu
type: library
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import assert from 'node:assert';
import path from 'path';
import fs from 'fs-extra';
import type { ExampleApp } from '../input';
import type { TemplateConfiguration } from '../template';

export async function getDependencyVersionsFromExampleApp(
folder: string,
exampleAppType: ExampleApp
config: TemplateConfiguration
) {
const examplePackageJson = await fs.readJSON(
path.join(folder, 'example', 'package.json')
Expand All @@ -27,7 +27,11 @@ export async function getDependencyVersionsFromExampleApp(
'react-native': reactNative,
};

if (exampleAppType === 'vanilla') {
if (
config.example === 'vanilla' &&
(config.project.moduleConfig === 'turbo-modules' ||
config.project.viewConfig === 'fabric-view')
) {
// React Native doesn't provide the community CLI as a dependency.
// We have to get read the version from the example app and put to the root package json
const exampleCommunityCLIVersion =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from 'path';
import https from 'https';
import { spawn } from '../utils/spawn';
import sortObjectKeys from '../utils/sortObjectKeys';
import type { ExampleApp } from '../input';
import type { TemplateConfiguration } from '../template';

const FILES_TO_DELETE = [
'__tests__',
Expand Down Expand Up @@ -42,33 +42,23 @@ const PACKAGES_TO_ADD_WEB = {
};

export default async function generateExampleApp({
type,
dest,
arch,
project,
bobVersion,
config,
destination,
reactNativeVersion = 'latest',
}: {
type: ExampleApp;
dest: string;
arch: 'new' | 'legacy';
project: {
slug: string;
name: string;
package: string;
};
bobVersion: string;
config: TemplateConfiguration;
destination: string;
reactNativeVersion?: string;
}) {
const directory = path.join(dest, 'example');
const directory = path.join(destination, 'example');

// `npx --package react-native-test-app@latest init --name ${projectName}Example --destination example --version ${reactNativeVersion}`
const testAppArgs = [
'--package',
`react-native-test-app@latest`,
'init',
'--name',
`${project.name}Example`,
`${config.project.name}Example`,
`--destination`,
directory,
...(reactNativeVersion !== 'latest'
Expand All @@ -84,9 +74,9 @@ export default async function generateExampleApp({
const vanillaArgs = [
`@react-native-community/cli`,
'init',
`${project.name}Example`,
`${config.project.name}Example`,
'--package-name',
`${project.package}.example`,
`${config.project.package}.example`,
'--directory',
directory,
'--version',
Expand All @@ -107,7 +97,7 @@ export default async function generateExampleApp({

let args: string[] = [];

switch (type) {
switch (config.example) {
case 'vanilla':
args = vanillaArgs;
break;
Expand All @@ -131,7 +121,7 @@ export default async function generateExampleApp({
// Patch the example app's package.json
const pkg = await fs.readJSON(path.join(directory, 'package.json'));

pkg.name = `${project.slug}-example`;
pkg.name = `${config.project.slug}-example`;

// Remove Jest config for now
delete pkg.jest;
Expand All @@ -144,12 +134,12 @@ export default async function generateExampleApp({
const SCRIPTS_TO_ADD = {
'build:android':
'react-native build-android --extra-params "--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a"',
'build:ios': `react-native build-ios --scheme ${project.name}Example --mode Debug --extra-params "-sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO"`,
'build:ios': `react-native build-ios --scheme ${config.project.name}Example --mode Debug --extra-params "-sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO"`,
};

if (type === 'vanilla') {
if (config.example === 'vanilla') {
Object.assign(scripts, SCRIPTS_TO_ADD);
} else if (type === 'test-app') {
} else if (config.example === 'test-app') {
// `react-native-test-app` doesn't bundle application by default in 'Release' mode and also `bundle` command doesn't create a directory.
// `mkdist` script should be removed after stable React Native major contains this fix: https://github.com/facebook/react-native/pull/45182.

Expand All @@ -173,9 +163,9 @@ export default async function generateExampleApp({
const app = await fs.readJSON(path.join(directory, 'app.json'));

app.android = app.android || {};
app.android.package = `${project.package}.example`;
app.android.package = `${config.project.package}.example`;
app.ios = app.ios || {};
app.ios.bundleIdentifier = `${project.package}.example`;
app.ios.bundleIdentifier = `${config.project.package}.example`;

await fs.writeJSON(path.join(directory, 'app.json'), app, {
spaces: 2,
Expand All @@ -188,12 +178,19 @@ export default async function generateExampleApp({
});

const PACKAGES_TO_ADD_DEV = {
'react-native-builder-bob': `^${bobVersion}`,
'react-native-builder-bob': `^${config.versions.bob}`,
};

if (config.project.moduleConfig === 'nitro-modules') {
const packagesToAddNitro = {
'react-native-nitro-modules': `^${config.versions.nitroModules}`,
};
Object.assign(dependencies, packagesToAddNitro);
}

Object.assign(devDependencies, PACKAGES_TO_ADD_DEV);

if (type === 'expo') {
if (config.example === 'expo') {
const sdkVersion = dependencies.expo.split('.')[0].replace(/[^\d]/, '');

let bundledNativeModules: Record<string, string>;
Expand Down Expand Up @@ -231,15 +228,17 @@ export default async function generateExampleApp({
const app = await fs.readJSON(path.join(directory, 'app.json'));

app.expo.android = app.expo.android || {};
app.expo.android.package = `${project.package}.example`;
app.expo.android.package = `${config.project.package}.example`;
app.expo.ios = app.expo.ios || {};
app.expo.ios.bundleIdentifier = `${project.package}.example`;
app.expo.ios.bundleIdentifier = `${config.project.package}.example`;

await fs.writeJSON(path.join(directory, 'app.json'), app, {
spaces: 2,
});
}

// Sort the deps by name to match behavior of package managers
// This way the package.json doesn't get updated when installing deps
for (const field of ['dependencies', 'devDependencies']) {
if (pkg[field]) {
pkg[field] = sortObjectKeys(pkg[field]);
Expand All @@ -250,7 +249,7 @@ export default async function generateExampleApp({
spaces: 2,
});

if (type !== 'expo') {
if (config.example !== 'expo') {
let gradleProperties = await fs.readFile(
path.join(directory, 'android', 'gradle.properties'),
'utf8'
Expand All @@ -264,7 +263,7 @@ export default async function generateExampleApp({
);

// If the library is on new architecture, enable new arch for iOS and Android
if (arch === 'new') {
if (config.project.arch === 'new') {
// iOS
// Add ENV['RCT_NEW_ARCH_ENABLED'] = 1 on top of example/ios/Podfile
const podfile = await fs.readFile(
Expand Down
32 changes: 24 additions & 8 deletions packages/create-react-native-library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { getDependencyVersionsFromExampleApp } from './exampleApp/dependencies';
import { printErrorHelp, printNextSteps, printUsedRNVersion } from './inform';

const FALLBACK_BOB_VERSION = '0.36.0';
const FALLBACK_NITRO_MODULES_VERSION = '0.22.1';

yargs
.command(
Expand Down Expand Up @@ -48,6 +49,10 @@ async function create(_argv: yargs.Arguments<Args>) {
'react-native-builder-bob',
FALLBACK_BOB_VERSION
);
const nitroModulesVersionPromise = resolveNpmPackageVersion(
'react-native-nitro-modules',
FALLBACK_NITRO_MODULES_VERSION
);

const local = await promptLocalLibrary(argv);
const folder = await promptPath(argv, local);
Expand All @@ -70,8 +75,18 @@ async function create(_argv: yargs.Arguments<Args>) {

const bobVersion = await bobVersionPromise;

const nitroModulesVersion =
answers.type === 'nitro-module'
? await nitroModulesVersionPromise
: undefined;

const config = generateTemplateConfiguration({
bobVersion,
versions: {
bob: bobVersion,
nitroModules: nitroModulesVersion,
// Nitro codegen's version is always the same as nitro modules version.
nitroCodegen: nitroModulesVersion,
},
basename,
answers,
});
Expand All @@ -88,12 +103,9 @@ async function create(_argv: yargs.Arguments<Args>) {
spinner.text = 'Generating example app';

await generateExampleApp({
type: config.example,
dest: folder,
arch: config.project.arch,
project: config.project,
bobVersion,
destination: folder,
reactNativeVersion: answers.reactNativeVersion,
config,
});
}

Expand All @@ -106,7 +118,7 @@ async function create(_argv: yargs.Arguments<Args>) {
if (config.example !== 'none') {
const { devDependencies } = await getDependencyVersionsFromExampleApp(
folder,
config.example
config
);

rootPackageJson.devDependencies = rootPackageJson.devDependencies
Expand All @@ -117,7 +129,11 @@ async function create(_argv: yargs.Arguments<Args>) {
: devDependencies;
}

if (config.example === 'vanilla' && config.project.arch === 'new') {
if (
config.example === 'vanilla' &&
(config.project.moduleConfig === 'turbo-modules' ||
config.project.viewConfig === 'fabric-view')
) {
addCodegenBuildScript(folder);
}

Expand Down
17 changes: 12 additions & 5 deletions packages/create-react-native-library/src/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,24 @@ export type ProjectType =
| 'fabric-view'
| 'legacy-module'
| 'legacy-view'
| 'nitro-module'
| 'library';

const LANGUAGE_CHOICES: {
title: string;
value: ProjectLanguages;
types: ProjectType[];
}[] = [
{
title: 'Kotlin & Swift',
value: 'kotlin-swift',
types: ['nitro-module', 'legacy-module', 'legacy-view'],
},
{
title: 'Kotlin & Objective-C',
value: 'kotlin-objc',
types: ['turbo-module', 'fabric-view', 'legacy-module', 'legacy-view'],
},
{
title: 'Kotlin & Swift',
value: 'kotlin-swift',
types: ['legacy-module', 'legacy-view'],
},
{
title: 'C++ for Android & iOS',
value: 'cpp',
Expand Down Expand Up @@ -89,6 +90,12 @@ const TYPE_CHOICES: {
value: 'turbo-module',
description: 'integration for native APIs to JS',
},
{
title: 'Nitro module',
value: 'nitro-module',
description:
'type-safe, fast integration for native APIs to JS (experimental)',
},
{
title: 'Fabric view',
value: 'fabric-view',
Expand Down
Loading
Loading