diff --git a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts index cd8f50cd1..cba9422e1 100644 --- a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts +++ b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts @@ -406,7 +406,7 @@ export default async function generateExampleApp({ 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.slug = `${config.project.identifier}-example`; app.expo.android = app.expo.android ?? {}; app.expo.android.package = `${config.project.package}.example`; app.expo.ios = app.expo.ios ?? {}; diff --git a/packages/create-react-native-library/src/index.ts b/packages/create-react-native-library/src/index.ts index 401be0f67..d3bb671bd 100644 --- a/packages/create-react-native-library/src/index.ts +++ b/packages/create-react-native-library/src/index.ts @@ -133,7 +133,10 @@ async function create() { let addedNitro = false; - if (config.project.moduleConfig === 'nitro-modules') { + if ( + config.project.moduleConfig === 'nitro-modules' || + config.project.viewConfig === 'nitro-view' + ) { addedNitro = await addNitroDependencyToLocalLibrary(config); } diff --git a/packages/create-react-native-library/src/inform.ts b/packages/create-react-native-library/src/inform.ts index 23877f4ce..bcc09b06f 100644 --- a/packages/create-react-native-library/src/inform.ts +++ b/packages/create-react-native-library/src/inform.ts @@ -50,6 +50,10 @@ export function printLocalLibNextSteps({ addedNitro: boolean; packageManager: string; }) { + const isNitro = + config.project.moduleConfig === 'nitro-modules' || + config.project.viewConfig === 'nitro-view'; + console.log( dedent(` ${kleur.magenta( @@ -64,11 +68,18 @@ export function printLocalLibNextSteps({ : `- Link the library at ${kleur.blue( path.relative(process.cwd(), folder) )} based on your project setup\n`) + - (config.project.moduleConfig === 'nitro-modules' && !addedNitro + (isNitro && !addedNitro ? `- Run ${kleur.blue( `${packageManager} add react-native-nitro-modules` + )} and ${kleur.blue( + `${packageManager} add --dev nitrogen` )} to install nitro modules \n` : '') + + (isNitro + ? `- Run ${kleur.blue( + `cd ${path.relative(process.cwd(), folder)} && npx nitrogen` + )} to generate the nitro code \n` + : '') + `- Run ${kleur.blue( 'pod install --project-directory=ios' )} to install dependencies with CocoaPods\n` + diff --git a/packages/create-react-native-library/src/prompt.ts b/packages/create-react-native-library/src/prompt.ts index 7fc206f69..40a55dc1d 100644 --- a/packages/create-react-native-library/src/prompt.ts +++ b/packages/create-react-native-library/src/prompt.ts @@ -240,9 +240,17 @@ export const prompt = create(['[name]'], { return undefined; }, - validate: (input) => - validateNpmPackage(input).validForNewPackages || - 'Must be a valid npm package name', + validate: (input) => { + if (!validateNpmPackage(input).validForNewPackages) { + return 'Must be a valid npm package name'; + } + + if (!/^[a-z]/.test(input.replace(/^(react-native-|@[^/]+\/)/, ''))) { + return 'Must start with a letter after the scope or the react-native- prefix'; + } + + return true; + }, required: true, }, description: { diff --git a/packages/create-react-native-library/src/template.ts b/packages/create-react-native-library/src/template.ts index b6e09c776..56f50af5e 100644 --- a/packages/create-react-native-library/src/template.ts +++ b/packages/create-react-native-library/src/template.ts @@ -8,10 +8,9 @@ export type TemplateVersions = { nitro: string | undefined; }; -export type ModuleConfig = - 'native-modules' | 'turbo-modules' | 'nitro-modules' | null; +export type ModuleConfig = 'turbo-modules' | 'nitro-modules' | null; -export type ViewConfig = 'paper-view' | 'fabric-view' | 'nitro-view' | null; +export type ViewConfig = '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 @@ -201,9 +200,10 @@ export function generateTemplateConfiguration({ ? // If the project name is already in PascalCase, use it as-is basename : // Otherwise, convert it to PascalCase and remove any non-alphanumeric characters - `${project.charAt(0).toUpperCase()}${project - .replace(/[^a-z0-9](\w)/g, (_, $1: string) => $1.toUpperCase()) - .slice(1)}`, + project + .split(/[^a-z0-9]+/) + .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`) + .join(''), package: pack, package_dir: pack.replace(/\./g, path.sep), package_cpp: pack.replace(/\./g, '_'), @@ -277,104 +277,52 @@ export async function applyTemplates( } } - if (answers.languages === 'js') { - await applyTemplate(config, JS_FILES, folder); - - if (config.example != null) { - if (config.example === 'expo') { - await applyTemplate(config, EXAMPLE_EXPO_FILES, folder); - } else { - await applyTemplate(config, EXAMPLE_BARE_FILES, folder); - } + if (config.example != null) { + if (config.example === 'expo') { + await applyTemplate(config, EXAMPLE_EXPO_FILES, folder); + } else { + await applyTemplate(config, EXAMPLE_BARE_FILES, folder); } - } else { - if (answers.languages === 'cpp') { - if (config.example === 'expo') { - await applyTemplate(config, EXAMPLE_EXPO_FILES, folder); - - if (config.project.native) { - await applyTemplate(config, EXAMPLE_NATIVE_COMMON_FILES, folder); - } - } else if (config.example != null) { - await applyTemplate(config, EXAMPLE_BARE_FILES, folder); - - if (config.project.native) { - await applyTemplate(config, EXAMPLE_NATIVE_COMMON_FILES, folder); - } - } - await applyTemplate(config, NATIVE_FILES['module_new'], folder); - await applyTemplate(config, CPP_FILES, folder); - - if (config.example === 'expo' || config.tools.includes('vite')) { - await applyTemplate(config, JS_FILES, folder); - } - - return; + if (config.project.native) { + await applyTemplate(config, EXAMPLE_NATIVE_COMMON_FILES, folder); } + } - await applyTemplate(config, NATIVE_COMMON_FILES, folder); - - if (config.example === 'expo') { - await applyTemplate(config, EXAMPLE_EXPO_FILES, folder); + if (answers.languages === 'js') { + await applyTemplate(config, JS_FILES, folder); - if (config.project.native) { - await applyTemplate(config, EXAMPLE_NATIVE_COMMON_FILES, folder); - } - } else if (config.example != null) { - await applyTemplate(config, EXAMPLE_BARE_FILES, folder); + return; + } - if (config.project.native) { - await applyTemplate(config, EXAMPLE_NATIVE_COMMON_FILES, folder); - } - } + if (answers.languages === 'cpp') { + await applyTemplate(config, NATIVE_FILES['module_new'], folder); + await applyTemplate(config, CPP_FILES, folder); + } else { + await applyTemplate(config, NATIVE_COMMON_FILES, folder); if (config.project.moduleConfig === 'nitro-modules') { await applyTemplate(config, NITRO_COMMON_FILES, folder); await applyTemplate(config, NATIVE_FILES['module_nitro'], folder); - - if (config.example === 'expo' || config.tools.includes('vite')) { - await applyTemplate(config, JS_FILES, folder); - } - - return; - } - - if (config.project.viewConfig === 'nitro-view') { + } else if (config.project.viewConfig === 'nitro-view') { await applyTemplate(config, NITRO_COMMON_FILES, folder); await applyTemplate(config, NATIVE_FILES['view_nitro'], folder); - - if (config.example === 'expo' || config.tools.includes('vite')) { - await applyTemplate(config, JS_VIEW_FILES, folder); - } - - return; - } - - if (config.project.moduleConfig !== null) { - await applyTemplate(config, NATIVE_FILES[`module_new`], folder); + } else if (config.project.moduleConfig !== null) { + await applyTemplate(config, NATIVE_FILES['module_new'], folder); + await applyTemplate(config, OBJC_FILES['module_common'], folder); + await applyTemplate(config, KOTLIN_FILES['module_new'], folder); } else { - await applyTemplate(config, NATIVE_FILES[`view_new`], folder); + await applyTemplate(config, NATIVE_FILES['view_new'], folder); + await applyTemplate(config, OBJC_FILES['view_new'], folder); + await applyTemplate(config, KOTLIN_FILES['view_new'], folder); } + } - if (config.project.moduleConfig !== null) { - await applyTemplate(config, OBJC_FILES[`module_common`], folder); + if (config.example === 'expo' || config.tools.includes('vite')) { + if (config.project.viewConfig !== null) { + await applyTemplate(config, JS_VIEW_FILES, folder); } else { - await applyTemplate(config, OBJC_FILES[`view_new`], folder); - } - - const templateType = `${ - config.project.moduleConfig !== null ? 'module' : 'view' - }_new` as const; - - await applyTemplate(config, KOTLIN_FILES[templateType], folder); - - if (config.example === 'expo' || config.tools.includes('vite')) { - if (config.project.viewConfig !== null) { - await applyTemplate(config, JS_VIEW_FILES, folder); - } else { - await applyTemplate(config, JS_FILES, folder); - } + await applyTemplate(config, JS_FILES, folder); } } } diff --git a/packages/create-react-native-library/src/utils/local.ts b/packages/create-react-native-library/src/utils/local.ts index bfb73b6e6..82077c7ec 100644 --- a/packages/create-react-native-library/src/utils/local.ts +++ b/packages/create-react-native-library/src/utils/local.ts @@ -4,6 +4,7 @@ import type { TemplateConfiguration } from '../template.ts'; type PackageJson = { dependencies?: Record; + devDependencies?: Record; }; /** @returns `true` if successfull */ @@ -21,10 +22,13 @@ export async function addNitroDependencyToLocalLibrary( const appPackageJson: PackageJson = await fs.readJson(appPackageJsonPath); const dependencies = appPackageJson['dependencies'] ?? {}; + const devDependencies = appPackageJson['devDependencies'] ?? {}; dependencies['react-native-nitro-modules'] = config.versions.nitro; + devDependencies['nitrogen'] = config.versions.nitro; appPackageJson['dependencies'] = dependencies; + appPackageJson['devDependencies'] = devDependencies; await fs.writeJson(appPackageJsonPath, appPackageJson, { spaces: 2, }); diff --git a/packages/create-react-native-library/src/utils/resolveNpmPackageVersion.ts b/packages/create-react-native-library/src/utils/resolveNpmPackageVersion.ts index e41333c83..dc0896f3c 100644 --- a/packages/create-react-native-library/src/utils/resolveNpmPackageVersion.ts +++ b/packages/create-react-native-library/src/utils/resolveNpmPackageVersion.ts @@ -3,7 +3,7 @@ import { spawn } from './spawn.ts'; export async function resolveNpmPackageVersion( name: string, fallback: string, - timeout: number = 1000 + timeout: number = 5000 ): Promise { let result: string; @@ -14,7 +14,7 @@ export async function resolveNpmPackageVersion( new Promise((resolve) => { setTimeout(() => { resolve(fallback); - }, timeout); + }, timeout).unref(); }), promise, ]); diff --git a/packages/create-react-native-library/templates/common-local/$package.json b/packages/create-react-native-library/templates/common-local/$package.json index 2462f7b06..894db6b5f 100644 --- a/packages/create-react-native-library/templates/common-local/$package.json +++ b/packages/create-react-native-library/templates/common-local/$package.json @@ -1,8 +1,9 @@ { "name": "<%- project.slug -%>", "version": "0.0.0", - "description": "<%- project.description %>", + "description": <%- JSON.stringify(project.description) %>, "main": "src/index", +<% if (project.moduleConfig === 'turbo-modules' || project.viewConfig === 'fabric-view') { -%> "codegenConfig": { "name": "<%- project.name -%><%- project.viewConfig !== null ? 'View': '' -%>Spec", "type": <%- project.viewConfig !== null ? '"all"': '"modules"' %>, @@ -20,6 +21,7 @@ <% } -%> } }, +<% } -%> "author": "<%- author.name -%> <<%- author.email -%>> (<%- author.url -%>)", "license": "UNLICENSED", "homepage": "<%- repo -%>#readme" diff --git a/packages/create-react-native-library/templates/common/$.github/actions/setup/action.yml b/packages/create-react-native-library/templates/common/$.github/actions/setup/action.yml index a61333276..5cd9434ad 100644 --- a/packages/create-react-native-library/templates/common/$.github/actions/setup/action.yml +++ b/packages/create-react-native-library/templates/common/$.github/actions/setup/action.yml @@ -5,13 +5,13 @@ runs: using: composite steps: - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version-file: .nvmrc - name: Restore dependencies id: yarn-cache - uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | **/node_modules @@ -28,7 +28,7 @@ runs: - name: Cache dependencies if: steps.yarn-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | **/node_modules 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 b6cf8b81c..15ff1aa55 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 @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup uses: ./.github/actions/setup @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup uses: ./.github/actions/setup @@ -53,7 +53,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup uses: ./.github/actions/setup @@ -61,7 +61,7 @@ jobs: - name: Build package run: yarn prepare -<% if (example != null) { -%> +<% if (project.native) { -%> build-android: runs-on: ubuntu-latest @@ -70,7 +70,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup uses: ./.github/actions/setup @@ -81,7 +81,7 @@ jobs: <% } -%> - name: Cache turborepo for Android - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ${{ env.TURBO_CACHE_DIR }} key: ${{ runner.os }}-turborepo-android-${{ hashFiles('yarn.lock') }} @@ -98,7 +98,7 @@ jobs: - name: Install JDK if: env.turbo_cache_hit != 1 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 with: distribution: 'zulu' java-version: '17' @@ -117,7 +117,7 @@ jobs: - name: Cache Gradle if: env.turbo_cache_hit != 1 - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.gradle/wrapper @@ -128,7 +128,7 @@ jobs: - name: Build example for Android env: - JAVA_OPTS: "-XX:MaxHeapSize=6g" + GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g" run: | yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" @@ -143,7 +143,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup uses: ./.github/actions/setup @@ -154,7 +154,7 @@ jobs: <% } -%> - name: Cache turborepo for iOS - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ${{ env.TURBO_CACHE_DIR }} key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('yarn.lock') }} @@ -171,7 +171,7 @@ jobs: - name: Use appropriate Xcode version if: env.turbo_cache_hit != 1 - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 + uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 with: xcode-version: ${{ env.XCODE_VERSION }} @@ -182,11 +182,10 @@ jobs: yarn example expo prebuild --platform ios <% } else { -%> - name: Install cocoapods - if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true' + if: env.turbo_cache_hit != 1 run: | cd example bundle install - bundle exec pod repo update --verbose bundle exec pod install --project-directory=ios <% } -%> @@ -201,7 +200,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup uses: ./.github/actions/setup diff --git a/packages/create-react-native-library/templates/common/$.gitignore b/packages/create-react-native-library/templates/common/$.gitignore index 67f32126d..2bae16034 100644 --- a/packages/create-react-native-library/templates/common/$.gitignore +++ b/packages/create-react-native-library/templates/common/$.gitignore @@ -7,7 +7,6 @@ # VSCode .vscode/ -jsconfig.json # Xcode # @@ -55,12 +54,6 @@ npm-debug.log yarn-debug.log yarn-error.log -# BUCK -buck-out/ -\.buckd/ -android/app/libs -android/keystores/debug.keystore - # Yarn .yarn/* !.yarn/patches @@ -69,9 +62,6 @@ android/keystores/debug.keystore !.yarn/sdks !.yarn/versions -# Expo -.expo/ - # Turborepo .turbo/ diff --git a/packages/create-react-native-library/templates/common/$package.json b/packages/create-react-native-library/templates/common/$package.json index 0657b7bd9..159b3d179 100644 --- a/packages/create-react-native-library/templates/common/$package.json +++ b/packages/create-react-native-library/templates/common/$package.json @@ -1,7 +1,7 @@ { "name": "<%- project.slug -%>", "version": "0.1.0", - "description": "<%- project.description %>", + "description": <%- JSON.stringify(project.description) %>, "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", "exports": { @@ -10,6 +10,9 @@ "types": "./lib/typescript/src/index.d.ts", "default": "./lib/module/index.js" }, +<% if (project.viewConfig === 'nitro-view') { -%> + "./nitrogen/generated/shared/json/*": "./nitrogen/generated/shared/json/*", +<% } -%> "./package.json": "./package.json" }, "files": [ @@ -36,9 +39,7 @@ "!**/.*" ], "scripts": { -<% if (example !== 'none') { -%> "example": "yarn workspace <%- project.slug -%>-example", -<% } -%> <% if (example !== 'expo') { -%> "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", <% } else { -%> @@ -57,14 +58,14 @@ ], "repository": { "type": "git", - "url": "git+<%- repo -%>.git" + "url": <%- JSON.stringify(`git+${repo}.git`) %> }, - "author": "<%- author.name -%> <<%- author.email -%>> (<%- author.url -%>)", + "author": <%- JSON.stringify(`${author.name} <${author.email}> (${author.url})`) %>, "license": "MIT", "bugs": { - "url": "<%- repo -%>/issues" + "url": <%- JSON.stringify(`${repo}/issues`) %> }, - "homepage": "<%- repo -%>#readme", + "homepage": <%- JSON.stringify(`${repo}#readme`) %>, "publishConfig": { "registry": "https://registry.npmjs.org/" }, @@ -92,11 +93,9 @@ "react-native": "*" <% } -%> }, -<% if (example !== 'none') { -%> "workspaces": [ "example" ], -<% } -%> "packageManager": "yarn@4.18.1", "react-native-builder-bob": { "source": "src", diff --git a/packages/create-react-native-library/templates/common/CONTRIBUTING.md b/packages/create-react-native-library/templates/common/CONTRIBUTING.md index 78cdab2b4..0c2d50746 100644 --- a/packages/create-react-native-library/templates/common/CONTRIBUTING.md +++ b/packages/create-react-native-library/templates/common/CONTRIBUTING.md @@ -68,14 +68,6 @@ To run the example app on iOS: yarn example ios ``` -To confirm that the app is running with the new architecture, you can check the Metro logs for a message like this: - -```sh -Running "<%- project.name -%>Example" with {"fabric":true,"initialProps":{"concurrentRoot":true},"rootTag":1} -``` - -Note the `"fabric":true` and `"concurrentRoot":true` properties. - <% if (example === 'expo' || tools.includes('vite')) { -%> To run the example app on Web: @@ -148,19 +140,19 @@ The `package.json` file contains various scripts for common tasks: - `yarn`: setup project by installing dependencies. - `yarn typecheck`: type-check files with TypeScript. - <% if (tools.includes('eslint')) { -%> + <%_ if (tools.includes('eslint')) { -%> - `yarn lint`: lint files with [ESLint](https://eslint.org/). - <% } -%> - <% if (tools.includes('jest')) { -%> + <%_ } -%> + <%_ if (tools.includes('jest')) { -%> - `yarn test`: run unit tests with [Jest](https://jestjs.io/). - <% } -%> + <%_ } -%> - `yarn example start`: start the Metro server for the example app. - `yarn example android`: run the example app on Android. - `yarn example ios`: run the example app on iOS. - <% if (example === 'expo' || tools.includes('vite')) { -%> + <%_ if (example === 'expo' || tools.includes('vite')) { -%> - `yarn example web`: run the example app on Web. - `yarn example build:web`: build the example app for Web. - <% } -%> + <%_ } -%> ### Sending a pull request diff --git a/packages/create-react-native-library/templates/common/README.md b/packages/create-react-native-library/templates/common/README.md index 4561a5be7..4e4c6622a 100644 --- a/packages/create-react-native-library/templates/common/README.md +++ b/packages/create-react-native-library/templates/common/README.md @@ -8,9 +8,9 @@ ```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 { -%> @@ -29,7 +29,7 @@ import { <%- project.name -%>View } from "<%- project.slug -%>"; // ... -<<%- project.name -%>View color="tomato" /> +<<%- project.name -%>View color="#32a852" /> ``` <% } else { -%> diff --git a/packages/create-react-native-library/templates/common/babel.config.js b/packages/create-react-native-library/templates/common/babel.config.mjs similarity index 100% rename from packages/create-react-native-library/templates/common/babel.config.js rename to packages/create-react-native-library/templates/common/babel.config.mjs diff --git a/packages/create-react-native-library/templates/cpp-library/android/CMakeLists.txt b/packages/create-react-native-library/templates/cpp-library/android/CMakeLists.txt index 1432d65c6..e515457e8 100644 --- a/packages/create-react-native-library/templates/cpp-library/android/CMakeLists.txt +++ b/packages/create-react-native-library/templates/cpp-library/android/CMakeLists.txt @@ -1,8 +1,6 @@ -cmake_minimum_required(VERSION 3.4.1) +cmake_minimum_required(VERSION 3.13) project(<%- project.name -%>) -set (CMAKE_VERBOSE_MAKEFILE ON) - add_library( <%- project.identifier -%> STATIC diff --git a/packages/create-react-native-library/templates/cpp-library/{%- project.name %}.podspec b/packages/create-react-native-library/templates/cpp-library/{%- project.name %}.podspec index e0e23482d..482f73d38 100644 --- a/packages/create-react-native-library/templates/cpp-library/{%- project.name %}.podspec +++ b/packages/create-react-native-library/templates/cpp-library/{%- project.name %}.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.authors = package["author"] s.platforms = { :ios => min_ios_version_supported } - s.source = { :git => "<%- repo -%>.git", :tag => "#{s.version}" } + s.source = { :git => "<%- repo -%>.git", :tag => "v#{s.version}" } s.source_files = "ios/**/*.{h,m,mm}", "cpp/**/*.{hpp,cpp,c,h}" s.private_header_files = "ios/**/*.h" diff --git a/packages/create-react-native-library/templates/js-view/src/{%- project.name %}View.tsx b/packages/create-react-native-library/templates/js-view/src/{%- project.name %}View.tsx index f5b2c76f3..0f0cd9a45 100644 --- a/packages/create-react-native-library/templates/js-view/src/{%- project.name %}View.tsx +++ b/packages/create-react-native-library/templates/js-view/src/{%- project.name %}View.tsx @@ -1,8 +1,16 @@ +<% if (project.viewConfig === 'nitro-view') { -%> +import { View, type ViewProps } from 'react-native'; + +type Props = ViewProps & { + color: string; +}; +<% } else { -%> import { View, type ColorValue, type ViewProps } from 'react-native'; type Props = ViewProps & { color?: ColorValue; }; +<% } -%> export function <%- project.name -%>View({ color, style, ...rest }: Props) { return ; diff --git a/packages/create-react-native-library/templates/kotlin-library-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt b/packages/create-react-native-library/templates/kotlin-library-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt index bdac55d7d..139b48efb 100644 --- a/packages/create-react-native-library/templates/kotlin-library-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt +++ b/packages/create-react-native-library/templates/kotlin-library-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt @@ -5,7 +5,6 @@ import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.module.model.ReactModuleInfo import com.facebook.react.module.model.ReactModuleInfoProvider -import java.util.HashMap class <%- project.name -%>Package : BaseReactPackage() { override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { diff --git a/packages/create-react-native-library/templates/kotlin-view-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}View.kt b/packages/create-react-native-library/templates/kotlin-view-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}View.kt index 6f7bfc565..595c36ee7 100644 --- a/packages/create-react-native-library/templates/kotlin-view-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}View.kt +++ b/packages/create-react-native-library/templates/kotlin-view-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}View.kt @@ -1,15 +1,6 @@ package com.<%- project.package %> import android.content.Context -import android.util.AttributeSet import android.view.View -class <%- project.name -%>View : View { - constructor(context: Context?) : super(context) - constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) - constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) -} +class <%- project.name -%>View(context: Context) : View(context) diff --git a/packages/create-react-native-library/templates/kotlin-view-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt b/packages/create-react-native-library/templates/kotlin-view-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}ViewPackage.kt similarity index 100% rename from packages/create-react-native-library/templates/kotlin-view-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt rename to packages/create-react-native-library/templates/kotlin-view-new/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}ViewPackage.kt 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 837ee04d3..ce3aed6a2 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 @@ -1,28 +1,14 @@ -buildscript { - ext.<%- project.name -%> = [ - kotlinVersion: "2.0.21", - minSdkVersion: 24, - compileSdkVersion: 36 - ] - - ext.getExtOrDefault = { prop -> - if (rootProject.ext.has(prop)) { - return rootProject.ext.get(prop) - } - - return <%- project.name -%>[prop] - } - - repositories { - google() - mavenCentral() +ext.<%- project.name -%> = [ + minSdkVersion: 24, + compileSdkVersion: 36 +] + +ext.getExtOrDefault = { prop -> + if (rootProject.ext.has(prop)) { + return rootProject.ext.get(prop) } - dependencies { - classpath "com.android.tools.build:gradle:8.7.2" - // noinspection DifferentKotlinGradleVersion - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" - } + return <%- project.name -%>[prop] } <% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> @@ -104,13 +90,7 @@ android { "**/libfolly_runtime.so", "**/libglog.so", "**/libhermes.so", - "**/libhermes-executor-debug.so", - "**/libhermes_executor.so", - "**/libreactnative.so", - "**/libreactnativejni.so", - "**/libturbomodulejsijni.so", - "**/libreact_nativemodule_core.so", - "**/libjscexecutor.so" + "**/libreactnative.so" ] } } @@ -119,11 +99,6 @@ android { prefab true } <% } -%> - - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } } dependencies { 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 1c6e8cee9..c7cfb79c3 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 @@ -11,13 +11,11 @@ Pod::Spec.new do |s| s.authors = package["author"] s.platforms = { :ios => min_ios_version_supported } - s.source = { :git => "<%- repo -%>.git", :tag => "#{s.version}" } + s.source = { :git => "<%- repo -%>.git", :tag => "v#{s.version}" } <% if (project.moduleConfig !== "nitro-modules" && project.viewConfig !== "nitro-view") { -%> s.source_files = "ios/**/*.{h,m,mm,swift,cpp}" -<% if (!project.swift) { -%> s.private_header_files = "ios/**/*.h" -<% } -%> <% } else { -%> s.source_files = [ "ios/**/*.{swift}", diff --git a/packages/create-react-native-library/templates/nitro-common/android/CMakeLists.txt b/packages/create-react-native-library/templates/nitro-common/android/CMakeLists.txt index 1fa9ed39d..3cf2832fd 100644 --- a/packages/create-react-native-library/templates/nitro-common/android/CMakeLists.txt +++ b/packages/create-react-native-library/templates/nitro-common/android/CMakeLists.txt @@ -1,8 +1,7 @@ +cmake_minimum_required(VERSION 3.13) 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 diff --git a/packages/create-react-native-library/templates/nitro-module/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}Package.kt b/packages/create-react-native-library/templates/nitro-module/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}Package.kt index b2f34145b..49f7b9e39 100644 --- a/packages/create-react-native-library/templates/nitro-module/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}Package.kt +++ b/packages/create-react-native-library/templates/nitro-module/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}Package.kt @@ -6,17 +6,17 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.module.model.ReactModuleInfoProvider class <%- project.name -%>Package : BaseReactPackage() { - override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { - return null - } + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return null + } - override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { - return ReactModuleInfoProvider { HashMap() } - } + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { emptyMap() } + } - companion object { - init { - System.loadLibrary("<%- project.package_cpp -%>") - } + companion object { + init { + System.loadLibrary("<%- project.package_cpp -%>") } + } } diff --git a/packages/create-react-native-library/templates/nitro-module/ios/{%- project.name %}.swift b/packages/create-react-native-library/templates/nitro-module/ios/{%- project.name %}.swift index 4515e2ed5..fc99b5c34 100644 --- a/packages/create-react-native-library/templates/nitro-module/ios/{%- project.name %}.swift +++ b/packages/create-react-native-library/templates/nitro-module/ios/{%- project.name %}.swift @@ -1,5 +1,5 @@ class <%- project.name -%>: Hybrid<%- project.name -%>Spec { - public func multiply(a: Double, b: Double) throws -> Double { - return a * b - } + public func multiply(a: Double, b: Double) throws -> Double { + return a * b + } } diff --git a/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}Package.kt b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}Package.kt index 998b2c8f4..a1c1497ec 100644 --- a/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}Package.kt +++ b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}Package.kt @@ -9,21 +9,21 @@ import com.facebook.react.uimanager.ViewManager import com.margelo.nitro.<%- project.package %>.views.Hybrid<%- project.name -%>Manager class <%- project.name -%>Package : BaseReactPackage() { - override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { - return null - } + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return null + } - override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { - return ReactModuleInfoProvider { HashMap() } - } + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { emptyMap() } + } - override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return listOf(Hybrid<%- project.name -%>Manager()) - } + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return listOf(Hybrid<%- project.name -%>Manager()) + } - companion object { - init { - System.loadLibrary("<%- project.package_cpp -%>") - } + 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 index 0e4c8ef3c..56e7fc1e4 100644 --- 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 @@ -11,13 +11,8 @@ class Hybrid<%- project.name -%> : Hybrid<%- project.name -%>Spec { } func hexStringToUIColor(hexColor: String) -> UIColor { - let stringScanner = Scanner(string: hexColor) - - if(hexColor.hasPrefix("#")) { - stringScanner.scanLocation = 1 - } - var color: UInt32 = 0 - stringScanner.scanHexInt32(&color) + let hex = hexColor.hasPrefix("#") ? String(hexColor.dropFirst()) : hexColor + let color = UInt32(hex, radix: 16) ?? 0 let r = CGFloat(Int(color >> 16) & 0x000000FF) let g = CGFloat(Int(color >> 8) & 0x000000FF) diff --git a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}View.native.tsx b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}View.native.tsx index 2f1c95268..883a17fb7 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}View.native.tsx +++ b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}View.native.tsx @@ -1,10 +1,11 @@ import { getHostComponent } from 'react-native-nitro-modules'; -const <%- project.name %>Config = require('../nitrogen/generated/shared/json/<%- project.name %>Config.json'); import type { <%- project.name %>Methods, <%- project.name %>Props, } from './<%- project.name %>.nitro'; +const <%- project.name %>Config = require('<%- project.slug %>/nitrogen/generated/shared/json/<%- project.name %>Config.json'); + export const <%- project.name %>View = getHostComponent< <%- project.name %>Props, <%- project.name %>Methods diff --git a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}View.tsx b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}View.tsx index 77709ebb1..e4b9a589b 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}View.tsx +++ b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}View.tsx @@ -1,7 +1,7 @@ -import type { ColorValue, ViewProps } from 'react-native'; +import type { ViewProps } from 'react-native'; type Props = ViewProps & { - color?: ColorValue; + color: string; }; export function <%- project.name -%>View(_props: Props): never { diff --git a/packages/create-react-native-library/templates/objc-library/ios/{%- project.name %}.mm b/packages/create-react-native-library/templates/objc-library/ios/{%- project.name %}.mm index 5a356782f..3b3451c7c 100644 --- a/packages/create-react-native-library/templates/objc-library/ios/{%- project.name %}.mm +++ b/packages/create-react-native-library/templates/objc-library/ios/{%- project.name %}.mm @@ -3,15 +3,15 @@ @implementation <%- project.name -%> - (NSNumber *)multiply:(double)a b:(double)b { - NSNumber *result = @(a * b); + NSNumber *result = @(a * b); - return result; + return result; } - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_sharedSpecJSI>(params); + return std::make_sharedSpecJSI>(params); } + (NSString *)moduleName diff --git a/packages/create-react-native-library/templates/objc-view-new/ios/{%- project.name %}View.h b/packages/create-react-native-library/templates/objc-view-new/ios/{%- project.name %}View.h index 74ab340f4..bcf872d41 100644 --- a/packages/create-react-native-library/templates/objc-view-new/ios/{%- project.name %}View.h +++ b/packages/create-react-native-library/templates/objc-view-new/ios/{%- project.name %}View.h @@ -1,8 +1,4 @@ #import -#import - -#ifndef <%- project.name -%>ViewNativeComponent_h -#define <%- project.name -%>ViewNativeComponent_h NS_ASSUME_NONNULL_BEGIN @@ -10,5 +6,3 @@ NS_ASSUME_NONNULL_BEGIN @end NS_ASSUME_NONNULL_END - -#endif /* <%- project.name -%>ViewNativeComponent_h */ diff --git a/packages/create-react-native-library/templates/objc-view-new/ios/{%- project.name %}View.mm b/packages/create-react-native-library/templates/objc-view-new/ios/{%- project.name %}View.mm index c9b518d79..93fabf98e 100644 --- a/packages/create-react-native-library/templates/objc-view-new/ios/{%- project.name %}View.mm +++ b/packages/create-react-native-library/templates/objc-view-new/ios/{%- project.name %}View.mm @@ -6,17 +6,15 @@ #import ViewSpec/Props.h> #import ViewSpec/RCTComponentViewHelpers.h> -#import "RCTFabricComponentsPlugins.h" - using namespace facebook::react; @implementation <%- project.name -%>View { - UIView * _view; + UIView * _view; } + (ComponentDescriptorProvider)componentDescriptorProvider { - return concreteComponentDescriptorProvider<<%- project.name -%>ViewComponentDescriptor>(); + return concreteComponentDescriptorProvider<<%- project.name -%>ViewComponentDescriptor>(); } - (instancetype)initWithFrame:(CGRect)frame @@ -35,14 +33,14 @@ - (instancetype)initWithFrame:(CGRect)frame - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { - const auto &oldViewProps = *std::static_pointer_cast<<%- project.name -%>ViewProps const>(_props); - const auto &newViewProps = *std::static_pointer_cast<<%- project.name -%>ViewProps const>(props); + const auto &oldViewProps = *std::static_pointer_cast<<%- project.name -%>ViewProps const>(_props); + const auto &newViewProps = *std::static_pointer_cast<<%- project.name -%>ViewProps const>(props); - if (oldViewProps.color != newViewProps.color) { - [_view setBackgroundColor: RCTUIColorFromSharedColor(newViewProps.color)]; - } + if (oldViewProps.color != newViewProps.color) { + [_view setBackgroundColor: RCTUIColorFromSharedColor(newViewProps.color)]; + } - [super updateProps:props oldProps:oldProps]; + [super updateProps:props oldProps:oldProps]; } @end diff --git a/packages/create-react-native-library/templates/tools/lefthook/lefthook.yml b/packages/create-react-native-library/templates/tools/lefthook/lefthook.yml index 05b7d0597..dfb47a29f 100644 --- a/packages/create-react-native-library/templates/tools/lefthook/lefthook.yml +++ b/packages/create-react-native-library/templates/tools/lefthook/lefthook.yml @@ -7,7 +7,7 @@ pre-commit: run: npx eslint {staged_files} <% } %> types: - glob: "*.{js,ts, jsx, tsx}" + glob: "*.{js,ts,jsx,tsx}" run: npx tsc commit-msg: parallel: true diff --git a/packages/create-react-native-library/templates/tools/turborepo/turbo.json b/packages/create-react-native-library/templates/tools/turborepo/turbo.json index 8b2bf0876..504c3ee17 100644 --- a/packages/create-react-native-library/templates/tools/turborepo/turbo.json +++ b/packages/create-react-native-library/templates/tools/turborepo/turbo.json @@ -4,13 +4,15 @@ "globalEnv": ["NODE_ENV"], "tasks": { "build:android": { - "env": ["ANDROID_HOME", "ORG_GRADLE_PROJECT_newArchEnabled"], + "env": ["ANDROID_HOME"], "inputs": [ "package.json", + "react-native.config.js", + "nitro.json", "android", "!android/build", - "src/*.ts", - "src/*.tsx", + "cpp", + "src/**", "example/package.json", "example/android", "!example/android/.gradle", @@ -21,7 +23,6 @@ }, "build:ios": { "env": [ - "RCT_NEW_ARCH_ENABLED", "RCT_REMOVE_LEGACY_ARCH", "RCT_USE_RN_DEP", "RCT_USE_PREBUILT_RNCORE" @@ -29,9 +30,10 @@ "inputs": [ "package.json", "*.podspec", + "nitro.json", "ios", - "src/*.ts", - "src/*.tsx", + "cpp", + "src/**", "example/package.json", "example/ios", "!example/ios/build", diff --git a/packages/create-react-native-library/templates/tools/vite/~package.json b/packages/create-react-native-library/templates/tools/vite/~package.json deleted file mode 100644 index 8620ccee4..000000000 --- a/packages/create-react-native-library/templates/tools/vite/~package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "scripts": { - "web": "vite", - "build:web": "vite build" - }, - "devDependencies": { - "react-native-web": "~0.21.4" - } -} diff --git a/scripts/upgrade-template-deps.mts b/scripts/upgrade-template-deps.mts index ac72f97d4..8f4f35a0a 100755 --- a/scripts/upgrade-template-deps.mts +++ b/scripts/upgrade-template-deps.mts @@ -12,6 +12,12 @@ const ROOT_DIR = path.resolve(import.meta.dirname, '..'); const CRNL_DIR = path.join(ROOT_DIR, 'packages/create-react-native-library'); const TEMPLATES_DIR = path.join(CRNL_DIR, 'templates'); const BIN_PATH = path.join(CRNL_DIR, 'bin/create-react-native-library'); +const CONSTANTS_PATH = path.join(CRNL_DIR, 'src/constants.ts'); + +const FALLBACK_VERSIONS = { + FALLBACK_BOB_VERSION: 'react-native-builder-bob', + FALLBACK_NITRO_MODULES_VERSION: 'react-native-nitro-modules', +}; // These are tied to the React Native release and can't be upgraded independently const IGNORED_PACKAGES = [ @@ -112,7 +118,31 @@ function updateDeps(filePath: string, changes: Record) { } } +function updateFallbackVersions() { + const content = fs.readFileSync(CONSTANTS_PATH, 'utf8'); + + let updated = content; + + for (const [constant, name] of Object.entries(FALLBACK_VERSIONS)) { + const version = execFileSync('npm', ['view', name, 'dist-tags.latest'], { + encoding: 'utf8', + }).trim(); + + updated = updated.replace( + new RegExp(`(${constant} = ')[^']*'`), + `$1${version}'` + ); + } + + if (updated !== content) { + fs.writeFileSync(CONSTANTS_PATH, updated); + console.log(`Updated: ${path.relative(CRNL_DIR, CONSTANTS_PATH)}`); + } +} + function main() { + updateFallbackVersions(); + console.log('Building create-react-native-library...'); execSync('yarn workspace create-react-native-library prepare', {