diff --git a/.github/workflows/test-nitro-cli.yml b/.github/workflows/test-nitro-cli.yml index 1a8eb2e9..aed939ec 100644 --- a/.github/workflows/test-nitro-cli.yml +++ b/.github/workflows/test-nitro-cli.yml @@ -70,7 +70,7 @@ jobs: runs-on: macos-latest strategy: matrix: - pm: ['bun', 'yarn'] + pm: ['bun', 'yarn', 'pnpm'] package-type: ['module', 'view'] env: @@ -83,8 +83,14 @@ jobs: git config --global user.name "GitHub Actions Bot" git config --global user.email "actions@github.com" + - name: Setup pnpm + if: matrix.pm == 'pnpm' + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js - if: matrix.pm == 'yarn' + if: matrix.pm == 'yarn' || matrix.pm == 'pnpm' uses: actions/setup-node@v4 with: node-version: 22.x @@ -113,8 +119,14 @@ jobs: - name: Generate ${{ matrix.package-type }} with ${{ matrix.pm }} continue-on-error: false + if: matrix.pm != 'pnpm' run: ${{ matrix.pm }} create nitro-module test-${{ matrix.package-type }} --skip-install --ci + - name: Generate ${{ matrix.package-type }} with ${{ matrix.pm }} + continue-on-error: false + if: matrix.pm == 'pnpm' + run: create-nitro-module test-${{ matrix.package-type }} --skip-install --ci + - name: Verify generated package structure run: | PACKAGE_DIR="react-native-test-${{ matrix.package-type }}" @@ -182,7 +194,7 @@ jobs: runs-on: macos-latest strategy: matrix: - pm: ['bun', 'yarn'] + pm: ['bun', 'yarn', 'pnpm'] package-type: ['module', 'view'] mode: ['Debug', 'Release'] env: @@ -209,8 +221,14 @@ jobs: ruby-version: '3.2' bundler-cache: true + - name: Setup pnpm + if: matrix.pm == 'pnpm' + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js - if: matrix.pm == 'yarn' + if: matrix.pm == 'yarn' || matrix.pm == 'pnpm' uses: actions/setup-node@v4 with: node-version: 22.x @@ -272,7 +290,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - pm: ['bun', 'yarn'] + pm: ['bun', 'yarn', 'pnpm'] package-type: ['module', 'view'] mode: ['Debug', 'Release'] env: @@ -293,8 +311,14 @@ jobs: echo "Package structure:" find . -type f -name "*.json" -o -name "*.js" -o -name "*.ts" | head -20 + - name: Setup pnpm + if: matrix.pm == 'pnpm' + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js - if: matrix.pm == 'yarn' + if: matrix.pm == 'yarn' || matrix.pm == 'pnpm' uses: actions/setup-node@v4 with: node-version: 22.x diff --git a/README.md b/README.md index d65c5bbe..4a248f79 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ bun create nitro-module@latest my-nitro-module # Using yarn yarn create nitro-module@latest my-nitro-module +# Using pnpm +pnpm create nitro-module@latest my-nitro-module + # Using npx npx create-nitro-module@latest my-nitro-module ``` diff --git a/commitlint.config.cjs b/commitlint.config.cjs index 3e16e7f1..186619e5 100644 --- a/commitlint.config.cjs +++ b/commitlint.config.cjs @@ -1,3 +1,6 @@ module.exports = { extends: ['@commitlint/config-conventional'], + rules: { + 'footer-max-line-length': [0, 'always'], + }, } diff --git a/docs/docs/commands.md b/docs/docs/commands.md index 5eb9005f..853e7b27 100644 --- a/docs/docs/commands.md +++ b/docs/docs/commands.md @@ -45,6 +45,11 @@ Options: yarn create nitro-module@latest my-awesome-module ``` + + ```bash + pnpm create nitro-module@latest my-awesome-module + ``` + For additional support, please [open an issue](https://github.com/patrickkabwe/create-nitro-module/issues) on our GitHub repository. diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index a7102267..9adc3889 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -6,81 +6,78 @@ This section provides solutions to common issues you might encounter while using 1. **Pod Install Fails** - If you encounter issues during `pod install`, try the following steps: + If you encounter issues during `pod install`, try the following steps: - ```bash - cd yourpackage/ios - pod deintegrate - pod install - ``` + ```bash + cd yourpackage/ios + pod deintegrate + pod install + ``` 2. **Missing Header Files** - If Xcode reports missing header files, follow these steps: + If Xcode reports missing header files, follow these steps: - - Clean the build folder in Xcode (`Product` -> `Clean Build Folder`). - - Ensure all native dependencies are properly linked. - - Rebuild the project. + - Clean the build folder in Xcode (`Product` -> `Clean Build Folder`). + - Ensure all native dependencies are properly linked. + - Rebuild the project. ### Android Build Issues 1. **Gradle Sync Failed** - If Gradle sync fails, try cleaning and rebuilding the project: + If Gradle sync fails, try cleaning and rebuilding the project: - ```bash - cd yourpackage/android - ./gradlew clean - ./gradlew build - ``` + ```bash + cd yourpackage/android + ./gradlew clean + ./gradlew build + ``` 2. **Missing Dependencies** - If you encounter missing dependencies, check the following: + If you encounter missing dependencies, check the following: - - Ensure `build.gradle` contains the correct dependencies. - - Sync the project with Gradle files. - - Invalidate caches and restart Android Studio. + - Ensure `build.gradle` contains the correct dependencies. + - Sync the project with Gradle files. + - Invalidate caches and restart Android Studio. ### General Issues 1. **Error Invalid Version: latest** - If you encounter an invalid version error, this is due to an issue with the CLI: See issue: [Invalid Version: latest](https://github.com/react-native-community/cli/issues/2486) + If you encounter an invalid version error, this is due to an issue with the CLI: See issue: [Invalid Version: latest](https://github.com/react-native-community/cli/issues/2486) - ```bash - ✖ Failed to create nitro module: Command failed: bunx -y @react-native-community/cli@latest init TestToSpeechExample --directory path/react-native-module/example --skip-install - Resolving dependencies - Resolved, downloaded and extracted [2] - Saved lockfile - error Invalid Version: latest. - ``` + ```bash + ✖ Failed to create nitro module: Command failed: bunx -y @react-native-community/cli@latest init TestToSpeechExample --directory path/react-native-module/example --skip-install + Resolving dependencies + Resolved, downloaded and extracted [2] + Saved lockfile + error Invalid Version: latest. + ``` - To resolve this issue, use the following command: keep trying until it works. + To resolve this issue, use the following command: keep trying until it works. -2. **Module Not Found** +2. **Command Not Found** - If a module is not found, ensure it is properly installed and linked: + If a CLI command is not recognized, ensure the CLI is installed globally: - ```bash - npm install - npx react-native link - ``` + ```bash + npm install -g create-nitro-module@latest + # or + pnpm add -g create-nitro-module@latest + # or + yarn global add create-nitro-module@latest + # or + bun i -g create-nitro-module@latest + ``` -3. **Command Not Found** +3. **Permission Denied** - If a CLI command is not recognized, ensure the CLI is installed globally: + If you encounter permission issues, try running the command with `sudo`: - ```bash - npm install -g create-nitro-module - ``` - -4. **Permission Denied** - - If you encounter permission issues, try running the command with `sudo`: - - ```bash - sudo - ``` + ```bash + sudo + ``` For additional support, please [open an issue](https://github.com/patrickkabwe/create-nitro-module/issues) on our GitHub repository. diff --git a/docs/docs/usage/create-a-nitro-module.md b/docs/docs/usage/create-a-nitro-module.md index 147e2b17..3b266845 100644 --- a/docs/docs/usage/create-a-nitro-module.md +++ b/docs/docs/usage/create-a-nitro-module.md @@ -29,6 +29,11 @@ To create a Nitro Module along with an example app, use the following command. T yarn create nitro-module@latest my-awesome-module ``` + + ```bash + pnpm create nitro-module@latest my-awesome-module + ``` + ## Without example app @@ -51,6 +56,11 @@ If you prefer to create a Nitro Module without an example app, use the following yarn create nitro-module@latest my-awesome-module --skip-example ``` + + ```bash + pnpm create nitro-module@latest my-awesome-module --skip-example + ``` + The `--skip-example` flag indicates that the example app should be skipped. @@ -75,6 +85,11 @@ If you prefer to create a Nitro Module within a specific directory, use the foll yarn create nitro-module@latest my-awesome-module --module-dir packages ``` + + ```bash + pnpm create nitro-module@latest my-awesome-module --module-dir packages + ``` + This command will create a Nitro Module within the `packages` directory as shown in the example above. diff --git a/docs/docs/usage/installation.md b/docs/docs/usage/installation.md index 3f7e0c1c..579c2a1d 100644 --- a/docs/docs/usage/installation.md +++ b/docs/docs/usage/installation.md @@ -23,6 +23,12 @@ bun install -g create-nitro-module yarn global add create-nitro-module ``` +### Using PNPM + +```bash +pnpm add -g create-nitro-module +``` + ### Using NPM ```bash diff --git a/package.json b/package.json index 641ee74f..48f05248 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,7 @@ ], "license": "MIT", "bin": { - "create-nitro-module": "./lib/cli/index.js", - "nitro-module": "./lib/cli/index.js" + "create-nitro-module": "./lib/cli/index.js" }, "repository": { "type": "git", diff --git a/src/cli/create.ts b/src/cli/create.ts index 0c83926b..bf9e5a1a 100644 --- a/src/cli/create.ts +++ b/src/cli/create.ts @@ -144,7 +144,7 @@ const getUserAnswers = async ( platforms: [SupportedPlatform.IOS, SupportedPlatform.ANDROID], packageType: Nitro.Module, langs: [SupportedLang.SWIFT, SupportedLang.KOTLIN], - pm: usedPm || 'bun', + pm: usedPm || 'pnpm', } } @@ -250,6 +250,10 @@ const getUserAnswers = async ( label: 'npm', value: 'npm', }, + { + label: 'pnpm', + value: 'pnpm', + }, ], }) }, diff --git a/src/generate-nitro-package.ts b/src/generate-nitro-package.ts index e53b9838..72977879 100644 --- a/src/generate-nitro-package.ts +++ b/src/generate-nitro-package.ts @@ -142,6 +142,8 @@ export class NitroModuleFactory { let script = `${this.config.pm} --cwd example pod` if (this.config.pm === 'npm') { script = `${this.config.pm} --prefix example run pod` + } else if (this.config.pm === 'pnpm') { + script = `pnpm --filter ./example pod` } return script } @@ -187,6 +189,23 @@ export class NitroModuleFactory { cwd: this.config.cwd, }) await execAsync('corepack disable', { cwd: this.config.cwd }) + } else if (this.config.pm === 'pnpm') { + const workspaceDirs = ['example'] + const yamlContent = `packages:\n${workspaceDirs.map(d => ` - ${d}`).join('\n')}\n` + + const WORKSPACE_FILENAME = 'pnpm-workspace.yaml' + await writeFile( + path.join(this.config.cwd, WORKSPACE_FILENAME), + yamlContent, + { encoding: 'utf8' } + ) + const NPMRC_FILENAME = '.npmrc' + await writeFile( + path.join(this.config.cwd, NPMRC_FILENAME), + 'node-linker=hoisted', + { encoding: 'utf8' } + ) + delete newWorkspacePackageJsonFile.workspaces } if (skipExample) { @@ -206,9 +225,9 @@ export class NitroModuleFactory { const replacements = { [JS_PACKAGE_NAME_TAG]: this.config.finalPackageName, $$command$$: - this.config.pm === 'bun' || this.config.pm === 'yarn' - ? `${this.config.pm} add` - : 'npm install', + this.config.pm === 'npm' + ? 'npm install' + : `${this.config.pm} add`, [DESCRIPTION_TAG]: this.config.description, [AUTHOR_TAG]: getGitUserInfo().name, [LICENSE_YEAR_TAG]: new Date().getFullYear().toString(), @@ -257,7 +276,12 @@ export class NitroModuleFactory { } private async createExampleApp() { - const packageManager = this.config.pm === 'bun' ? 'bunx' : 'npx -y' + const packageManager = + this.config.pm === 'bun' + ? 'bunx' + : this.config.pm === 'pnpm' + ? 'pnpx' + : 'npx -y' const reactNativeVersion = templatePackageJson.devDependencies['react-native'] @@ -346,9 +370,9 @@ export class NitroModuleFactory { replacements, }) - await writeFile(reactNativeConfigPath, reactNativeConfig, { - encoding: 'utf8', - }) + // await writeFile(reactNativeConfigPath, reactNativeConfig, { + // encoding: 'utf8', + // }) // Setup metro.config.js const metroConfigPath = path.join( this.config.cwd, @@ -356,7 +380,7 @@ export class NitroModuleFactory { 'metro.config.js' ) - await writeFile(metroConfigPath, metroConfig, { encoding: 'utf8' }) + // await writeFile(metroConfigPath, metroConfig, { encoding: 'utf8' }) // Setup babel.config.js const babelConfigPath = path.join( @@ -365,7 +389,7 @@ export class NitroModuleFactory { 'babel.config.js' ) - await writeFile(babelConfigPath, babelConfig, { encoding: 'utf8' }) + // await writeFile(babelConfigPath, babelConfig, { encoding: 'utf8' }) // Setup tsconfig.json const tsConfigPath = path.join( @@ -374,11 +398,11 @@ export class NitroModuleFactory { 'tsconfig.json' ) - await writeFile( - tsConfigPath, - exampleTsConfig(this.config.finalPackageName), - { encoding: 'utf8' } - ) + // await writeFile( + // tsConfigPath, + // exampleTsConfig(this.config.finalPackageName), + // { encoding: 'utf8' } + // ) const androidSettingsGradlePath = path.join( this.config.cwd, @@ -416,12 +440,35 @@ export class NitroModuleFactory { 'hermesCommand = "$rootDir/../../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"', } - const toWrite = await replacePlaceholder({ + const androidBuildGradleData = await replacePlaceholder({ data: androidBuildGradle, replacements: gradleReplacements, }) - await writeFile(androidBuildGradlePath, toWrite, { encoding: 'utf8' }) + // await writeFile(androidBuildGradlePath, androidBuildGradleData, { encoding: 'utf8' }) + + const filesToWrite = [ + { saveTo: reactNativeConfigPath, data: reactNativeConfig }, + { saveTo: metroConfigPath, data: metroConfig }, + { saveTo: babelConfigPath, data: babelConfig }, + { + saveTo: tsConfigPath, + data: exampleTsConfig(this.config.finalPackageName), + }, + { + saveTo: androidSettingsGradlePath, + data: androidSettingsGradleCode( + toPascalCase(this.config.packageName) + ), + }, + { saveTo: androidBuildGradlePath, data: androidBuildGradleData }, + ] + await Promise.all( + filesToWrite.map(async item => { + const { saveTo, data } = item + await writeFile(saveTo, data, { encoding: 'utf8' }) + }) + ) for (const folder of foldersToRemoveFromExampleApp) { await rm(path.join(this.config.cwd, 'example', folder), { diff --git a/src/types.ts b/src/types.ts index 3212fec1..b9fec1cb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,5 @@ import * as p from '@clack/prompts' +import { detectPackageManager } from './utils' export interface UserAnswers { packageName: string @@ -33,7 +34,10 @@ export type CreateModuleOptions = { skipInstall?: boolean } -export type PackageManager = 'bun' | 'yarn' | 'npm' +export type PackageManager = Exclude< + ReturnType, + undefined +> export enum Nitro { Module = 'module', diff --git a/src/utils.ts b/src/utils.ts index bbd5f4a0..d9115b8c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -209,6 +209,7 @@ export const detectPackageManager = () => { if (userAgent.startsWith('npm')) return 'npm' if (userAgent.startsWith('yarn')) return 'yarn' if (userAgent.startsWith('bun')) return 'bun' + if (userAgent.startsWith('pnpm')) return 'pnpm' return 'bun' }