11#!/usr/bin/env node
2+ const chalk = require ( 'chalk' ) ;
23const fs = require ( 'fs' ) ;
3- const tmpdir = require ( 'os' ) . tmpdir ( ) + '/react-native-bundle-visualizer' ;
4+ const os = require ( 'os' ) ;
45const argv = require ( 'minimist' ) ( process . argv . slice ( 2 ) ) ;
56const execa = require ( 'execa' ) ;
7+ const rimraf = require ( 'rimraf' ) ;
8+ const open = require ( 'open' ) ;
9+ const { explore } = require ( 'source-map-explorer' ) ;
10+ const pkgJSON = JSON . parse ( fs . readFileSync ( './package.json' ) ) ;
11+
12+ function getAppName ( ) {
13+ if ( pkgJSON . name ) return pkgJSON . name ;
14+ try {
15+ const appJSON = JSON . parse ( fs . readFileSync ( './app.json' ) ) ;
16+ return appJSON . name || appJSON . expo . name || 'UnknownApp' ;
17+ } catch ( err ) {
18+ return 'UnknownApp' ;
19+ }
20+ }
621
722function getEntryPoint ( ) {
8- const pkgJSON = JSON . parse ( fs . readFileSync ( './package.json' ) ) ;
923 let entry = pkgJSON . main || 'index.js' ;
1024 if ( entry [ 0 ] !== '.' && entry [ 0 ] !== '/' && entry [ 0 ] !== '\\' ) {
1125 entry = './' + entry ;
@@ -14,17 +28,24 @@ function getEntryPoint() {
1428}
1529
1630// Get (default) arguments
31+ const baseDir = os . tmpdir ( ) + '/react-native-bundle-visualizer' ;
32+ const tmpDir = baseDir + '/' + getAppName ( ) ;
1733const entryFile = argv [ 'entry-file' ] || getEntryPoint ( ) ;
1834const platform = argv . platform || 'ios' ;
1935const dev = argv . dev || false ;
36+ const verbose = argv . verbose || false ;
2037const bundleOutput =
21- argv [ 'bundle-output' ] || tmpdir + '/' + platform + '.bundle' ;
38+ argv [ 'bundle-output' ] || tmpDir + '/' + platform + '.bundle' ;
2239const bundleOutputSourceMap = bundleOutput + '.map' ;
40+ const bundleOutputExplorerHTML = tmpDir + '/output/explorer.html' ;
2341
2442// Make sure output dir exists
25- if ( ! fs . existsSync ( tmpdir ) ) fs . mkdirSync ( tmpdir ) ;
43+ if ( ! fs . existsSync ( baseDir ) ) fs . mkdirSync ( baseDir ) ;
44+ if ( fs . existsSync ( tmpDir ) ) rimraf . sync ( tmpDir ) ;
45+ fs . mkdirSync ( tmpDir ) ;
2646
27- // Start
47+ // Bundle
48+ console . log ( chalk . green . bold ( 'Generating bundle...' ) ) ;
2849const bundlePromise = execa ( './node_modules/.bin/react-native' , [
2950 'bundle' ,
3051 '--platform' ,
@@ -39,10 +60,57 @@ const bundlePromise = execa('./node_modules/.bin/react-native', [
3960 bundleOutputSourceMap
4061] ) ;
4162bundlePromise . stdout . pipe ( process . stdout ) ;
42- bundlePromise . then ( ( ) => {
43- const explorerPromise = execa ( './node_modules/.bin/source-map-explorer' , [
44- bundleOutput ,
45- bundleOutputSourceMap
46- ] ) ;
47- explorerPromise . stdout . pipe ( process . stdout ) ;
48- } ) ;
63+
64+ // Upon bundle completion, run `source-map-explorer`
65+ bundlePromise
66+ . then (
67+ ( ) => {
68+ const stats = fs . statSync ( bundleOutput ) ;
69+ console . log (
70+ chalk . green . bold (
71+ 'Bundle is ' +
72+ Math . round ( ( stats . size / ( 1024 * 1024 ) ) * 10 ) / 10 +
73+ ' MB in size'
74+ )
75+ ) ;
76+ return explore (
77+ {
78+ code : bundleOutput ,
79+ map : bundleOutputSourceMap
80+ } ,
81+ {
82+ output : {
83+ format : 'html' ,
84+ filename : bundleOutputExplorerHTML
85+ }
86+ }
87+ ) ;
88+ }
89+
90+ // Log info and open html file
91+ )
92+ . then ( result => {
93+ if ( verbose ) {
94+ result . bundles . forEach ( bundle => {
95+ Object . keys ( bundle . files ) . forEach ( file => {
96+ console . log (
97+ chalk . green ( file + ', size: ' + bundle . files [ file ] + ' bytes' )
98+ ) ;
99+ } ) ;
100+ } ) ;
101+ }
102+
103+ // Log any errors
104+ if ( result . errors ) {
105+ result . errors . forEach ( error => {
106+ if ( error . isWarning ) {
107+ console . log ( chalk . yellow . bold ( error . message ) ) ;
108+ } else {
109+ console . log ( chalk . red . bold ( error . message ) ) ;
110+ }
111+ } ) ;
112+ }
113+
114+ // Open html file
115+ return open ( bundleOutputExplorerHTML ) ;
116+ } ) ;
0 commit comments