diff --git a/packages/create-react-native-library/src/index.ts b/packages/create-react-native-library/src/index.ts index 1dce51722..014634ec6 100644 --- a/packages/create-react-native-library/src/index.ts +++ b/packages/create-react-native-library/src/index.ts @@ -6,7 +6,12 @@ import yargs from 'yargs'; import { addCodegenBuildScript } from './exampleApp/addCodegenBuildScript'; import { alignDependencyVersionsWithExampleApp } from './exampleApp/dependencies'; import generateExampleApp from './exampleApp/generateExampleApp'; -import { printErrorHelp, printNextSteps, printUsedRNVersion } from './inform'; +import { + printErrorHelp, + printLocalLibNextSteps, + printNonLocalLibNextSteps, + printUsedRNVersion, +} from './inform'; import { acceptedArgs, createMetadata, @@ -19,6 +24,12 @@ import { assertNpxExists, assertUserInput } from './utils/assert'; import { createInitialGitCommit } from './utils/initialCommit'; import { prompt } from './utils/prompt'; import { resolveNpmPackageVersion } from './utils/resolveNpmPackageVersion'; +import { + addNitroDependencyToLocalLibrary, + linkLocalLibrary, + promptLocalLibrary, +} from './utils/local'; +import { determinePackageManager } from './utils/packageManager'; const FALLBACK_BOB_VERSION = '0.40.5'; const FALLBACK_NITRO_MODULES_VERSION = '0.22.1'; @@ -143,43 +154,44 @@ async function create(_argv: yargs.Arguments) { spaces: 2, }); + const printSuccessMessage = () => + spinner.succeed( + `Project created successfully at ${kleur.yellow( + path.relative(process.cwd(), folder) + )}!\n` + ); + if (!local) { await createInitialGitCommit(folder); - } - - spinner.succeed( - `Project created successfully at ${kleur.yellow( - path.relative(process.cwd(), folder) - )}!\n` - ); - await printNextSteps(local, folder, config); -} + printSuccessMessage(); -async function promptLocalLibrary(argv: Args) { - let local = false; + printNonLocalLibNextSteps(config); + return; + } - if (typeof argv.local === 'boolean') { - local = argv.local; - } else { - const hasPackageJson = await fs.pathExists( - path.join(process.cwd(), 'package.json') - ); + const packageManager = await determinePackageManager(); - if (hasPackageJson) { - // If we're under a project with package.json, ask the user if they want to create a local library - const answers = await prompt({ - type: 'confirm', - name: 'local', - message: `Looks like you're under a project folder. Do you want to create a local library?`, - initial: true, - }); - - local = answers.local; - } + let addedNitro = false; + if (config.project.moduleConfig === 'nitro-modules') { + addedNitro = await addNitroDependencyToLocalLibrary(config); } - return local; + const linkedLocalLibrary = await linkLocalLibrary( + config, + folder, + packageManager + ); + + printSuccessMessage(); + + printLocalLibNextSteps({ + config, + packageManager, + linkedLocalLibrary, + addedNitro, + folder, + }); } async function promptPath(argv: Args, local: boolean) { diff --git a/packages/create-react-native-library/src/inform.ts b/packages/create-react-native-library/src/inform.ts index 8ded66eac..47a8a99fd 100644 --- a/packages/create-react-native-library/src/inform.ts +++ b/packages/create-react-native-library/src/inform.ts @@ -1,60 +1,74 @@ import path from 'path'; -import fs from 'fs-extra'; import dedent from 'dedent'; import type { TemplateConfiguration } from './template'; import kleur from 'kleur'; -export async function printNextSteps( - local: boolean, - folder: string, - config: TemplateConfiguration -) { - if (local) { - let linked; - - const packageManager = (await fs.pathExists( - path.join(process.cwd(), 'yarn.lock') - )) - ? 'yarn' - : 'npm'; - - const packageJsonPath = path.join(process.cwd(), 'package.json'); - - if (await fs.pathExists(packageJsonPath)) { - const packageJson = await fs.readJSON(packageJsonPath); - const isReactNativeProject = Boolean( - packageJson.dependencies?.['react-native'] - ); +export function printNonLocalLibNextSteps(config: TemplateConfiguration) { + const platforms = { + ios: { name: 'iOS', color: 'cyan' }, + android: { name: 'Android', color: 'green' }, + ...(config.example === 'expo' + ? ({ web: { name: 'Web', color: 'blue' } } as const) + : null), + } as const; + + console.log( + dedent(` + ${kleur.magenta( + `${kleur.bold('Get started')} with the project` + )}${kleur.gray(':')} - if (isReactNativeProject) { - packageJson.dependencies = packageJson.dependencies || {}; - packageJson.dependencies[config.project.slug] = - packageManager === 'yarn' - ? `link:./${path.relative(process.cwd(), folder)}` - : `file:./${path.relative(process.cwd(), folder)}`; + ${kleur.gray('$')} yarn + ${Object.entries(platforms) + .map( + ([script, { name, color }]) => ` + ${kleur[color](`Run the example app on ${kleur.bold(name)}`)}${kleur.gray( + ':' + )} - await fs.writeJSON(packageJsonPath, packageJson, { - spaces: 2, - }); + ${kleur.gray('$')} yarn example ${script}` + ) + .join('\n')} - linked = true; - } - } + ${kleur.yellow( + `See ${kleur.bold('CONTRIBUTING.md')} for more details. Good luck!` + )} + `) + ); +} - console.log( - dedent(` +export function printLocalLibNextSteps({ + folder, + config, + linkedLocalLibrary, + addedNitro, + packageManager, +}: { + folder: string; + config: TemplateConfiguration; + linkedLocalLibrary: boolean; + addedNitro: boolean; + packageManager: string; +}) { + console.log( + dedent(` ${kleur.magenta( `${kleur.bold('Get started')} with the project` )}${kleur.gray(':')} ${ - (linked + (linkedLocalLibrary ? `- Run ${kleur.blue( `${packageManager} install` )} to link the library\n` : `- Link the library at ${kleur.blue( path.relative(process.cwd(), folder) )} based on your project setup\n`) + + (config.project.moduleConfig === 'nitro-modules' && !addedNitro + ? `- Run ${kleur.blue( + `${packageManager} add react-native-nitro-modules` + )} to install nitro modules \n` + : '') + `- Run ${kleur.blue( 'pod install --project-directory=ios' )} to install dependencies with CocoaPods\n` + @@ -68,40 +82,7 @@ export async function printNextSteps( ${kleur.yellow(`Good luck!`)} `) - ); - } else { - const platforms = { - ios: { name: 'iOS', color: 'cyan' }, - android: { name: 'Android', color: 'green' }, - ...(config.example === 'expo' - ? ({ web: { name: 'Web', color: 'blue' } } as const) - : null), - } as const; - - console.log( - dedent(` - ${kleur.magenta( - `${kleur.bold('Get started')} with the project` - )}${kleur.gray(':')} - - ${kleur.gray('$')} yarn - ${Object.entries(platforms) - .map( - ([script, { name, color }]) => ` - ${kleur[color](`Run the example app on ${kleur.bold(name)}`)}${kleur.gray( - ':' - )} - - ${kleur.gray('$')} yarn example ${script}` - ) - .join('\n')} - - ${kleur.yellow( - `See ${kleur.bold('CONTRIBUTING.md')} for more details. Good luck!` - )} - `) - ); - } + ); } export function printErrorHelp(message: string, error: Error) { diff --git a/packages/create-react-native-library/src/template.ts b/packages/create-react-native-library/src/template.ts index faad7fcce..901ee136f 100644 --- a/packages/create-react-native-library/src/template.ts +++ b/packages/create-react-native-library/src/template.ts @@ -39,6 +39,7 @@ export type TemplateConfiguration = { email: string; url: string; }; + /** Git repo URL */ repo: string; example: ExampleApp; year: number; diff --git a/packages/create-react-native-library/src/utils/local.ts b/packages/create-react-native-library/src/utils/local.ts new file mode 100644 index 000000000..d785e5ede --- /dev/null +++ b/packages/create-react-native-library/src/utils/local.ts @@ -0,0 +1,99 @@ +import fs from 'fs-extra'; +import path from 'path'; +import { prompt } from './prompt'; +import type { TemplateConfiguration } from '../template'; +import type { Args } from '../input'; + +type PackageJson = { + dependencies?: Record; +}; + +export async function promptLocalLibrary(argv: Args): Promise { + if (typeof argv.local === 'boolean') { + return argv.local; + } + + const hasPackageJson = findAppPackageJsonPath() !== null; + if (!hasPackageJson) { + return false; + } + + // If we're under a project with package.json, ask the user if they want to create a local library + const answers = await prompt({ + type: 'confirm', + name: 'local', + message: `Looks like you're under a project folder. Do you want to create a local library?`, + initial: true, + }); + + return answers.local; +} + +/** @returns `true` if successfull */ +export async function addNitroDependencyToLocalLibrary( + config: TemplateConfiguration +): Promise { + if (config.versions.nitroModules === undefined) { + return false; + } + + const appPackageJsonPath = await findAppPackageJsonPath(); + if (appPackageJsonPath === null) { + return false; + } + + const appPackageJson: PackageJson = await fs.readJson(appPackageJsonPath); + const dependencies = appPackageJson['dependencies'] ?? {}; + + dependencies['react-native-nitro-modules'] = config.versions.nitroModules; + + appPackageJson['dependencies'] = dependencies; + await fs.writeJson(appPackageJsonPath, appPackageJson, { + spaces: 2, + }); + + return true; +} + +/** @returns `true` if successfull */ +export async function linkLocalLibrary( + config: TemplateConfiguration, + folder: string, + packageManager: string +): Promise { + const appPackageJsonPath = await findAppPackageJsonPath(); + if (appPackageJsonPath === null) { + return false; + } + + const appPackageJson: PackageJson = await fs.readJson(appPackageJsonPath); + + const isReactNativeProject = Boolean( + appPackageJson.dependencies?.['react-native'] + ); + + if (!isReactNativeProject) { + return false; + } + + const dependencies = appPackageJson['dependencies'] ?? {}; + dependencies[config.project.slug] = + packageManager === 'yarn' + ? `link:./${path.relative(process.cwd(), folder)}` + : `file:./${path.relative(process.cwd(), folder)}`; + + await fs.writeJSON(appPackageJsonPath, appPackageJson, { + spaces: 2, + }); + + return true; +} + +async function findAppPackageJsonPath(): Promise { + const cwdPackageJson = path.join(process.cwd(), 'package.json'); + if (!(await fs.pathExists(cwdPackageJson))) { + return null; + } + + return cwdPackageJson; +} diff --git a/packages/create-react-native-library/src/utils/packageManager.ts b/packages/create-react-native-library/src/utils/packageManager.ts new file mode 100644 index 000000000..5f7fecb33 --- /dev/null +++ b/packages/create-react-native-library/src/utils/packageManager.ts @@ -0,0 +1,8 @@ +import fs from 'fs-extra'; +import path from 'path'; + +export async function determinePackageManager() { + return (await fs.pathExists(path.join(process.cwd(), 'yarn.lock'))) + ? 'yarn' + : 'npm'; +}