Remove console.log in Production to Enhance Performance (babel-plugin-transform-remove-console) - Part 2

This is a follow up since the original is closed

@notbrent Hi Brent, I just rebuild my App and have a burning question. How come I install the babel-plugin-transform-remove-console in dev, and then put it into production? Since I will have no way to check if there are console.log running in production (or, is there a way??). how do I know it works?

Right now under app.json, I have:
image

And then in bable.config.js:
image

Is that because Babel can only “live” in dev? Does it look like correct? Thanks a lot!!!

Hi @rachellauyui

I don’t think you need to do anything at all to remove console.log() calls from the code in production mode.

If you run npx expo start and then connect to http://[your-ip]:19000 in a web browser you will get something like this:

{"name":"test","slug":"test","version":"1.0.0","orientation":"portrait","icon":"./assets/icon.png","userInterfaceStyle":"light","splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff","imageUrl":"http://192.168.99.99:19000/assets/./assets/splash.png"},"updates":{"fallbackToCacheTimeout":0},"assetBundlePatterns":["**/*"],"ios":{"supportsTablet":true,"bundleIdentifier":"com.example.test"},"android":{"adaptiveIcon":{"foregroundImage":"./assets/adaptive-icon.png","backgroundColor":"#FFFFFF","foregroundImageUrl":"http://192.168.99.99:19000/assets/./assets/adaptive-icon.png"},"package":"com.example.test"},"web":{"favicon":"./assets/favicon.png"},"_internal":{"isDebug":false,"projectRoot":"/tmp/test","dynamicConfigPath":null,"staticConfigPath":"/tmp/test/app.json","packageJsonPath":"/tmp/test/package.json"},"sdkVersion":"46.0.0","platforms":["ios","android","web"],"iconUrl":"http://192.168.99.99:19000/assets/./assets/icon.png","debuggerHost":"192.168.99.99:19000","logUrl":"http://192.168.99.99:19000/logs","developer":{"tool":"expo-cli","projectRoot":"/tmp/test"},"packagerOpts":{"dev":false},"mainModuleName":"node_modules/expo/AppEntry","__flipperHack":"React Native packager is running","hostUri":"192.168.99.99:19000","bundleUrl":"http://192.168.99.99:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=false&hot=false&minify=true"}

At the end there is a bundleUrl:

http://192.168.99.99:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=false&hot=false&minify=true

You can modify that URL to fetch either the iOS or Android bundle, and you can fetch the minified code or the unminified code, and you can specify the dev or production versions.

If I fetch e.g. the iOS, dev=true, unminified bundle for a test app that has one console.log() call and search for instances of console.log in it, I get this:

$ curl -s 'http://192.168.99.99:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false' | grep console.log
            prevLog = console.log;
        console.log('Failed to print error: ', ee.message);
            console.log((info.type === TO_JS ? 'N->JS' : 'JS->N') + " : " + ("" + (info.module != null ? info.module + '.' : '') + info.method) + ("(" + JSON.stringify(info.args) + ")"));
            prevLog = console.log;
        console.log('HeapCapture.captureHeap succeeded: ' + path);
        console.log('HeapCapture.captureHeap error: ' + e.toString());
          console.log('The JSC Sampling Profiler has started');
          console.log('The JSC Sampling Profiler has stopped');
        console.log('Error occurred when restarting Sampling Profiler: ' + e.toString());
          console.log(logs.join('\n  '));
            console.log.apply(console, args);
            console.log(new Error().stack.split('\n').slice(1).join('\n'));
            console.log(key);
            console.log(value);
            console.log('Props:', result.props);
            console.log('State:', result.state);
            console.log('Hooks:', result.hooks);
            console.log('Nodes:', nativeNodes);
            console.log('Location:', result.source);
            console.log('Right-click any value to save it as a global variable for further inspection.');
          prevLog = console.log;
            console.log('%crecordMount()', 'color: green; font-weight: bold;', id, getData(internalInstance).displayName);
            console.log(key);
            console.log(value);
            console.log('Props:', result.props);
            console.log('State:', result.state);
            console.log('Context:', result.context);
            console.log('Node:', nativeNode);
            console.log('Right-click any value to save it as a global variable for further inspection.');
              console.log('[React DevTools] Error calling listener', data);
              console.log('error:', error);
            console.log('You specified `onScroll` on a <ScrollView> but not ' + '`scrollEventThrottle`. You will only receive one event. ' + 'Using `16` you get all the events but be aware that it may ' + "cause frame drops, use a bigger number if you don't need as " + 'much precision.');
    console.log("Hello, World!");
$

Only the very last one is in my actual code. The rest is all from React, React Native, etc.

If I do the same for a production version, it finds no calls to console.log:

$ curl -s 'http://192.168.99.99:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=false&hot=false&minify=false' | grep console.log
$

The above is with minify=false, so it’s not like console.log was renamed or something. But to be sure, you can grep for ‘Hello’ and see that the result is the same:

$ curl -s 'http://192.168.99.99:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=false&hot=false&minify=false' | grep Hello
$

Hi Michael!! I wonder if this is a SDK46 specific? Where it just inbibit all console.log in production since nobody is reading it anyway?

I didn’t check earlier SDK versions, but I doubt it’s specific to SDK 46. You could try my test on an earlier SDK if you’re interested.

I did notice that the npx expo export command does not seem to strip the console.log() calls. I’m not sure why that is, but have not investigated any further yet.