Skip to content

Commit 4359b83

Browse files
troZeeptrocki
andauthored
refactor: add separate option to generate view modules (#105)
Co-authored-by: ptrocki <[email protected]>
1 parent 05e8089 commit 4359b83

File tree

17 files changed

+606
-24
lines changed

17 files changed

+606
-24
lines changed

src/create.ts

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,41 @@ import pack from '../package.json';
1313
const BINARIES = /(gradlew|\.(jar|keystore|png|jpg|gif))$/;
1414

1515
const COMMON_FILES = path.resolve(__dirname, '../templates/common');
16-
const NATIVE_FILES = path.resolve(__dirname, '../templates/native-library');
1716
const JS_FILES = path.resolve(__dirname, '../templates/js-library');
1817
const EXPO_FILES = path.resolve(__dirname, '../templates/expo-library');
1918
const CPP_FILES = path.resolve(__dirname, '../templates/cpp-library');
20-
const OBJC_FILES = path.resolve(__dirname, '../templates/objc-library');
21-
const SWIFT_FILES = path.resolve(__dirname, '../templates/swift-library');
2219
const EXAMPLE_FILES = path.resolve(__dirname, '../templates/example');
2320

21+
// Android
22+
const NATIVE_FILES = (moduleType: ModuleType) => {
23+
switch (moduleType) {
24+
case 'module':
25+
return path.resolve(__dirname, '../templates/native-library');
26+
case 'view':
27+
return path.resolve(__dirname, '../templates/native-view-library');
28+
}
29+
};
30+
31+
// Objc
32+
const OBJC_FILES = (moduleType: ModuleType) => {
33+
switch (moduleType) {
34+
case 'module':
35+
return path.resolve(__dirname, '../templates/objc-library');
36+
case 'view':
37+
return path.resolve(__dirname, '../templates/objc-view-library');
38+
}
39+
};
40+
41+
// Swift
42+
const SWIFT_FILES = (moduleType: ModuleType) => {
43+
switch (moduleType) {
44+
case 'module':
45+
return path.resolve(__dirname, '../templates/swift-library');
46+
case 'view':
47+
return path.resolve(__dirname, '../templates/swift-view-library');
48+
}
49+
};
50+
2451
type ArgName =
2552
| 'slug'
2653
| 'description'
@@ -30,14 +57,25 @@ type ArgName =
3057
| 'repo-url'
3158
| 'type';
3259

60+
type ModuleType = 'module' | 'view';
61+
62+
type LibraryType =
63+
| 'native-view'
64+
| 'native-view-swift'
65+
| 'native'
66+
| 'native-swift'
67+
| 'js'
68+
| 'cpp'
69+
| 'expo';
70+
3371
type Answers = {
3472
slug: string;
3573
description: string;
3674
authorName: string;
3775
authorEmail: string;
3876
authorUrl: string;
3977
repoUrl: string;
40-
type: 'native' | 'native-swift' | 'js' | 'cpp' | 'expo';
78+
type: LibraryType;
4179
};
4280

4381
export const args: Record<ArgName, yargs.Options> = {
@@ -168,6 +206,8 @@ export default async function create(argv: yargs.Arguments<any>) {
168206
message: 'What type of package do you want to develop?',
169207
// @ts-ignore - seems types are wrong for inquirer
170208
choices: [
209+
{ name: 'Native view in Kotlin and Objective-C', value: 'native-view' },
210+
{ name: 'Native view in Kotlin and Swift', value: 'native-view-swift' },
171211
{ name: 'Native module in Kotlin and Objective-C', value: 'native' },
172212
{ name: 'Native module in Kotlin and Swift', value: 'native-swift' },
173213
{ name: 'Native module with C++ code', value: 'cpp' },
@@ -211,6 +251,8 @@ export default async function create(argv: yargs.Arguments<any>) {
211251
} as Answers;
212252

213253
const project = slug.replace(/^(react-native-|@[^/]+\/)/, '');
254+
const moduleType: ModuleType =
255+
type === 'native-view' || type === 'native-view-swift' ? 'view' : 'module';
214256

215257
const options = {
216258
bob: {
@@ -226,10 +268,16 @@ export default async function create(argv: yargs.Arguments<any>) {
226268
.slice(1)}`,
227269
package: slug.replace(/[^a-z0-9]/g, '').toLowerCase(),
228270
podspec: slug.replace(/[^a-z0-9]+/g, '-').replace(/^-/, ''),
229-
native: type === 'native' || type === 'cpp' || 'native-swift',
271+
native:
272+
type === 'native' ||
273+
type === 'cpp' ||
274+
'native-swift' ||
275+
'native-view' ||
276+
'native-view-swift',
230277
cpp: type === 'cpp',
231-
swift: type === 'native-swift',
278+
swift: type === 'native-swift' || 'native-view-swift',
232279
module: type !== 'js',
280+
moduleType,
233281
},
234282
author: {
235283
name: authorName,
@@ -284,14 +332,15 @@ export default async function create(argv: yargs.Arguments<any>) {
284332
path.join(EXAMPLE_FILES, 'example'),
285333
path.join(folder, 'example')
286334
);
287-
await copyDir(NATIVE_FILES, folder);
335+
336+
await copyDir(NATIVE_FILES(moduleType), folder);
288337

289338
if (type === 'cpp') {
290339
await copyDir(CPP_FILES, folder);
291340
} else if (type === 'native-swift') {
292-
await copyDir(SWIFT_FILES, folder);
341+
await copyDir(SWIFT_FILES(moduleType), folder);
293342
} else {
294-
await copyDir(OBJC_FILES, folder);
343+
await copyDir(OBJC_FILES(moduleType), folder);
295344
}
296345
}
297346

templates/common/example/src/App.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
import * as React from 'react';
2+
<% if (project.moduleType === "view") { %>
3+
import { StyleSheet, View } from 'react-native';
4+
import <%= project.name %>ViewManager from '<%= project.slug %>';
5+
<% } else {%>
26
import { StyleSheet, View, Text } from 'react-native';
3-
import <%= project.name %>, { <%= project.name %>ViewManager } from '<%= project.slug %>';
7+
import <%= project.name %> from '<%= project.slug %>';
8+
<% }%>
49

10+
<% if (project.moduleType === "view") { %>
11+
export default function App() {
12+
return (
13+
<View style={styles.container}>
14+
<<%= project.name %>ViewManager color="#32a852" style={styles.box} />
15+
</View>
16+
);
17+
}
18+
<% } else {%>
519
export default function App() {
620
const [result, setResult] = React.useState<number | undefined>();
721

@@ -12,10 +26,10 @@ export default function App() {
1226
return (
1327
<View style={styles.container}>
1428
<Text>Result: {result}</Text>
15-
<<%= project.name %>ViewManager color="#32a852" style={styles.box} />
1629
</View>
1730
);
18-
}
31+
}
32+
<% }%>
1933

2034
const styles = StyleSheet.create({
2135
container: {
@@ -28,4 +42,4 @@ const styles = StyleSheet.create({
2842
height: 60,
2943
marginVertical: 20,
3044
},
31-
});
45+
});

templates/native-library/android/src/main/java/com/{%= project.package %}/{%= project.name %}Package.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ class <%= project.name %>Package : ReactPackage {
1212
}
1313

1414
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15-
return listOf(<%= project.name %>ViewManager())
15+
return emptyList()
1616
}
1717
}
Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
1-
import { NativeModules, requireNativeComponent, ViewStyle } from 'react-native';
1+
import { NativeModules } from 'react-native';
22

33
type <%= project.name %>Type = {
44
multiply(a: number, b: number): Promise<number>;
55
};
66

7-
type <%= project.name %>Props = {
8-
color: string;
9-
style: ViewStyle;
10-
};
11-
127
const { <%= project.name %> } = NativeModules;
138

14-
export const <%= project.name %>ViewManager = requireNativeComponent<<%= project.name %>Props>(
15-
'<%= project.name %>View'
16-
);
17-
189
export default <%= project.name %> as <%= project.name %>Type;
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
buildscript {
2+
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
3+
def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['<%= project.name %>_kotlinVersion']
4+
5+
repositories {
6+
google()
7+
jcenter()
8+
}
9+
10+
dependencies {
11+
classpath 'com.android.tools.build:gradle:3.2.1'
12+
// noinspection DifferentKotlinGradleVersion
13+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14+
}
15+
}
16+
17+
apply plugin: 'com.android.library'
18+
apply plugin: 'kotlin-android'
19+
20+
def getExtOrDefault(name) {
21+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['<%= project.name %>_' + name]
22+
}
23+
24+
def getExtOrIntegerDefault(name) {
25+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['<%= project.name %>_' + name]).toInteger()
26+
}
27+
28+
android {
29+
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
30+
buildToolsVersion getExtOrDefault('buildToolsVersion')
31+
defaultConfig {
32+
minSdkVersion 16
33+
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
34+
versionCode 1
35+
versionName "1.0"
36+
<% if (project.cpp) {%>
37+
externalNativeBuild {
38+
cmake {
39+
cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all"
40+
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
41+
}
42+
}
43+
<% } %>
44+
}
45+
<% if (project.cpp) {%>
46+
externalNativeBuild {
47+
cmake {
48+
path "CMakeLists.txt"
49+
}
50+
}
51+
<% } %>
52+
buildTypes {
53+
release {
54+
minifyEnabled false
55+
}
56+
}
57+
lintOptions {
58+
disable 'GradleCompatible'
59+
}
60+
compileOptions {
61+
sourceCompatibility JavaVersion.VERSION_1_8
62+
targetCompatibility JavaVersion.VERSION_1_8
63+
}
64+
}
65+
66+
repositories {
67+
mavenCentral()
68+
jcenter()
69+
google()
70+
71+
def found = false
72+
def defaultDir = null
73+
def androidSourcesName = 'React Native sources'
74+
75+
if (rootProject.ext.has('reactNativeAndroidRoot')) {
76+
defaultDir = rootProject.ext.get('reactNativeAndroidRoot')
77+
} else {
78+
defaultDir = new File(
79+
projectDir,
80+
'/../../../node_modules/react-native/android'
81+
)
82+
}
83+
84+
if (defaultDir.exists()) {
85+
maven {
86+
url defaultDir.toString()
87+
name androidSourcesName
88+
}
89+
90+
logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}")
91+
found = true
92+
} else {
93+
def parentDir = rootProject.projectDir
94+
95+
1.upto(5, {
96+
if (found) return true
97+
parentDir = parentDir.parentFile
98+
99+
def androidSourcesDir = new File(
100+
parentDir,
101+
'node_modules/react-native'
102+
)
103+
104+
def androidPrebuiltBinaryDir = new File(
105+
parentDir,
106+
'node_modules/react-native/android'
107+
)
108+
109+
if (androidPrebuiltBinaryDir.exists()) {
110+
maven {
111+
url androidPrebuiltBinaryDir.toString()
112+
name androidSourcesName
113+
}
114+
115+
logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}")
116+
found = true
117+
} else if (androidSourcesDir.exists()) {
118+
maven {
119+
url androidSourcesDir.toString()
120+
name androidSourcesName
121+
}
122+
123+
logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}")
124+
found = true
125+
}
126+
})
127+
}
128+
129+
if (!found) {
130+
throw new GradleException(
131+
"${project.name}: unable to locate React Native android sources. " +
132+
"Ensure you have you installed React Native as a dependency in your project and try again."
133+
)
134+
}
135+
}
136+
137+
def kotlin_version = getExtOrDefault('kotlinVersion')
138+
139+
dependencies {
140+
// noinspection GradleDynamicVersion
141+
api 'com.facebook.react:react-native:+'
142+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
143+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<%= project.name %>_kotlinVersion=1.3.50
2+
<%= project.name %>_compileSdkVersion=28
3+
<%= project.name %>_buildToolsVersion=28.0.3
4+
<%= project.name %>_targetSdkVersion=28
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.<%= project.package %>">
3+
4+
</manifest>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.<%= project.package %>
2+
3+
import com.facebook.react.ReactPackage
4+
import com.facebook.react.bridge.NativeModule
5+
import com.facebook.react.bridge.ReactApplicationContext
6+
import com.facebook.react.uimanager.ViewManager
7+
8+
9+
class <%= project.name %>Package : ReactPackage {
10+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11+
return emptyList()
12+
}
13+
14+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15+
return listOf(<%= project.name %>ViewManager())
16+
}
17+
}

0 commit comments

Comments
 (0)