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

Open
wants to merge 62 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
46ddcc3
feat: add script target
atlj Dec 18, 2024
fe2541b
feat: add clean to the script target
atlj Dec 19, 2024
8c83b6d
feat: rename script target to custom
atlj Dec 19, 2024
9d26a13
feat: add nitro option to cli
atlj Nov 29, 2024
07ed68a
fix: don't print using undefined react native version
atlj Nov 29, 2024
1eaf7eb
feat: add new arch to nitro modules
atlj Nov 29, 2024
fca9ff0
feat: apply the nitro template
atlj Nov 29, 2024
2081fcb
feat: create index and nitro files
atlj Nov 29, 2024
e681eae
feat: add required stuff to podspec
atlj Nov 29, 2024
e8f5caf
feat: add cmakelist
atlj Nov 29, 2024
f76b40c
feat: add cpp adapter
atlj Nov 29, 2024
9cafd09
feat: don't add codegen with nitro
atlj Nov 29, 2024
bc206e4
feat: don't add rnccli for nitro
atlj Nov 29, 2024
e8ac44a
feat: add kotlin files
atlj Nov 29, 2024
0ea5548
feat: add swift code
atlj Nov 29, 2024
57fbdbc
feat: make the necessary changes on build.gradle
atlj Nov 29, 2024
8ec51dc
feat: don't add codegen prebuild when we ship nitro
atlj Nov 29, 2024
90a6199
feat: add dependencies for nitro
atlj Nov 29, 2024
66e021a
feat: add nitro to contributing
atlj Nov 29, 2024
9a99a09
feat: make swift vars public
atlj Nov 29, 2024
ebb193e
feat: print nitro docs prompt
atlj Nov 29, 2024
c2380f5
feat: json is the worst format ever
atlj Nov 29, 2024
93e92dc
fix: nitro json expects an array
atlj Nov 29, 2024
b0f4920
fix: use correct podspec
atlj Nov 29, 2024
a9b5509
feat: add nitrogen script
atlj Nov 29, 2024
9d0f611
fix: type problems
atlj Nov 29, 2024
88edf48
fix: remove newline on swift file
atlj Nov 29, 2024
5715cfd
fix: use project name for pod name
atlj Nov 29, 2024
0dd5139
fix: make index a tsx file
atlj Nov 29, 2024
627d1c7
fix: redundant podspec file
atlj Nov 29, 2024
5967c5c
fix: use project package cpp for autolinking
atlj Nov 29, 2024
748f009
fix: pass args to cmake
atlj Nov 29, 2024
f647cef
docs: add installation steps
atlj Nov 29, 2024
7fcd809
fix: move the autolinked package file to correct package
atlj Dec 6, 2024
e168b11
chore: formatting
atlj Dec 6, 2024
72645bd
fix: remove unnecessary package json
atlj Dec 6, 2024
d6c14fa
fix: better spacing
atlj Dec 6, 2024
492af38
fix: correct the nitro paths
atlj Dec 6, 2024
3d057b7
chore: add nitro to CI
atlj Dec 6, 2024
221b1e4
Update packages/create-react-native-library/templates/common/CONTRIBU…
atlj Dec 6, 2024
faf940f
Update packages/create-react-native-library/src/inform.ts
atlj Dec 6, 2024
8f8cb09
docs: update comment
atlj Dec 16, 2024
e0d72b0
feat: add newline with nitro
atlj Dec 16, 2024
0d3de4b
feat: don't mention the nitro docs when user creates a lib
atlj Dec 16, 2024
bc2f42f
chore: remove unnecessary $ from file names
atlj Dec 16, 2024
ced03bc
feat: explain why nitro modules are needed as a dependency
atlj Dec 16, 2024
e8fae83
feat: change nitro description
atlj Dec 16, 2024
d0b4ca3
refactor: remove package_array
atlj Dec 16, 2024
c617ff0
feat: remove unnecessary comment
atlj Dec 16, 2024
c63565f
refactor: introduce viewConfig and moduleConfig
atlj Dec 16, 2024
024428c
add newline in nitro ts
atlj Dec 17, 2024
d296b20
fix: use the correct cpp path
atlj Dec 17, 2024
7efc356
feat: only ignore jsi libs on nitro modules
atlj Dec 17, 2024
8a1e45e
feat: ignore nitrogen
atlj Dec 17, 2024
f0d6783
feat: add nitrogen custom target
atlj Dec 19, 2024
f78f9a3
feat: generate codegen code on lib ci
atlj Dec 19, 2024
eed5089
fix: remove nitrogen step
atlj Dec 19, 2024
2cab29a
feat: only fetch the nitro version when the module type is nitro
atlj Dec 19, 2024
8e421d4
feat: make nitro the second option and add an experimental label
atlj Dec 20, 2024
1e45d9e
feat: remove one doc link from contributing
atlj Dec 20, 2024
78b9436
feat: pin the nitro modules peer dep
atlj Dec 22, 2024
d07a8e3
feat: update ios template with the latest version
atlj Dec 23, 2024
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
atlj marked this conversation as resolved.
Show resolved Hide resolved
- 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}`,
atlj marked this conversation as resolved.
Show resolved Hide resolved
};
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.32.0';
const FALLBACK_NITRO_MODULES_VERSION = '0.18.0';

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