Skip to content

chore: use react-native init for generating example app #271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9f1febf
feat: generate example app via `react-native init`
atlj Sep 6, 2022
a06282b
chore(example template): remove android files
atlj Sep 6, 2022
3d2482f
chore(example template): remove unused root files
atlj Sep 6, 2022
98f8e40
chore(example template): remove ios files
atlj Sep 6, 2022
795d980
chore(example template): remove android buildscripts
atlj Sep 6, 2022
93223d1
refactor: move rn example app generator to utils
atlj Sep 6, 2022
25bb21b
chore(example template): rename index.tsx to index.ts
atlj Sep 6, 2022
8bd1521
feat: enable new architecture on turbo module libraries
atlj Sep 6, 2022
e1aacb6
refactor: rename app exampleAppGenerators to generateRNApp
atlj Sep 6, 2022
910769d
refactor: don't specify RN version for example apps
atlj Sep 6, 2022
8d3e444
refactor(example generator): extract files to delete to constant
atlj Sep 6, 2022
3e1548b
refactor(rn example generator): extract packages to add and remove
atlj Sep 6, 2022
2f01afb
fix: native example code is generated on expo projects
atlj Sep 6, 2022
f7fb47d
refactor(example generator): change isTurbomodule flag as isNewArch
atlj Sep 6, 2022
950881a
docs(example generator): remove version param from init command
atlj Sep 6, 2022
6fd32f3
feat: set root package's react and react native versions from example…
atlj Sep 7, 2022
9e3a313
chore: add a patch for react-native 0.70.0 for codegen on ios
atlj Sep 7, 2022
72097b4
fix(example template): tests cant import `App.tsx`
atlj Sep 7, 2022
5a23737
fix(example generator): react-test-renderer and react-native types ar…
atlj Sep 8, 2022
a7f8e6d
fix: remove unnecessary parts from patch file
atlj Sep 14, 2022
f086680
feat: use react-native init without any templates
atlj Sep 17, 2022
949ecb1
feat: show spinner while generating example app
atlj Sep 17, 2022
1b69ed0
Merge branch 'main' into @atlj/integrate-react-native-init
satya164 Sep 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/create-react-native-library/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"fs-extra": "^10.1.0",
"github-username": "^6.0.0",
"kleur": "^4.1.4",
"ora": "^5.4.1",
"prompts": "^2.4.2",
"validate-npm-package-name": "^4.0.0",
"yargs": "^17.5.1"
Expand Down
28 changes: 28 additions & 0 deletions packages/create-react-native-library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import dedent from 'dedent';
import kleur from 'kleur';
import yargs from 'yargs';
import spawn from 'cross-spawn';
import ora from 'ora';
import validateNpmPackage from 'validate-npm-package-name';
import githubUsername from 'github-username';
import prompts, { PromptObject } from './utils/prompts';
import generateRNApp from './utils/generateRNApp';

const FALLBACK_BOB_VERSION = '0.18.3';

Expand Down Expand Up @@ -413,6 +415,17 @@ async function create(argv: yargs.Arguments<any>) {
}
};

await fs.mkdirp(folder);
if (example === 'native') {
const spinner = ora('Generating example app').start();
await generateRNApp({
dest: folder,
projectName: options.project.name,
isNewArch: options.project.turbomodule,
});
spinner.succeed();
}

await copyDir(COMMON_FILES, folder);

if (languages === 'js') {
Expand Down Expand Up @@ -469,6 +482,21 @@ async function create(argv: yargs.Arguments<any>) {
}
}

if (example === 'native') {
// Set `react` and `react-native` versions of root `package.json` from example `package.json`
const examplePackageJson = fs.readJSONSync(
path.join(folder, 'example', 'package.json')
);
const rootPackageJson = fs.readJSONSync(path.join(folder, 'package.json'));
rootPackageJson.devDependencies.react =
examplePackageJson.dependencies.react;
rootPackageJson.devDependencies['react-native'] =
examplePackageJson.dependencies['react-native'];
fs.writeJSONSync(path.join(folder, 'package.json'), rootPackageJson, {
spaces: 2,
});
}

try {
spawn.sync('git', ['init'], { cwd: folder });
spawn.sync('git', ['add', '.'], { cwd: folder });
Expand Down
132 changes: 132 additions & 0 deletions packages/create-react-native-library/src/utils/generateRNApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import fs from 'fs';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can call it generateExampleApp.
WDYT?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screen Shot 2022-09-06 at 17 55 11

It was like this then got changed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exampleAppGenerators is different 😅

I think generateReactNativeExample or something like that is good, we'd also need generateExpoExample

import spawn from 'cross-spawn';
import path from 'path';

const FILES_TO_DELETE = [
'.eslintrc.js',
'.gitignore',
'.prettierrc.js',
'App.js',
'index.js',
'.flowconfig',
'.buckconfig',
];

const FOLDERS_TO_DELETE = ['__tests__'];

const PACKAGES_TO_REMOVE = [
'@react-native-community/eslint-config',
'babel-jest',
'eslint',
'jest',
'react-test-renderer',
];

const PACKAGES_TO_ADD = {
'babel-plugin-module-resolver': '^4.1.0',
'metro-react-native-babel-preset': '^0.72.1',
'patch-package': '^6.4.7',
'postinstall-postinstall': '^2.1.0',
};

export default async function generateRNApp({
dest,
projectName,
isNewArch,
}: {
dest: string;
projectName: string;
isNewArch: boolean;
}) {
// Generate the example app's base using `npx react-native init <projectName>Example --directory example --skip-install`
const createRNAppProcess = spawn(
'npx',
[
'react-native',
'init',
`${projectName}Example`,
'--directory',
path.join(dest, 'example'),
'--skip-install',
],
{
cwd: dest,
}
);
await new Promise((resolve, reject) => {
createRNAppProcess.once('error', reject);
createRNAppProcess.once('close', resolve);
});

// Remove unnecessary files
FILES_TO_DELETE.forEach((file) => {
try {
fs.unlinkSync(path.join(dest, 'example', file));
} catch (e) {
//ignore
}
});

// Remove unnecessary folders
FOLDERS_TO_DELETE.forEach((folder) => {
try {
fs.rmSync(path.join(dest, 'example', folder), {
recursive: true,
});
} catch (e) {
// ignore
}
});

// Patch the example app's package.json
const examplePackageJson = JSON.parse(
fs.readFileSync(path.join(dest, 'example', 'package.json'), 'utf8')
);
examplePackageJson.scripts = {
...examplePackageJson.scripts,
test: undefined,
lint: undefined,

pods: 'pod-install --quiet',
postinstall: 'patch-package',
};
PACKAGES_TO_REMOVE.forEach((pkg) => {
examplePackageJson.devDependencies[pkg] = undefined;
});
examplePackageJson.devDependencies = {
...examplePackageJson.devDependencies,
...PACKAGES_TO_ADD,
};
examplePackageJson.jest = undefined;
fs.writeFileSync(
path.join(dest, 'example', 'package.json'),
JSON.stringify(examplePackageJson, null, 2)
);

// If the library is on new architecture, enable new arch for IOS and Android
if (isNewArch) {
// Android
// Change newArchEnabled=false to newArchEnabled=true in example/android/gradle.properties
const gradleProperties = fs
.readFileSync(
path.join(dest, 'example', 'android', 'gradle.properties'),
'utf8'
)
.replace('newArchEnabled=false', 'newArchEnabled=true');
fs.writeFileSync(
path.join(dest, 'example', 'android', 'gradle.properties'),
gradleProperties
);

// IOS
// Add ENV['RCT_NEW_ARCH_ENABLED'] = 1 on top of example/ios/Podfile
const podfile = fs.readFileSync(
path.join(dest, 'example', 'ios', 'Podfile'),
'utf8'
);
fs.writeFileSync(
path.join(dest, 'example', 'ios', 'Podfile'),
"ENV['RCT_NEW_ARCH_ENABLED'] = '1'\n" + podfile
);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
diff --git a/node_modules/react-native/scripts/codegen/generate-artifacts-executor.js b/node_modules/react-native/scripts/codegen/generate-artifacts-executor.js
index 458495b..6fc398a 100644
--- a/node_modules/react-native/scripts/codegen/generate-artifacts-executor.js
+++ b/node_modules/react-native/scripts/codegen/generate-artifacts-executor.js
@@ -204,6 +204,55 @@ function handleThirdPartyLibraries(
});
}

+function handleLibrariesFromReactNativeConfig(
+ libraries,
+ codegenConfigKey,
+ codegenConfigFilename,
+ appRootDir,
+) {
+ const rnConfigFileName = 'react-native.config.js';
+
+ console.log(
+ `\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in ${rnConfigFileName}`,
+ );
+
+ const rnConfigFilePath = path.join(appRootDir, rnConfigFileName);
+
+ if (fs.existsSync(rnConfigFilePath)) {
+ const rnConfig = require(rnConfigFilePath);
+
+ if (rnConfig.dependencies != null) {
+ Object.keys(rnConfig.dependencies).forEach(name => {
+ const dependencyConfig = rnConfig.dependencies[name];
+
+ if (dependencyConfig.root) {
+ const codegenConfigFileDir = path.resolve(
+ appRootDir,
+ dependencyConfig.root,
+ );
+ const configFilePath = path.join(
+ codegenConfigFileDir,
+ codegenConfigFilename,
+ );
+ const pkgJsonPath = path.join(codegenConfigFileDir, 'package.json');
+
+ if (fs.existsSync(configFilePath)) {
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath));
+ const configFile = JSON.parse(fs.readFileSync(configFilePath));
+ extractLibrariesFromJSON(
+ configFile,
+ libraries,
+ codegenConfigKey,
+ pkgJson.name,
+ codegenConfigFileDir,
+ );
+ }
+ }
+ });
+ }
+ }
+}
+
function handleInAppLibraries(
libraries,
pkgJson,
@@ -362,6 +411,39 @@ function createComponentProvider(
}
}

+function findCodegenEnabledLibraries(
+ appRootDir,
+ baseCodegenConfigFileDir,
+ codegenConfigFilename,
+ codegenConfigKey,
+) {
+ const pkgJson = readPackageJSON(appRootDir);
+ const dependencies = {...pkgJson.dependencies, ...pkgJson.devDependencies};
+ const libraries = [];
+
+ handleReactNativeCodeLibraries(
+ libraries,
+ codegenConfigFilename,
+ codegenConfigKey,
+ );
+ handleThirdPartyLibraries(
+ libraries,
+ baseCodegenConfigFileDir,
+ dependencies,
+ codegenConfigFilename,
+ codegenConfigKey,
+ );
+ handleLibrariesFromReactNativeConfig(
+ libraries,
+ codegenConfigKey,
+ codegenConfigFilename,
+ appRootDir,
+ );
+ handleInAppLibraries(libraries, pkgJson, codegenConfigKey, appRootDir);
+
+ return libraries;
+}
+
// It removes all the empty files and empty folders
// it finds, starting from `filepath`, recursively.
//
@@ -429,23 +511,12 @@ function execute(
}

try {
- const pkgJson = readPackageJSON(appRootDir);
- const dependencies = {...pkgJson.dependencies, ...pkgJson.devDependencies};
- const libraries = [];
-
- handleReactNativeCodeLibraries(
- libraries,
- codegenConfigFilename,
- codegenConfigKey,
- );
- handleThirdPartyLibraries(
- libraries,
+ const libraries = findCodegenEnabledLibraries(
+ appRootDir,
baseCodegenConfigFileDir,
- dependencies,
codegenConfigFilename,
codegenConfigKey,
);
- handleInAppLibraries(libraries, pkgJson, codegenConfigKey, appRootDir);

if (libraries.length === 0) {
console.log('[Codegen] No codegen-enabled libraries found.');
@@ -482,6 +553,7 @@ module.exports = {
execute: execute,
// exported for testing purposes only:
_extractLibrariesFromJSON: extractLibrariesFromJSON,
+ _findCodegenEnabledLibraries: findCodegenEnabledLibraries,
_executeNodeScript: executeNodeScript,
_generateCode: generateCode,
_cleanupEmptyFilesAndFolders: cleanupEmptyFilesAndFolders,

This file was deleted.

This file was deleted.

Loading