Skip to content

Instantly share code, notes, and snippets.

@lelandrichardson
Last active May 12, 2017 15:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lelandrichardson/c7a68950ec10576e174543413bb6e711 to your computer and use it in GitHub Desktop.
Save lelandrichardson/c7a68950ec10576e174543413bb6e711 to your computer and use it in GitHub Desktop.
Find RN Imports
const walk = require('babylon-walk');
const babylon = require('babylon');
const glob = require('glob');
const fs = require('fs');
const path = require('path');
const zip = (a, b, fn) => a.forEach((el, i) => fn(el, b[i], i));
const promisify = fn => new Promise((res, rej) => {
const done = (err, val) => (err ? rej(err) : res(val));
fn(done);
});
const getFile = fpath => promisify(cb => fs.readFile(fpath, 'utf8', cb));
const getFiles = fpath => promisify(cb => fs.readdir(fpath, cb));
const getGlobbedFiles = (g, opts) => promisify(cb => glob(g, opts, cb));
function getAST(data, file) {
let tree;
try {
tree = babylon.parse(data, {
sourceType: 'module',
plugins: [
'jsx',
'flow',
'objectRestSpread',
'exportExtensions',
'classProperties',
],
});
return tree;
} catch (e) {
console.error(file, e);
return null;
}
}
function getReactNativeImports(tree, collector) {
walk.simple(tree, {
ImportDeclaration: (node) => {
if (node.source.value === 'react-native') {
const names = node.specifiers
.filter(spec => spec.type === 'ImportSpecifier')
.map(spec => spec.imported.name);
collector.push(...names);
}
},
});
return collector;
}
function getReactNativeImportsFromPath(file, collector) {
return getFile(file)
.then(str => getAST(str, file))
.then(tree => getReactNativeImports(tree, collector));
}
const results = [];
getGlobbedFiles(process.argv[2], { dot: false, absolute: true })
.then(files => Promise.all(files.map(f => getReactNativeImportsFromPath(f, results))))
.then(() => {
const amounts = {};
results.forEach(name => {
if (!amounts[name]) {
amounts[name] = 0;
}
amounts[name] += 1;
});
process.stdout.write(`name\tcount\n`);
Object.keys(amounts).forEach(key => {
process.stdout.write(`${key}\t${amounts[key]}\n`);
});
});

To run this, you will first need to install the following npm packages:

npm i babylon babylon-walk glob

Then, with the script in the current directory in find-rn-imports.js, you would want to run it, passing in a glob pattern to hit all of the source code files in your repo. For instance I ran something like:

node ./find-rn-imports.js '!(node_modules|test)/**/*.js'

The output of that script will indicate which react native APIs you are importing and how many times in your code base (though this assumes you are using import and not require).

@lelandrichardson
Copy link
Author

@mini-eggs you can add decorator support by adding 'decorators' to the list of plugins in the babylon.parse call

@dabit3
Copy link

dabit3 commented Apr 30, 2017

name	count
View	59
StyleSheet	35
Platform	20
Image	12
Dimensions	15
TouchableOpacity	7
Text	56
TouchableWithoutFeedback	9
ScrollView	6
Navigator	4
TouchableHighlight	8
Animated	5
Easing	3
StatusBar	3
TextInput	3
TouchableNativeFeedback	5
ActivityIndicator	5
DatePickerAndroid	1
DatePickerIOS	1
Keyboard	4
TimePickerAndroid	1
Picker	1
Switch	1
Modal	1
ListView	10
WebView	2
PanResponder	1
Alert	5
Linking	2
CameraRoll	3
InteractionManager	7
KeyboardAvoidingView	3

@justinobney
Copy link

@lelandrichardson curious what airbnb is using for routing?

@bleonard
Copy link

bleonard commented May 1, 2017

name count
View 129
TouchableWithoutFeedback 7
Image 9
PixelRatio 46
NativeModules 11
Vibration 2
TouchableOpacity 16
StyleSheet 114
PanResponder 5
Animated 6
Easing 4
Text 8
ListView 9
Dimensions 22
Keyboard 8
Platform 16
StatusBar 3
InteractionManager 2
Modal 1
ScrollView 16
Linking 7
ActivityIndicator 4
Switch 1
TextInput 1
Clipboard 6
TouchableHighlight 2
AppState 2
Navigator 1
Alert 1
AlertIOS 1
PushNotificationIOS 2
BackAndroid 2
RefreshControl 2
WebView 4
findNodeHandle 1
Picker 3
Share 1
AsyncStorage 1
ActionSheetIOS 1

@bleonard
Copy link

bleonard commented May 1, 2017

We wrap many of the components, so I assume this wouldn't catch them. For example we have out own <Text> that sets various defaults and such on the built-in one.
The platform stuff as well is wrapped with one file included in android and one in iOS. So there are several alerts and/or action sheets, but we only include it in Platform/ActionSheet.ios.js similar to the sample project

@sahrens
Copy link

sahrens commented May 1, 2017

@mini-eggs - what kind of abstractions around Animated have you found valuable?

@bmeck
Copy link

bmeck commented May 1, 2017

from an isomorphic UI lib in use in several apps:

name	count
View	11
TouchableWithoutFeedback	4
Text	12
StyleSheet	7
Platform	3
TouchableOpacity	1
TouchableHighlight	1
Modal	1
TextInput	1
NativeModules	1
Switch	2

@lelandrichardson
Copy link
Author

@justinobney there's a lot more info about that here: https://www.youtube.com/watch?v=tWitQoPgs8w

@fabriziomoscon
Copy link

my list

name	count
NativeModules	1
NativeEventEmitter	1
Platform	20
StyleSheet	68
Text	64
TextInput	8
View	68
Animated	2
Easing	2
Image	16
ActivityIndicator	14
Dimensions	3
StatusBar	3
TouchableOpacity	20
TouchableNativeFeedback	12
NavigationExperimental	4
Alert	10
Linking	1
ScrollView	16
Modal	4
ListView	2
RefreshControl	2
Switch	1
AppState	3
Share	2
Picker	1
NetInfo	1
WebView	1
AsyncStorage	2

@timbielawski
Copy link

I got

name count
View 98
Text 87
Linking 4
TouchableOpacity 46
Alert 5
Animated 18
ListView 3
StyleSheet 88
TextInput 8
TouchableWithoutFeedback 6
PanResponder 2
AppRegistry 1
Image 32
ScrollView 35
Dimensions 5
TouchableHighlight 6
LayoutAnimation 7
ActivityIndicator 32
Platform 29
ToastAndroid 2
TouchableNativeFeedback 1
BackAndroid 2
PermissionsAndroid 1
AlertIOS 1
Picker 1
AsyncStorage 2
InteractionManager 10
KeyboardAvoidingView 2
RecyclerViewBackedScrollView 2
Modal 3
Keyboard 1
WebView 1
Slider 1
StatusBar 2
AppState 1
NetInfo 1
Navigator 1

@tijs
Copy link

tijs commented May 2, 2017

For a recent RN project of ours:

name count
Alert 16
Platform 20
Text 47
View 65
StyleSheet 62
TextInput 7
Dimensions 31
TouchableOpacity 28
Image 30
Animated 14
TouchableHighlight 10
TouchableWithoutFeedback 9
StatusBar 5
Easing 9
ScrollView 6
ListView 7
UIManager 5
LayoutAnimation 5
PermissionsAndroid 1
Linking 8
NetInfo 1
AppState 3
NativeModules 4
InteractionManager 2
RefreshControl 2
ActionSheetIOS 1
Navigator 1
AsyncStorage 1

@kelset
Copy link

kelset commented May 3, 2017

Output for our production app:
screen shot 2017-05-03 at 15 00 07

@sahrens
Copy link

sahrens commented May 8, 2017

I had to break up the Promise.all into multiple batches to get it to finish, but here are our numbers:

 { globFiles: 11540, filesProcessed: 11540 }
name	count
StyleSheet	3110
View	3045
Text	1507
Image	962
Platform	725
NativeModules	543
TouchableOpacity	431
TouchableHighlight	314
ScrollView	284
Dimensions	200
ListView	184
TouchableWithoutFeedback	181
Animated	163
PixelRatio	153
TextInput	137
Alert	89
LayoutAnimation	87
Modal	81
Linking	80
AppRegistry	67
Navigator	53
UIManager	44
ActivityIndicator	34
StatusBar	34
AsyncStorage	32
AlertIOS	31
TouchableNativeFeedback	31
FlatList	28
KeyboardAvoidingView	28
Keyboard	28
WebView	26
Easing	26
Switch	25
PanResponder	22
ToastAndroid	19
ActionSheetIOS	17
InteractionManager	15
RefreshControl	15
AppState	15
SectionList	14
Clipboard	14
PushNotificationIOS	12
Picker	12
PermissionsAndroid	9
NetInfo	7
NativeEventEmitter	7
Slider	4
RecyclerViewBackedScrollView	2

@sahrens
Copy link

sahrens commented May 8, 2017

I also had to change the matcher to handle our requires since we still haven't switched, so I used a whitelist on the module names, so might have missed some.

@sahrens
Copy link

sahrens commented May 12, 2017

Also note with our numbers up there we have some different internal implementations, e.g. for Image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment