From 05c7a024dc8cca7e9c78db655b79be62eb7e1ef0 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Fri, 28 Mar 2025 15:09:21 +0200 Subject: [PATCH 01/18] feat: add nitro view template --- .../common/$.github/workflows/ci.yml | 4 +-- .../templates/common/$package.json | 14 +++++----- .../templates/common/CONTRIBUTING.md | 3 ++ .../templates/common/README.md | 8 ++++-- .../native-common/android/build.gradle | 19 +++++++------ .../native-common/{%- project.name %}.podspec | 4 +-- .../nitro-view/android/CMakeLists.txt | 24 ++++++++++++++++ .../android/src/main/cpp/cpp-adapter.cpp | 6 ++++ .../{%- project.name %}.kt | 23 +++++++++++++++ .../{%- project.name %}Package.kt | 28 +++++++++++++++++++ .../nitro-view/ios/{%- project.name %}.swift | 28 +++++++++++++++++++ .../templates/nitro-view/nitro.json | 17 +++++++++++ .../templates/nitro-view/src/index.tsx | 8 ++++++ .../src/{%- project.name %}.nitro.ts | 12 ++++++++ 14 files changed, 176 insertions(+), 22 deletions(-) create mode 100644 packages/create-react-native-library/templates/nitro-view/android/CMakeLists.txt create mode 100644 packages/create-react-native-library/templates/nitro-view/android/src/main/cpp/cpp-adapter.cpp create mode 100644 packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}.kt create mode 100644 packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt create mode 100644 packages/create-react-native-library/templates/nitro-view/ios/{%- project.name %}.swift create mode 100644 packages/create-react-native-library/templates/nitro-view/nitro.json create mode 100644 packages/create-react-native-library/templates/nitro-view/src/index.tsx create mode 100644 packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts diff --git a/packages/create-react-native-library/templates/common/$.github/workflows/ci.yml b/packages/create-react-native-library/templates/common/$.github/workflows/ci.yml index 9fa7e5228..4dcbeeb8e 100644 --- a/packages/create-react-native-library/templates/common/$.github/workflows/ci.yml +++ b/packages/create-react-native-library/templates/common/$.github/workflows/ci.yml @@ -61,7 +61,7 @@ jobs: - name: Setup uses: ./.github/actions/setup -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> - name: Generate nitrogen code run: yarn nitrogen @@ -123,7 +123,7 @@ jobs: - name: Setup uses: ./.github/actions/setup -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> - name: Generate nitrogen code run: yarn nitrogen diff --git a/packages/create-react-native-library/templates/common/$package.json b/packages/create-react-native-library/templates/common/$package.json index 4a0f1184f..f56fe43a3 100644 --- a/packages/create-react-native-library/templates/common/$package.json +++ b/packages/create-react-native-library/templates/common/$package.json @@ -48,7 +48,7 @@ "clean": "del-cli lib", <% } -%> "prepare": "bob build", -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> "nitrogen": "nitro-codegen", <% } -%> "release": "release-it --only-version" @@ -91,15 +91,15 @@ "eslint-config-prettier": "^10.1.1", "eslint-plugin-prettier": "^5.2.3", "jest": "^29.7.0", -<% if (project.moduleConfig === 'nitro-modules') { -%> - "nitro-codegen": "^<%- versions.nitro %>", +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> + "nitro-codegen": "^<%- versions.nitroCodegen %>", <% } -%> "prettier": "^3.0.3", "react": "19.0.0", "react-native": "0.78.1", "react-native-builder-bob": "^<%- versions.bob %>", -<% if (project.moduleConfig === 'nitro-modules') { -%> - "react-native-nitro-modules": "^<%- versions.nitro %>", +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> + "react-native-nitro-modules": "^<%- versions.nitroModules %>", <% } -%> "release-it": "^17.10.0", <% if (example !== 'expo') { -%> @@ -109,7 +109,7 @@ }, "peerDependencies": { "react": "*", -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> "react-native": "*", "react-native-nitro-modules": "^<%- versions.nitro %>" <% } else { -%> @@ -164,7 +164,7 @@ "source": "src", "output": "lib", "targets": [ -<% if (project.moduleConfig === "nitro-modules") { -%> +<% if (project.moduleConfig === "nitro-modules" || project.viewConfig === "nitro-view") { -%> [ "custom", { diff --git a/packages/create-react-native-library/templates/common/CONTRIBUTING.md b/packages/create-react-native-library/templates/common/CONTRIBUTING.md index ab5549219..b2617b772 100644 --- a/packages/create-react-native-library/templates/common/CONTRIBUTING.md +++ b/packages/create-react-native-library/templates/common/CONTRIBUTING.md @@ -18,6 +18,7 @@ yarn ``` > Since the project relies on Yarn workspaces, you cannot use [`npm`](https://github.com/npm/cli) for development. +> <% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> <% if (project.moduleConfig === 'nitro-modules') { -%> This project uses Nitro Modules. If you're not familiar with how Nitro works, make sure to check the [Nitro Modules Docs](https://nitro.margelo.com/). @@ -35,6 +36,8 @@ To invoke **Nitrogen**, use the following command: yarn nitrogen ``` +<% } -%> + <% } -%> The [example app](/example/) demonstrates usage of the library. You need to run it to test any changes you make. diff --git a/packages/create-react-native-library/templates/common/README.md b/packages/create-react-native-library/templates/common/README.md index 5b34c58f1..aacb0cf34 100644 --- a/packages/create-react-native-library/templates/common/README.md +++ b/packages/create-react-native-library/templates/common/README.md @@ -4,16 +4,20 @@ ## Installation -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> + ```sh npm install <%- project.slug %> react-native-nitro-modules > `react-native-nitro-modules` is required as this library relies on [Nitro Modules](https://nitro.margelo.com/). ``` + <% } else { -%> + ```sh npm install <%- project.slug %> ``` + <% } -%> ## Usage @@ -28,7 +32,7 @@ import { <%- project.name -%>View } from "<%- project.slug -%>"; <<%- project.name -%>View color="tomato" /> ``` -<% } else if (project.moduleConfig === 'nitro-modules' || project.moduleConfig === 'turbo-modules') { -%> +<% } else if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view' || project.moduleConfig === 'turbo-modules') { -%> ```js import { multiply } from '<%- project.slug -%>'; diff --git a/packages/create-react-native-library/templates/native-common/android/build.gradle b/packages/create-react-native-library/templates/native-common/android/build.gradle index e9383fe6a..34436f2f1 100644 --- a/packages/create-react-native-library/templates/native-common/android/build.gradle +++ b/packages/create-react-native-library/templates/native-common/android/build.gradle @@ -15,7 +15,7 @@ buildscript { } } -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.cpp || project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> def reactNativeArchitectures() { def value = rootProject.getProperties().get("reactNativeArchitectures") return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] @@ -24,7 +24,7 @@ def reactNativeArchitectures() { apply plugin: "com.android.library" apply plugin: "kotlin-android" -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> apply from: '../nitrogen/generated/android/<%- project.package_cpp -%>+autolinking.gradle' <% } -%> @@ -35,8 +35,9 @@ def getExtOrIntegerDefault(name) { } android { -<% if (project.moduleConfig === 'nitro-modules') { -%> - namespace "com.margelo.nitro.<%- project.package -%>" + if (supportsNamespace()) { +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> + namespace "com.margelo.nitro.<%- project.package -%>" <% } else { -%> namespace "com.<%- project.package -%>" <% } -%> @@ -46,7 +47,7 @@ android { defaultConfig { minSdkVersion getExtOrIntegerDefault("minSdkVersion") targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.cpp || project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> externalNativeBuild { cmake { @@ -66,7 +67,7 @@ android { } <% } -%> } -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.cpp || project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> externalNativeBuild { cmake { @@ -74,7 +75,7 @@ android { } } <% } -%> -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> packagingOptions { excludes = [ @@ -100,7 +101,7 @@ android { buildFeatures { buildConfig true -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> prefab true <% } -%> } @@ -140,7 +141,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion") dependencies { implementation "com.facebook.react:react-android" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> implementation project(":react-native-nitro-modules") <% } -%> } diff --git a/packages/create-react-native-library/templates/native-common/{%- project.name %}.podspec b/packages/create-react-native-library/templates/native-common/{%- project.name %}.podspec index 17b3180b2..6a392b86b 100644 --- a/packages/create-react-native-library/templates/native-common/{%- project.name %}.podspec +++ b/packages/create-react-native-library/templates/native-common/{%- project.name %}.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.platforms = { :ios => min_ios_version_supported } s.source = { :git => "<%- repo -%>.git", :tag => "#{s.version}" } -<% if (project.moduleConfig !== "nitro-modules") { -%> +<% if (project.moduleConfig !== "nitro-modules" || project.viewConfig === "nitro-view") { -%> <% if (project.swift) { -%> s.source_files = "ios/**/*.{h,m,mm,swift}" <% } else { -%> @@ -22,7 +22,7 @@ Pod::Spec.new do |s| <% } -%> <% } -%> -<% if (project.moduleConfig === "nitro-modules") { -%> +<% if (project.moduleConfig === "nitro-modules" || project.viewConfig === "nitro-view") { -%> s.source_files = [ "ios/**/*.{swift}", "ios/**/*.{m,mm}", diff --git a/packages/create-react-native-library/templates/nitro-view/android/CMakeLists.txt b/packages/create-react-native-library/templates/nitro-view/android/CMakeLists.txt new file mode 100644 index 000000000..1fa9ed39d --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/android/CMakeLists.txt @@ -0,0 +1,24 @@ +project(<%- project.package_cpp -%>) +cmake_minimum_required(VERSION 3.9.0) + +set(PACKAGE_NAME <%- project.package_cpp -%>) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_CXX_STANDARD 20) + +# Define C++ library and add all sources +add_library(${PACKAGE_NAME} SHARED src/main/cpp/cpp-adapter.cpp) + +# Add Nitrogen specs :) +include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/<%- project.package_cpp -%>+autolinking.cmake) + +# Set up local includes +include_directories("src/main/cpp" "../cpp") + +find_library(LOG_LIB log) + +# Link all libraries together +target_link_libraries( + ${PACKAGE_NAME} + ${LOG_LIB} + android # <-- Android core +) diff --git a/packages/create-react-native-library/templates/nitro-view/android/src/main/cpp/cpp-adapter.cpp b/packages/create-react-native-library/templates/nitro-view/android/src/main/cpp/cpp-adapter.cpp new file mode 100644 index 000000000..8e1f6123b --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/android/src/main/cpp/cpp-adapter.cpp @@ -0,0 +1,6 @@ +#include +#include "<%- project.package_cpp -%>OnLoad.hpp" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { + return margelo::nitro::<%- project.package_cpp -%>::initialize(vm); +} diff --git a/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}.kt b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}.kt new file mode 100644 index 000000000..9634f8d57 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}.kt @@ -0,0 +1,23 @@ +package com.margelo.nitro.<%- project.package %> + +import android.view.View +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.uimanager.ThemedReactContext +import androidx.core.graphics.toColorInt + +@DoNotStrip +class Hybrid<%- project.name %>(val context: ThemedReactContext) : Hybrid<%- project.name %>Spec() { + + // View + override val view: View = View(context) + + // Props + private var _color = "#000" + override var color: String + get() = _color + set(value) { + _color = value + val color = value.toColorInt() + view.setBackgroundColor(color) + } +} diff --git a/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt new file mode 100644 index 000000000..c2ceba5af --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt @@ -0,0 +1,28 @@ +package com.<%- project.package %> + +import com.facebook.react.TurboReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfoProvider +import com.facebook.react.uimanager.ViewManager +import com.margelo.nitro.<%- project.package_cpp -%>.views.Hybrid<%- project.name -%>Manager + +class <%- project.name -%>Package : TurboReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return null + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { HashMap() } + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return listOf(Hybrid<%- project.name -%>Manager()) + } + + companion object { + init { + System.loadLibrary("<%- project.package_cpp -%>") + } + } +} diff --git a/packages/create-react-native-library/templates/nitro-view/ios/{%- project.name %}.swift b/packages/create-react-native-library/templates/nitro-view/ios/{%- project.name %}.swift new file mode 100644 index 000000000..0e4c8ef3c --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/ios/{%- project.name %}.swift @@ -0,0 +1,28 @@ +class Hybrid<%- project.name -%> : Hybrid<%- project.name -%>Spec { + + // UIView + var view: UIView = UIView() + + // props + var color: String = "#000" { + didSet { + view.backgroundColor = hexStringToUIColor(hexColor: color) + } + } + + func hexStringToUIColor(hexColor: String) -> UIColor { + let stringScanner = Scanner(string: hexColor) + + if(hexColor.hasPrefix("#")) { + stringScanner.scanLocation = 1 + } + var color: UInt32 = 0 + stringScanner.scanHexInt32(&color) + + let r = CGFloat(Int(color >> 16) & 0x000000FF) + let g = CGFloat(Int(color >> 8) & 0x000000FF) + let b = CGFloat(Int(color) & 0x000000FF) + + return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1) + } +} diff --git a/packages/create-react-native-library/templates/nitro-view/nitro.json b/packages/create-react-native-library/templates/nitro-view/nitro.json new file mode 100644 index 000000000..78941a518 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/nitro.json @@ -0,0 +1,17 @@ +{ + "cxxNamespace": ["<%- project.package_cpp -%>"], + "ios": { + "iosModuleName": "<%- project.name -%>" + }, + "android": { + "androidNamespace": <%- JSON.stringify(project.package.split('.')) -%>, + "androidCxxLibName": "<%- project.package_cpp -%>" + }, + "autolinking": { + "<%- project.name -%>": { + "swift": "Hybrid<%- project.name -%>", + "kotlin": "Hybrid<%- project.name -%>" + } + }, + "ignorePaths": ["node_modules"] +} diff --git a/packages/create-react-native-library/templates/nitro-view/src/index.tsx b/packages/create-react-native-library/templates/nitro-view/src/index.tsx new file mode 100644 index 000000000..67a42c92b --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/src/index.tsx @@ -0,0 +1,8 @@ +import { getHostComponent } from 'react-native-nitro-modules'; +import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; +import type { <%- project.name %>Methods, <%- project.name %>Props } from './<%- project.name %>.nitro'; + +export const <%- project.name %>View = getHostComponent<<%- project.name %>Props, <%- project.name %>Methods>( + '<%- project.name %>', + () => <%- project.name %>Config +); diff --git a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts new file mode 100644 index 000000000..467dcf832 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts @@ -0,0 +1,12 @@ +import type { + HybridView, + HybridViewMethods, + HybridViewProps, +} from 'react-native-nitro-modules'; + +export interface <%- project.name %>Props extends HybridViewProps { + color: string; +} +export interface <%- project.name %>Methods extends HybridViewMethods {} + +export type <%- project.name %> = HybridView<<%- project.name %>Props, <%- project.name %>Methods>; From faf1ce9bdd2e354babb942edb4d7e10a66618d66 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Fri, 28 Mar 2025 15:31:47 +0200 Subject: [PATCH 02/18] feat: add nitro view to template creation --- .../src/exampleApp/generateExampleApp.ts | 5 ++++- packages/create-react-native-library/src/index.ts | 3 +-- packages/create-react-native-library/src/input.ts | 9 ++++++++- packages/create-react-native-library/src/template.ts | 11 ++++++++++- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts index b8df1856b..b0c7e2530 100644 --- a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts +++ b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts @@ -196,7 +196,10 @@ export default async function generateExampleApp({ 'react-native-monorepo-config': `^0.1.9`, }; - if (config.project.moduleConfig === 'nitro-modules') { + if ( + config.project.moduleConfig === 'nitro-modules' || + config.project.viewConfig === 'nitro-view' + ) { const packagesToAddNitro = { 'react-native-nitro-modules': `^${config.versions.nitro || 'latest'}`, }; diff --git a/packages/create-react-native-library/src/index.ts b/packages/create-react-native-library/src/index.ts index 14b95ee26..b10847fb1 100644 --- a/packages/create-react-native-library/src/index.ts +++ b/packages/create-react-native-library/src/index.ts @@ -72,9 +72,8 @@ async function create(_argv: Args) { }); const bobVersion = await bobVersionPromise; - const nitroModulesVersion = - answers.type === 'nitro-module' + answers.type === 'nitro-module' || answers.type === 'nitro-view' ? await nitroModulesVersionPromise : undefined; diff --git a/packages/create-react-native-library/src/input.ts b/packages/create-react-native-library/src/input.ts index 387438548..2b75ce4cc 100644 --- a/packages/create-react-native-library/src/input.ts +++ b/packages/create-react-native-library/src/input.ts @@ -14,6 +14,7 @@ export type ProjectType = | 'turbo-module' | 'fabric-view' | 'nitro-module' + | 'nitro-view' | 'library'; const LANGUAGE_CHOICES: { @@ -24,7 +25,7 @@ const LANGUAGE_CHOICES: { { title: 'Kotlin & Swift', value: 'kotlin-swift', - types: ['nitro-module'], + types: ['nitro-module', 'nitro-view'], }, { title: 'Kotlin & Objective-C', @@ -84,6 +85,12 @@ const TYPE_CHOICES: { description: 'type-safe, fast integration for native APIs to JS (experimental)', }, + { + title: 'Nitro View', + value: 'nitro-view', + description: + 'integration for native views to JS using nitro for prop parsing (experimental)', + }, { title: 'JavaScript library', value: 'library', diff --git a/packages/create-react-native-library/src/template.ts b/packages/create-react-native-library/src/template.ts index bce76ee97..1a4e50b7c 100644 --- a/packages/create-react-native-library/src/template.ts +++ b/packages/create-react-native-library/src/template.ts @@ -14,7 +14,7 @@ export type ModuleConfig = | 'nitro-modules' | null; -export type ViewConfig = 'paper-view' | 'fabric-view' | null; +export type ViewConfig = 'paper-view' | 'fabric-view' | 'nitro-view' | null; // Please think at least 5 times before introducing a new config key // You can just reuse the existing ones most of the time @@ -76,6 +76,7 @@ const NATIVE_FILES = { module_new: path.resolve(__dirname, '../templates/native-library-new'), view_new: path.resolve(__dirname, '../templates/native-view-new'), module_nitro: path.resolve(__dirname, '../templates/nitro-module'), + view_nitro: path.resolve(__dirname, '../templates/nitro-view'), } as const; const OBJC_FILES = { @@ -163,9 +164,12 @@ function getViewConfig(projectType: ProjectType): ViewConfig { switch (projectType) { case 'fabric-view': return 'fabric-view'; + case 'nitro-view': + return 'nitro-view'; case 'nitro-module': case 'turbo-module': case 'library': + default: return null; } } @@ -208,6 +212,11 @@ export async function applyTemplates( return; } + if (config.project.viewConfig === 'nitro-view') { + await applyTemplate(config, NATIVE_FILES['view_nitro'], folder); + return; + } + if (config.project.moduleConfig !== null) { await applyTemplate(config, NATIVE_FILES[`module_new`], folder); } else { From 40cd008c9be021afd7c1287becaf116bb54c25a0 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Fri, 28 Mar 2025 15:35:46 +0200 Subject: [PATCH 03/18] feat: ios16 min deployment for nitro modules example app --- .../src/exampleApp/generateExampleApp.ts | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts index b0c7e2530..be29ba620 100644 --- a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts +++ b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts @@ -313,6 +313,76 @@ export default async function generateExampleApp({ gradleProperties += '\nnewArchEnabled=true'; } + // nitro modules on xcode 16.2 requires ios 16 version because of the bug https://github.com/swiftlang/swift/issues/77909 + // full thread in https://github.com/mrousavy/nitro/issues/422 + if ( + config.project.viewConfig === 'nitro-view' || + config.project.moduleConfig === 'nitro-modules' + ) { + const newTargetVersion = 16.0; + + const podfile = await fs.readFile( + path.join(directory, 'ios', 'Podfile'), + 'utf8' + ); + + const postInstallLine = 'post_install do |installer|'; + // set pods deployement min version + const podVersionOverride = ` + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '${newTargetVersion}' + end + end + `; + + const insertionIndex = podfile.indexOf(postInstallLine); + + if (insertionIndex !== -1) { + const endOfMarkerLineIndex = podfile.indexOf('\n', insertionIndex); + + if (endOfMarkerLineIndex !== -1) { + const updatedPodfileContent = + podfile.slice(0, endOfMarkerLineIndex) + + podVersionOverride + + podfile.slice(endOfMarkerLineIndex); + + await fs.writeFile( + path.join(directory, 'ios', 'Podfile'), + updatedPodfileContent + ); + } + } + + // set project deployement min version + const project = await fs.readFile( + path.join( + directory, + `ios/${config.project.name}Example.xcodeproj`, + 'project.pbxproj' + ), + 'utf8' + ); + + // match whole IPHONEOS_DEPLOYMENT_TARGET line + const deployementLineRegex = + /^(\s*)IPHONEOS_DEPLOYMENT_TARGET\s*=\s*[^;]+;$/gm; + const replacementPattern = `$1IPHONEOS_DEPLOYMENT_TARGET = ${newTargetVersion};`; + const updatedContent = project.replace( + deployementLineRegex, + replacementPattern + ); + + await fs.writeFile( + path.join( + directory, + `ios/${config.project.name}Example.xcodeproj`, + 'project.pbxproj' + ), + updatedContent + ); + } + await fs.writeFile( path.join(directory, 'android', 'gradle.properties'), gradleProperties From 9d3404ec23cba29f62a3720fe53e1b7f7fcacc42 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Fri, 28 Mar 2025 16:43:52 +0200 Subject: [PATCH 04/18] chore: remove autospace in readme From 24d8ee185dacf466a4861af98dfc1b59c05dce06 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Fri, 28 Mar 2025 16:45:11 +0200 Subject: [PATCH 05/18] chore: lower case Nitro view in selection --- packages/create-react-native-library/src/input.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-react-native-library/src/input.ts b/packages/create-react-native-library/src/input.ts index 2b75ce4cc..b17f22231 100644 --- a/packages/create-react-native-library/src/input.ts +++ b/packages/create-react-native-library/src/input.ts @@ -86,7 +86,7 @@ const TYPE_CHOICES: { 'type-safe, fast integration for native APIs to JS (experimental)', }, { - title: 'Nitro View', + title: 'Nitro view', value: 'nitro-view', description: 'integration for native views to JS using nitro for prop parsing (experimental)', From 2d595764b02e6dcb88b1d61fad8c8c075156c0fa Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Mon, 31 Mar 2025 16:09:30 +0300 Subject: [PATCH 06/18] fix: add nitro view to CI matrix --- .github/workflows/build-templates.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-templates.yml b/.github/workflows/build-templates.yml index f2bcad51e..a20b7109e 100644 --- a/.github/workflows/build-templates.yml +++ b/.github/workflows/build-templates.yml @@ -35,6 +35,8 @@ jobs: language: kotlin-objc - name: nitro-module language: kotlin-swift + - name: nitro-view + language: kotlin-swift include: - os: ubuntu-latest type: From bc3e0e0b61a8a84345b2d822924dcdb12f9d494d Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Mon, 31 Mar 2025 16:18:55 +0300 Subject: [PATCH 07/18] fix: prettier ci error --- .../templates/nitro-view/src/{%- project.name %}.nitro.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts index 467dcf832..2cbd723b4 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts +++ b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts @@ -9,4 +9,7 @@ export interface <%- project.name %>Props extends HybridViewProps { } export interface <%- project.name %>Methods extends HybridViewMethods {} -export type <%- project.name %> = HybridView<<%- project.name %>Props, <%- project.name %>Methods>; +export type <%- project.name %> = HybridView< + <%- project.name %>Props, + <%- project.name %>Methods +>; \ No newline at end of file From 1ce6b8c4b0d6b614f0b315b6287d5f3786c9affa Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Mon, 31 Mar 2025 17:28:23 +0300 Subject: [PATCH 08/18] fix: prettier formatting for CI --- .../templates/nitro-view/src/index.tsx | 13 ++++++++----- .../nitro-view/src/{%- project.name %}.nitro.ts | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/create-react-native-library/templates/nitro-view/src/index.tsx b/packages/create-react-native-library/templates/nitro-view/src/index.tsx index 67a42c92b..e260bef1f 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/index.tsx +++ b/packages/create-react-native-library/templates/nitro-view/src/index.tsx @@ -1,8 +1,11 @@ import { getHostComponent } from 'react-native-nitro-modules'; import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; -import type { <%- project.name %>Methods, <%- project.name %>Props } from './<%- project.name %>.nitro'; +import type { + <%- project.name %>Methods, + <%- project.name %>Props, +} from './<%- project.name %>.nitro'; -export const <%- project.name %>View = getHostComponent<<%- project.name %>Props, <%- project.name %>Methods>( - '<%- project.name %>', - () => <%- project.name %>Config -); +export const <%- project.name %>View = getHostComponent< + <%- project.name %>Props, + <%- project.name %>Methods +>('<%- project.name %>', () => <%- project.name %>Config); diff --git a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts index 2cbd723b4..194477f98 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts +++ b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts @@ -12,4 +12,4 @@ export interface <%- project.name %>Methods extends HybridViewMethods {} export type <%- project.name %> = HybridView< <%- project.name %>Props, <%- project.name %>Methods ->; \ No newline at end of file +>; From 652982ea6f128701b7bf9cfcfe09d172ae8b6555 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Tue, 1 Apr 2025 17:18:45 +0300 Subject: [PATCH 09/18] fix: add nitrogen step in CI --- .github/workflows/build-templates.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build-templates.yml b/.github/workflows/build-templates.yml index a20b7109e..70c1adea6 100644 --- a/.github/workflows/build-templates.yml +++ b/.github/workflows/build-templates.yml @@ -142,6 +142,10 @@ jobs: fi fi + - name: Generate nitrogen code + if: matrix.type == 'nitro-view' || matrix.type == 'nitro-module' + run: yarn nitrogen + - name: Cache turborepo if: env.android_build == 1 || env.ios_build == 1 uses: actions/cache@v4 From 2dd9c44907d052ea2bb20043765150fefa13a16e Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Tue, 1 Apr 2025 17:25:43 +0300 Subject: [PATCH 10/18] fix: add full nitro-codegen command --- .github/workflows/build-templates.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-templates.yml b/.github/workflows/build-templates.yml index 70c1adea6..e2166c7cf 100644 --- a/.github/workflows/build-templates.yml +++ b/.github/workflows/build-templates.yml @@ -144,7 +144,7 @@ jobs: - name: Generate nitrogen code if: matrix.type == 'nitro-view' || matrix.type == 'nitro-module' - run: yarn nitrogen + run: yarn nitro-codegen - name: Cache turborepo if: env.android_build == 1 || env.ios_build == 1 From 578894d5f114acc8a47a16d4611449a23800c7e4 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Tue, 1 Apr 2025 17:32:19 +0300 Subject: [PATCH 11/18] fix: add working dir to nitrogen --- .github/workflows/build-templates.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-templates.yml b/.github/workflows/build-templates.yml index e2166c7cf..0c1fe3d59 100644 --- a/.github/workflows/build-templates.yml +++ b/.github/workflows/build-templates.yml @@ -143,8 +143,9 @@ jobs: fi - name: Generate nitrogen code - if: matrix.type == 'nitro-view' || matrix.type == 'nitro-module' - run: yarn nitro-codegen + if: matrix.type == 'nitro-view' || matrix.type == 'nitro-module' + working-directory: ${{ env.work_dir }} + run: yarn nitrogen - name: Cache turborepo if: env.android_build == 1 || env.ios_build == 1 From 30e2f4a9b277611e8a917f5dab845cfabe53328c Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Fri, 4 Apr 2025 09:06:47 +0300 Subject: [PATCH 12/18] fix: change config json import to require --- .../templates/nitro-view/src/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/create-react-native-library/templates/nitro-view/src/index.tsx b/packages/create-react-native-library/templates/nitro-view/src/index.tsx index e260bef1f..6d2946c19 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/index.tsx +++ b/packages/create-react-native-library/templates/nitro-view/src/index.tsx @@ -1,5 +1,6 @@ import { getHostComponent } from 'react-native-nitro-modules'; -import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; +// import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; +const <%- project.name %>Config = require('../nitrogen/generated/shared/json/<%- project.name %>Config.json') import type { <%- project.name %>Methods, <%- project.name %>Props, From 3b9efd3e77e00ef53d16a94bb35181ccc225a67a Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Fri, 4 Apr 2025 09:20:36 +0300 Subject: [PATCH 13/18] chore: prettier fix --- .../templates/nitro-view/src/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/create-react-native-library/templates/nitro-view/src/index.tsx b/packages/create-react-native-library/templates/nitro-view/src/index.tsx index 6d2946c19..2f1c95268 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/index.tsx +++ b/packages/create-react-native-library/templates/nitro-view/src/index.tsx @@ -1,6 +1,5 @@ import { getHostComponent } from 'react-native-nitro-modules'; -// import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; -const <%- project.name %>Config = require('../nitrogen/generated/shared/json/<%- project.name %>Config.json') +const <%- project.name %>Config = require('../nitrogen/generated/shared/json/<%- project.name %>Config.json'); import type { <%- project.name %>Methods, <%- project.name %>Props, From dc488ae4dda6ce9a7a6b96b02d7cbef227da907d Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Tue, 24 Jun 2025 21:09:29 +0300 Subject: [PATCH 14/18] fix: remove workaround for xcode 16.2 --- .../src/constants.ts | 2 +- .../src/exampleApp/generateExampleApp.ts | 70 ------------------- .../src/template.ts | 1 + .../templates/common/CONTRIBUTING.md | 5 +- .../native-common/android/build.gradle | 3 +- 5 files changed, 4 insertions(+), 77 deletions(-) diff --git a/packages/create-react-native-library/src/constants.ts b/packages/create-react-native-library/src/constants.ts index 1cecfd74d..583385744 100644 --- a/packages/create-react-native-library/src/constants.ts +++ b/packages/create-react-native-library/src/constants.ts @@ -1,3 +1,3 @@ export const FALLBACK_BOB_VERSION = '0.40.8'; -export const FALLBACK_NITRO_MODULES_VERSION = '0.25.2'; +export const FALLBACK_NITRO_MODULES_VERSION = '0.26.2'; export const SUPPORTED_REACT_NATIVE_VERSION = '0.79.2'; diff --git a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts index be29ba620..b0c7e2530 100644 --- a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts +++ b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts @@ -313,76 +313,6 @@ export default async function generateExampleApp({ gradleProperties += '\nnewArchEnabled=true'; } - // nitro modules on xcode 16.2 requires ios 16 version because of the bug https://github.com/swiftlang/swift/issues/77909 - // full thread in https://github.com/mrousavy/nitro/issues/422 - if ( - config.project.viewConfig === 'nitro-view' || - config.project.moduleConfig === 'nitro-modules' - ) { - const newTargetVersion = 16.0; - - const podfile = await fs.readFile( - path.join(directory, 'ios', 'Podfile'), - 'utf8' - ); - - const postInstallLine = 'post_install do |installer|'; - // set pods deployement min version - const podVersionOverride = ` - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '${newTargetVersion}' - end - end - `; - - const insertionIndex = podfile.indexOf(postInstallLine); - - if (insertionIndex !== -1) { - const endOfMarkerLineIndex = podfile.indexOf('\n', insertionIndex); - - if (endOfMarkerLineIndex !== -1) { - const updatedPodfileContent = - podfile.slice(0, endOfMarkerLineIndex) + - podVersionOverride + - podfile.slice(endOfMarkerLineIndex); - - await fs.writeFile( - path.join(directory, 'ios', 'Podfile'), - updatedPodfileContent - ); - } - } - - // set project deployement min version - const project = await fs.readFile( - path.join( - directory, - `ios/${config.project.name}Example.xcodeproj`, - 'project.pbxproj' - ), - 'utf8' - ); - - // match whole IPHONEOS_DEPLOYMENT_TARGET line - const deployementLineRegex = - /^(\s*)IPHONEOS_DEPLOYMENT_TARGET\s*=\s*[^;]+;$/gm; - const replacementPattern = `$1IPHONEOS_DEPLOYMENT_TARGET = ${newTargetVersion};`; - const updatedContent = project.replace( - deployementLineRegex, - replacementPattern - ); - - await fs.writeFile( - path.join( - directory, - `ios/${config.project.name}Example.xcodeproj`, - 'project.pbxproj' - ), - updatedContent - ); - } - await fs.writeFile( path.join(directory, 'android', 'gradle.properties'), gradleProperties diff --git a/packages/create-react-native-library/src/template.ts b/packages/create-react-native-library/src/template.ts index 1a4e50b7c..f02a2919c 100644 --- a/packages/create-react-native-library/src/template.ts +++ b/packages/create-react-native-library/src/template.ts @@ -156,6 +156,7 @@ function getModuleConfig(projectType: ProjectType): ModuleConfig { return 'turbo-modules'; case 'fabric-view': case 'library': + case 'nitro-view': return null; } } diff --git a/packages/create-react-native-library/templates/common/CONTRIBUTING.md b/packages/create-react-native-library/templates/common/CONTRIBUTING.md index b2617b772..2c4d7f103 100644 --- a/packages/create-react-native-library/templates/common/CONTRIBUTING.md +++ b/packages/create-react-native-library/templates/common/CONTRIBUTING.md @@ -18,9 +18,8 @@ yarn ``` > Since the project relies on Yarn workspaces, you cannot use [`npm`](https://github.com/npm/cli) for development. -> <% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> This project uses Nitro Modules. If you're not familiar with how Nitro works, make sure to check the [Nitro Modules Docs](https://nitro.margelo.com/). You need to run [Nitrogen](https://nitro.margelo.com/docs/nitrogen) to generate the boilerplate code required for this project. The example app will not build without this step. @@ -36,8 +35,6 @@ To invoke **Nitrogen**, use the following command: yarn nitrogen ``` -<% } -%> - <% } -%> The [example app](/example/) demonstrates usage of the library. You need to run it to test any changes you make. diff --git a/packages/create-react-native-library/templates/native-common/android/build.gradle b/packages/create-react-native-library/templates/native-common/android/build.gradle index 34436f2f1..e742c7f85 100644 --- a/packages/create-react-native-library/templates/native-common/android/build.gradle +++ b/packages/create-react-native-library/templates/native-common/android/build.gradle @@ -35,9 +35,8 @@ def getExtOrIntegerDefault(name) { } android { - if (supportsNamespace()) { <% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> - namespace "com.margelo.nitro.<%- project.package -%>" + namespace "com.margelo.nitro.<%- project.package -%>" <% } else { -%> namespace "com.<%- project.package -%>" <% } -%> From 111c0d5f9280949c88d42af9584af1d8c2057f24 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Wed, 25 Jun 2025 19:31:25 +0300 Subject: [PATCH 15/18] fix: adjust package in nitro android example --- .../{%- project.package_dir %}/{%- project.name %}Package.kt | 2 +- .../{%- project.package_dir %}/{%- project.name %}Package.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/create-react-native-library/templates/nitro-module/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt b/packages/create-react-native-library/templates/nitro-module/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt index f832910bc..4e2b8f2da 100644 --- a/packages/create-react-native-library/templates/nitro-module/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt +++ b/packages/create-react-native-library/templates/nitro-module/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt @@ -1,4 +1,4 @@ -package com.<%- project.package %> +package com.margelo.nitro.<%- project.package %> import com.facebook.react.TurboReactPackage import com.facebook.react.bridge.NativeModule diff --git a/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt index c2ceba5af..c46a5ece2 100644 --- a/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt +++ b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt @@ -1,4 +1,4 @@ -package com.<%- project.package %> +package com.margelo.nitro.<%- project.package %> import com.facebook.react.TurboReactPackage import com.facebook.react.bridge.NativeModule From d7c355fc525de3221aa6cc7e209dfb386eb251c3 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Wed, 25 Jun 2025 19:32:10 +0300 Subject: [PATCH 16/18] fix: use unified nitro version in template package --- .../templates/common/$package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/create-react-native-library/templates/common/$package.json b/packages/create-react-native-library/templates/common/$package.json index f56fe43a3..a351f7776 100644 --- a/packages/create-react-native-library/templates/common/$package.json +++ b/packages/create-react-native-library/templates/common/$package.json @@ -92,14 +92,14 @@ "eslint-plugin-prettier": "^5.2.3", "jest": "^29.7.0", <% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> - "nitro-codegen": "^<%- versions.nitroCodegen %>", + "nitro-codegen": "^<%- versions.nitro %>", <% } -%> "prettier": "^3.0.3", "react": "19.0.0", "react-native": "0.78.1", "react-native-builder-bob": "^<%- versions.bob %>", <% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> - "react-native-nitro-modules": "^<%- versions.nitroModules %>", + "react-native-nitro-modules": "^<%- versions.nitro %>", <% } -%> "release-it": "^17.10.0", <% if (example !== 'expo') { -%> From b65a76735f969774d0ca1fab97148c899cefb482 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Wed, 25 Jun 2025 19:56:20 +0300 Subject: [PATCH 17/18] fix: remove whitespaces in readme From 3dda6aad93b724311f57d10bf8bb30d122edb7ca Mon Sep 17 00:00:00 2001 From: Juozas Petkelis Date: Wed, 25 Jun 2025 19:58:38 +0300 Subject: [PATCH 18/18] fix: remove additional whitespaces in readme