Notes on sharing React Native project code between my Win 11 desktop PC and old Win 10 mini Laptop

Last updated on 5 Jun 2025
I recently upgraded Node on both my Windows 11 desktop PC (DPC) and old low-config Windows 10 Dell Mini Laptop (DML) to v22.16.0. I wanted to have same Node version on both the computers. DPC earlier had Node v22.13.1. DML seems to have had much older Node (probably v20.x.x). 

I then copied over all files of a Timestamp React native and Expo project which works with Expo Go from DPC to DML (using WiFi transfer of zip file of the project). The project folder size was around 205 MB (including node_modules) (zip file was around 66 MB). The code was working for both web and Android using Expo Go on DPC. The code ran right away on DML too (with npm run start)! I tested it (DML project) both on web and Android using Expo Go. Note that on DML I cannot run Android Emulator as it is too low-config for that. But I could use Expo Go on my Samsung Android phone and run the Timestamp app running (perhaps I should say being bundled, to be more accurate) on DML. It worked as expected. I think it is because I took care to have the same Node version on both computers that the code worked right away on DML with 'npm run start'.

Now if I have a long powercut problem, I think I will be able to do some work on the Timestamp RN project on DML. If that really works out, that will be cool!

I think that even for React Native projects using development build (like Simon Grimm Edu app (SG app) tutorial that I am going through), I could explore a similar approach. The folder size is much bigger (node_modules subfolder is 3.8 GB and android subfolder is 1.4 GB). But if the copied folder works on DML and I am able to run web app on DML and Android app on Samsung phone using development apk installed on Samsung phone then I will be able to use DML for development work on this project when I am having a long powercut issue. Of course, I will be able to do the development build only on DPC. But I think it is possible that for most JSX and Javascript code changes, Metro and Webpack bundlers running on DML should handle it with older development apk build on Samsung phone in case of Metro. I don't need to have a rebuilt dev app for most JSX and Javascript code changes. I will have to test this out to know whether it works or not.

Perhaps cloud EAS builds may also help when using DML. I did face a problem of local DPC build succeeding and the app running as expected on DPC but EAS build using same code copied to DML and EAS issued from DML, failing. So I think there are some tripping up points when using EAS cloud build as against local build.

I should also mention here that for React projects as well as backend API Node projects, DML manages it quite OK. It is a little slow but it works. React Native and Expo development build projects are much bigger in size and so I have to check whether DML can handle it in the way I have described above. 

In this context, I had a very interesting ChatGPT interaction starting on 31 May 2025 where I shared the above contents with ChatGPT. Chat is titled: 'Sharing React Native projects across PCs' and I have shared a pruned version of the long chat as a public Google Doc: https://docs.google.com/document/d/1qxL0nuX8rgZGqDI45q_5cPhuF7qzj2zsEoJXQukXWWQ/preview . The points below are based on that chat:
  1. Ensuring identical Node.js versions across systems is crucial for React Native and Expo projects. It avoids subtle issues due to differences in dependency resolution, Metro bundler behavior, or underlying native modules.
  2. Since you are relying on Expo Go and not a custom development build for the timestamp app, this approach (using npm run start with Expo Go) is highly portable. Expo abstracts away many native build-related concerns, making it ideal for low-resource machines like your DML.
  3. Different Uses of “Native” term in React Native / Node.js Ecosystems:
    1. Native Code means Java/Kotlin (Android) or Obj-C/Swift (iOS) code. It is code that runs directly on a mobile OS, not JavaScript. [Note that JavaScript is run on React Native apps on mobile using a JavaScript engine (typically Hermes) that translates JavaScript into device machine-readable instructions.]
    2. React Native refers to Framework that lets you use React with native mobile capabilities. Write JS, but it talks to Android/iOS native components.
    3. Native Module (React Native) refers to a JS module that calls into Android/iOS code (via bridge). It lets JS talk to camera, file system, sensors, etc.
    4. Native Node Module refers to an npm package with C/C++ code compiled for Node.js. It is used when JavaScript alone isn’t fast or powerful enough.
    5. Native Binary (Node) is used in context of Native Node Module and it means the compiled file (.node, .so, etc.) used by Node. It is the actual machine-level binary created from native Node module.
    6. Running on Native (e.g., Android native) means running compiled Java/Kotlin code directly on device. It bypasses JS, for performance or deeper system integration.
  4. Simple Mnemonic for "Native" term:
    1. If it runs in the browser or Node, it’s JavaScript.
    2. If it talks to the OS/hardware directly, it’s native.
    3. If it’s written in C/C++, Java, Kotlin, Swift, or Obj-C — it’s native code.
    4. If it needs to be compiled — it’s native code or native binary.
  5. Expo Project Terminology Clarification
    1. Managed Workflow:
      1. No native code.
      2. Runs in Expo Go.
      3. Easier, but limited in native capabilities.
    2. Bare Workflow:
      1. Full control over native code (like a typical React Native app).
      2. Must build your own app (locally or via eas build).
      3. Supports any React Native package, including those that require native linking.
    3. Custom Development Client:
      1. A variation of Bare Workflow that still uses Expo tooling, but with your own built version of Expo Go (expo-dev-client).
      2. You build this client once, install it on your device, and then run your app using npm run start.
  6. SG app uses Custom Dev Client workflow — ideal for building production-capable apps while still using Expo tools.
  7. One way to differentiate between an Expo managed worflow project and an Expo bare workflow (or prebuild workflow) project is package.json entry for "android".
    1. Timestamp which is an Expo managed workflow project has (in package.json): "android": "expo start --android".
      1. This tells Expo CLI to:
        1. Start the Metro bundler
        2. Open the Expo Go app (on emulator or connected device)
      2. It assumes you are using Expo Go, which only works in the Managed Workflow
      3. No need to compile native code or build APKs
    2. SG app is an Expo bare workflow project (to be more precise, it is a subset of Expo bare workflow project and the Expo team sometimes refers to such projects as “Prebuild Workflow” or “Custom Dev Client Workflow” projects). This project package.json has: "android": "expo run:android".
      1. This tells Expo CLI to:
        1. Compile and build the native Android app (using Gradle)
        2. Install it directly on a connected device or emulator
      2. This command only works if your project has an android/ directory → i.e., a Bare Workflow
      3. Required when using a custom dev client or modifying native code
  8. In React (Web):
    1. node_modules/ is created and populated by npm install or yarn install.
    2. It only contains package source code, metadata, and JS-related tooling.
    3. Web bundlers like Vite, Webpack, etc., do not add build artifacts inside node_modules.
    4. So even with many dependencies, node_modules rarely exceeds 300–500 MB (often much less).
  9. In React Native with development build (aka: Bare Workflow/Prebuild Workflow/Custom Dev Client Workflow):
    1. node_modules/ starts the same way: it's populated by npm install.
    2. BUT, if your project has native modules (e.g., react-native-reanimated, react-native-screens), and you run a local build (npx expo run:android, ./gradlew assembleDebug, etc.), then:
      1. These native packages get compiled into .so, .obj, etc.
      2. Those compiled binaries are stored inside their own node_modules/package-name/android/build/** subdirectories.
      3. Some intermediate outputs (NDK, CMake, Gradle caches, etc.) also get cached here.
    3. The android folder of these native modules has source files which come from the associated npm package itself. The local build uses these source files to create build artifacts of the package which are also placed in the same android folder. So, after a local build, these android folders will have source files as well as build artifacts. Metro on DML will not need the source files of node_modules/*/android/ directories. But retaining the source files will provide the ability of regenerating the build if needed (on a suitable specs machine). Hence only the build artifacts of these android folders should be excluded/deleted in the node_modules copy for DML. Further, the source files of these node_modules/*/android/ directories are not large in size and so deleting them will not give significant size reduction.
    4. It is due to these build artifacts created during local build that node_modules can bloat to 3 GB, 5 GB, or even more in a React Native project with development build/Bare Workflow — it's no longer just JS code, but also native compiled artifacts. In contrast, in React (web) , after npm install, the node_modules folder is not modified by any build process.
    5. Deleting/excluding build artifacts from node_modules needs a special script.
      1. 'npx react-native clean-project' will give option to delete whole of node_modules which is not what we want.
      2. 'cd android' followed by './gradlew clean' will not delete node_modules folder build artifacts.
      3. In SG app, besides react-native-* packages many expo-* packages have android/build folders (build artifacts).
      4. android\build and android\.cxx folders are definitely build artifacts and safe to  delete/exclude.
      5. But some folders named 'build' within node_modules folder tree are not build artifacts. For example, node_modules\expo-secure-store\build in the SG app has files which are part of the npm package. These are not build artifacts and should not be deleted or excluded. 
      6. Two Powershell scripts for this pruning have been provided later on in this post. This pruning should significantly reduce node_modules size. The build artifacts will be re-generated the next time a build is done. Details about the scripts are provided below:
        1. CopyPrunedRNNodeModules.ps1 copies node_modules excluding build artifacts.
        2. PruneRNNodeModules.ps1 deletes build artifacts.
        3. CopyPrunedRNNodeModules.ps1 is more efficient than two steps of first copying entire node_modules directory and then running PruneRNNodeModules.ps1 on the copy.
        4. A time.ps1 script is also provided which can be used to time the above commands.
        5. Attempts to create scripts to use 7zip to create a zip file directly from node_modules excluding the build artifact folders did not work out. So I have opted for a two step process: First copy node_modules excluding the build folders and then run 7zip on the copy.
        6. For SG app, CopyPrunedRNNodeModules.ps1 usually took around 7 minutes. The node_modules folder size was 3.75 GB but the pruned copy folder (nm_pruned) size was 475 MB only.  7zip took 1 min. 33 secs to zip nm_pruned folder to a 146 MB zip file.
  10. In React Native with Expo Managed Workflow (Expo Go), the node_modules folder size is similar to React (web) case, as no build artifacts are added to node_modules.
  11. Copying node_modules of a React Native project from one machine to another  — When It Can Work.
    1. If:
      1. Both machines are using the same OS type and version (e.g., Windows 10 vs Windows 11 usually OK, Windows vs Linux — not OK),
      2. Both have matching Node.js, npm/yarn versions, and
      3. The project doesn't include native Node modules (node-gyp, .node files), or they are rebuilt as needed,
      4. The copied node_modules has intermediate build files pruned (especially .so, .obj, build, cxx, etc.),
      5. And symlink-related quirks or post-install scripts are avoided or rerun via npm install or npm rebuild,
    2. Then yes, it is often safe and useful to copy node_modules — especially:
      1. When bandwidth is limited
      2. On low-RAM/low-CPU systems
      3. For development and testing, not production
    3. But Do Keep In Mind
      1. No guarantee it will always work — it's a shortcut with risk, though often a low one for typical RN projects
      2. If anything breaks unexpectedly (e.g., Metro server crashes, weird runtime errors), rebuild/reinstall cleanly as first troubleshooting step
      3. Don't use this approach for publishing, production builds, or CI/CD systems
    4.  Excellent for:
      1. Financially constrained students or learners with low-bandwith (low-speed like < 10 Mbps) and/or low data cap (like 1.5 to 2.5 GB per day) Internet. [My 4G mobile speed during daytime and evening is usually between 1 to 5 Mbps with higher speeds of usually 10 to 25 Mpbs during late night/early morning. I have two SIMs each with a 1.5 GB/day plan and so a total of 3 GB/day but I also use additional data packs when needed. I find that I am able to manage React Native development build for simple to medium complexity projects like SG app with this Internet connection and so have not opted for an optical fibre Internet connection (Jio Fiber 30 Mbps unlimited is around Rs.500 per month).]
      2. Low-spec machines used for Metro, JS/JSX development and testing
      3. Copying from "build-capable" to "Metro-only" machines
      4. Disk/backup snapshots of dev environments
  12. Large Project (like SG app with dev build) Transfer Strategy from DPC to DML
    1. Make a local copy of node_modules excluding build artifacts on DPC. This preserves the full build artifacts on DPC, avoiding unnecessary rebuilds later
    2. Transfer this pruned copy to DML and rename as node_modules
    3. On DML, run npm install (optional but safe) to fix anything missing
    4. On DML, run npm start (or npx expo start) to begin development. Web app can be run with w and on Samsung phone. scan Metro's Expo development mode (as against Expo Go mode) scancode to run Android app.
    5. On DML, use Metro’s “Reset Cache” option if weird bugs occur. On a slower machine like DML, cached bundles can get corrupted or stale. Run: npm start -- --reset-cache
    6. Why This Works
      1. React Native + Metro only need:
        1. JS code
        2. Package metadata
        3. Native module JS wrappers
      2. They don’t need the compiled .so files or intermediate C++/Gradle cache folders unless you’re rebuilding native code — which you’re not doing on DML.
    7. No re-compilation needed on DPC later when I use DPC for development, running and testing app.
  13. When do you need Gradle rebuild (on DPC)? You only need to rebuild the app with Gradle in these cases:
    1. You add/remove native packages (e.g. install react-native-camera, react-native-reanimated, etc.).
    2. You change native Java/Kotlin/NDK/C++ code.
    3. You do a fresh install on another device and don't have a dev APK built yet.
  14. I don't have any native code in the SG app itself. I already have the project set up on my main computer (DPC) and have done local build there and created dev APK which is installed on DPC Android emulator as well as on my Samsung phone. I don't need to do install of the project/app on any other device. So the only scenario where I will need to rebuild my app (dev APK) is if I add remove native packages.
  15. EAS Build Differences
    1. Your observation is important. EAS builds use managed environments, and if the system environment (like eas-cli or Node version or Expo SDK) differs even slightly, cloud build may fail.
    2. Suggestion:
      1. Use eas diagnostics to compare the local and remote build environments.
      2. Add eas.json to define build profiles (with clear dependencies and settings).
      3. Use npx expo doctor to ensure project sanity before sending it for EAS build.
  16. How common is it for node packages to have platform-specific binaries or compiled artifacts?
    1. Common Cases Where node_modules is Pure JavaScript
      1. Frontend libraries (e.g., react, redux, lodash, etc.)
      2. Utility libraries (moment, axios, uuid, etc.)
      3. Most Expo-compatible packages (especially in managed workflow)
      4. JavaScript-only backend packages (e.g., Express middleware, parsers)
      5. ✅ These are safe to copy across platforms as they're just JS.
    2. Cases Where Native Code or Platform-Specific Binaries Are Involved
      1. React Native Native Modules
        1. Packages like:
          1. react-native-fs
          2. react-native-sqlite-storage
          3. react-native-camera
          4. react-native-gesture-handler (partially native)
        2. These often include native Android (.so or .aar) and/or iOS code (.a, .framework) or compile C/C++/Java/Swift code during build time.
        3. Even in Expo, if you're using the development build workflow with expo-dev-client, native code is linked at build time.
      2. Packages with Node.js Native Addons (node-gyp)
        1. These compile C/C++ code at install time using your system's compiler.
        2. Examples:
          1. sharp (image processing)
          2. bcrypt (encryption)
          3. sqlite3 (database)
          4. node-sass (older CSS tooling)
        3. These generate platform-specific binaries in node_modules, and copying them between machines with different OS/architectures can cause errors.
      3. Build Artifacts & Prebuilt Binaries
        1. Some packages include precompiled binaries or use post-install scripts to download them.
        2. These binaries may be:
          1. OS-specific
          2. Node-version-specific
          3. Architecture-specific (e.g., x64 vs ARM)
  17. [ChatGPT review suggestion:] Connecting the dev APK on phone to Metro bundler using QR code scan
    1. To connect the development build APK running on my Samsung phone with the Metro bundler (running either on DPC or DML), I use the phone’s QR code scan feature. This scans the QR code displayed by Metro bundler (typically via npx expo start or similar command), which contains the local IP address and port of the Metro server.
    2. As both devices are on the same local network, this allows the dev APK to automatically connect to the Metro server without requiring any manual configuration of IP or port. The development build app then fetches the JavaScript bundle and assets directly from the connected Metro bundler, enabling live development and debugging features. This approach avoids the need to explicitly manage ports and simplifies testing across machines.
  18. [ChatGPT review suggestion:] Running the dev app on Android emulator on DPC using Metro on DPC.
    1. When working on the React Native app on my DPC (Windows 11 desktop PC), I run the app on the Android emulator using Metro on the same machine (DPC). I typically use either:
      1. npm run android — which starts Metro, launches the Android emulator, and if needed, builds and installs the app.
      2. Or I start Metro manually using npm run start and then press the a key in the Metro terminal window to reload or start the app in the Android emulator (and install it if it's not already installed).
    2. Since both Metro and the emulator are on the same machine, no special Metro configuration or port management is needed.
  19. Using npm install on DML to setup and use node_modules without build artifacts (equivalent to pruned node_modules): An alternative way to have limited size node_modules folder (~475 MB as against 3.8 GB node_modules folder with build artifacts) on DML and still be able to run web app on DML and Android app on Samsung phone is:
    1. Copy only the project source code including package.json from DPC to DML.
    2. Run npm install on DML which will download the packages into the node_modules folder. The download size would be around 475 MB but that is a manageable figure for me both from download time as well as data limit points of view.
    3. After that, running npm run start on DML will start the Metro bundler without triggering any Android build.
    4. This setup allows:
      1. The web version of the React Native app to run on DML.
      2. The previously built development APK (built on DPC and installed on the Samsung phone) to connect to the Metro bundler running on DML via QR code scanning.
The points below are short or very short info. about some topics. The details are provided in the pruned chat Google Doc mentioned earlier
  1. ChatGPT provided some tips to reduce data usage while doing React Native development:
    1. Use Gradle Offline Mode if your Android dependencies don’t change:
      1. ./gradlew assembleDebug --offline
      2. Or enable offline mode in Android Studio: File → Settings → Build, Execution, Deployment → Build Tools → Gradle → Offline work
    2.  Cache the Android SDK & Gradle
      1. Avoid using tools or settings that clean Gradle or SDK caches (like ./gradlew clean unless necessary).
      2. Pin specific Gradle and build tools versions in your android/build.gradle.
    3. Stick with Expo Go if Possible. Until you're ready to publish or test native features:
      1. Use Expo Go + npm start instead of dev builds.
      2. It dramatically reduces both build time and download needs.
      3. Your Expo Timestamp app is ideal for this workflow.
    4. Use pnpm (Optional). pnpm shares common node_modules across projects using symlinks. If you have multiple React Native projects:
      1. Saves storage
      2. May reduce install size and download time
      3. Requires changing install commands from npm to pnpm
  2. ChatGPT gave explanation of compilation process. Terms and processes explained: APK,  DEX (Dalvik EXecutable), Android Runtime (ART), architectures (armeabi-v7a (32-bit ARM), arm64-v8a (64-bit ARM), x86, x86_64 (less common, used in some emulators or Intel devices)), .dex (Java/Kotlin bytecode), .so (native C/C++/NDK code), cross-compilation using the Android NDK and ABI (Application Binary Interface)
=====================================
2 June 2025 , EH

[For CopyPrunedRNNodeModules run on SG lms (timed with time script):]
Elapsed time: 6 minute(s) and 51 second(s)
nm_pruned folder has size (on disk) of 475 MB. node_modules folder has size (on disk) of 3.75 GB.

For: time zf .\nm_pruned\ Y N
Elapsed time: 1 minute(s) and 33 second(s)
nm_pruned.zip is of size 146 MB

So a file of only 146 MB has to be transferred to DML from DPC.
...
On DML, which also had a node upgrade to v22.16.0 but, IFIRC, from an older version of node than v22.13.1, running strapi server (backend for SG app lms frontend) using 'npm run develop' gave the error (path slightly edited):
 Error: The module '\\?\C:\Users\{Username}\Projects\VSCode\ReactNative\SGEduApp\Ravi-lms-api\node_modules\better- sqlite3\build\Release\better_sqlite3.node'
 was compiled against a different Node.js version using                                                          
 NODE_MODULE_VERSION 115. This version of Node.js requires
 NODE_MODULE_VERSION 127. Please try re-compiling or re-installing
 the module (for instance, using `npm rebuild` or `npm install`).      
===========
[5 Jun Update: 
On digging up the issue, this seemed to be because I had done npm install for the SG Strapi server api on DML using its earlier Node version (which seems to have been NODE_MODULE_VERSION 115 and which seems to correspond to Node v20.x.x). The package better-sqlite3,  https://www.npmjs.com/package/better-sqlite3 has a binding.gyp file and src/better_sqlite3.cpp file indicating it has native code whose binary (.node file) is either downloaded or are compiled during npm install process. [ChatGPT: "better_sqlite3.node is a native binary compiled into a platform-specific format — e.g., .dll on Windows, .so on Linux, .dylib on macOS — and placed under build/Release/ by node-gyp or downloaded by prebuild-install."]

On DPC, I ran:
console.log({ 
...   node: process.version,
...   node_abi: process.versions.modules,
...   platform: process.platform,
...   arch: process.arch
... });
----
Its output:
{ node: 'v22.16.0', node_abi: '127', platform: 'win32', arch: 'x64' }

Note that DML also has Node v22.16.0 and so its node_abi (Node ABI version) will also be 127.
----

As per ChatGPT, "When a native addon is built with node-gyp, the compiled binary (.node file) is a [PE/ELF/DLL] format file containing compiled machine code targeted for a specific Node ABI version." .. "When you require('better-sqlite3'), Node attempts to load the .node binary. It checks the binary’s NODE_MODULE_VERSION (ABI version) embedded in the binary header against the currently running Node.js process.versions.modules. If they don’t match, Node throws an error like: " ..
"Error: The module was compiled against a different Node.js version using NODE_MODULE_VERSION XX but Node.js version YY is running." ..
"Even if the .node binary "might" work on a later ABI due to binary compatibility, Node.js refuses to risk it, hence the conservative runtime check."

So on DML, the better-sqlite3.node file would have been built or downloaded when I was using Node v20.x.x which may be associated with Node ABI version 115. After upgrading DML to Node v22.16.0 (Node ABI version 127), when I tried to run the strapi server built on earlier Node version, Node.js (with ABI 127) would have inspected strapi server's better-sqlite3.node file and found it was built with Node ABI 115 and so given the above error.

end 5 Jun update]

So I then tried out copying entire Ravi-lms-api folder on DPC to DML (with zip and later unzip). Running this copied api backend on DML using 'npm run develop' without doing an npm install, worked! Strapi server started quickly but Strapi administration panel on Chrome browser took lot of time to show up. Perhaps that's related to some other network related issue.

Next, I made a small .env API backend IP address related parameter change in lms app and then I started lms app bundler on DML with 'npm run start'. The Metro bundler started without issues. On opening app in web browser, the web bundling took perhaps 6 to 8 minutes after which the Login screen was shown. I don't know whether subsequent runs will be faster on not. Will check that. .. I was able to login and view the app pages on browser. Great!
Next I scanned the Metro QR code (on DML) on my Samsung phone. That started the dev app which was already installed on it. The Android bundling started on Metro. I don't know how much time it took as I had to do some other non-computer activity. IFIRC, after 10 minutes or so when I came back to the PC, the main Android bundling was done. The phone display had turned off. I turned it back on, and the app screen appeared with the tabs and title, but the main content area showed an activity indicator. Metro on PC showed that some DOM bundling was being done which took around 1 to 2 minutes after which the phone showed the main content area with the expected content.

So this approach of copying pruned node_modules and project source code of SG app (lms) which is a React Native and Expo development build app, from DPC to DML and then running Metro bundler on DML without any app build, has worked! Not only is the web app running on DML but the Android development build APK built on DPC and installed on Samsung phone is able to work with Metro running on DML.

3 Jun 2025

On DML, (in Terminal) ran SG Strapi server 'npm run develop' - It started in 50 odd secs.
On DML, for SG lms project, Metro started off very quickly (perhaps less than 10 secs) (in Terminal). Scanned QR code on phone resulting in Android bundling on Metro - That was less than 30 seconds I think but the app got stuck on Clerk auth as I don't have Internet now. At times, during late evening, I have experienced both Jio and Airtel networks Internet being off! It usually gets restored by half an hour to an hour, I think. I don't know whether it is my phone problem or problem faced by others too.

I restarted phone. After that, I was able to use Jio at slow speed but Airtel was still having some issues (don't recall now if it was just too slow or was not working at all). But little later, I think within the half-hour to one-hour period from when Internet had stopped on phone, both Jio and Airtel are now working at over 1 Mbps speeds which is the usual for late evening like 8 to 9 PM (now it is 8.58 PM).

=====================================

time.ps1 script

--- start script code ---
param (
    [Parameter(Mandatory = $true, ValueFromRemainingArguments = $true)]
    [string[]] $Command
)

# Show documentation message
Write-Host "NOTE: For Boolean parameters, pass 1 (true) or 0 (false) when using ./time.`n"

# Start stopwatch
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()

# Run the command with live output
#Invoke-Expression ($Command -join ' ')

# Run the command with live output
Write-Host "Executing command: $($Command -join ' ')" -ForegroundColor Cyan
Invoke-Expression ($Command -join ' ')

# Stop stopwatch
$stopwatch.Stop()

# Format elapsed time
$minutes = [int]$stopwatch.Elapsed.TotalMinutes
$seconds = $stopwatch.Elapsed.Seconds
Write-Host "Elapsed time: $minutes minute(s) and $seconds second(s)"

--- end script code ---

=====================================

CopyPrunedRNNodeModules.ps1 script

--- start script code ---
param (
    [string]$SourceFolder = ".\node_modules",
    # Keep destination folder name size lesser than node_modules to avoid filename length exceeding Windows OS limit error
    [string]$DestFolder = ".\nm_pruned",
    [bool]$ShowRoboCopyMessages = $true,
    [bool]$PromptForExclusion = $false
)

# Validate source folder exists, else error and exit
try {
    $sourceFolder = (Resolve-Path $SourceFolder -ErrorAction Stop).ProviderPath
} catch {
    Write-Error "Source folder '$SourceFolder' does not exist. Please provide a valid source folder."
    exit 1
}

# Check destination folder does NOT exist
if (Test-Path $DestFolder) {
    Write-Error "Destination folder '$DestFolder' already exists. Please specify a new destination folder or remove the existing one."
    exit 1
}

Write-Host "Source folder: $sourceFolder"
Write-Host "Destination folder: $DestFolder"
Write-Host ""

# Find android\build and android\.cxx folders inside node_modules to exclude
$excludeFolders = Get-ChildItem -Path $sourceFolder -Recurse -Directory |
    Where-Object { $_.FullName -match "android[\\/](build|\.cxx)$" } |
    Select-Object -ExpandProperty FullName

$finalExcludeFolders = @()

foreach ($folder in $excludeFolders) {
    if ($PromptForExclusion) {
        $response = Read-Host "Exclude folder '$folder' from copy? [Y/N] (default: N)"
        if ($response.Trim().ToUpper() -eq 'Y') {
            $finalExcludeFolders += $folder
        }
    } else {
        # No prompt, always exclude
        $finalExcludeFolders += $folder
    }
}

Write-Host ""
Write-Host "Folders to be excluded:"
$finalExcludeFolders | ForEach-Object { Write-Host $_ }
Write-Host ""

# Prepare robocopy arguments
$roboArgs = @(
    $sourceFolder,
    $DestFolder,
    "/E"  # copy all subdirectories including empty ones
)

if (-not $ShowRoboCopyMessages) {
    # Add output suppression flags only if ShowRoboCopyMessages is false
    $roboArgs += @(
        "/NFL",  # no file list
        "/NDL",  # no directory list
        "/NJH",  # no job header
        "/NJS",  # no job summary
        "/NP"    # no progress
    )
}

# Add /XD switches for each excluded folder
foreach ($excl in $finalExcludeFolders) {
    $roboArgs += "/XD"
    $roboArgs += $excl
}

# Show robocopy command line for confirmation
$roboCmdLine = "robocopy " + ($roboArgs | ForEach-Object { "`"$($_)`"" }) -join " "
Write-Host "Robocopy command that will be run:"
Write-Host $roboCmdLine
Write-Host ""

$response = Read-Host "Run robocopy? [Y/N] (default: N)"
if ($response.Trim().ToUpper() -ne 'Y') {
    Write-Host "Aborting copy."
    exit 0
}

# Run robocopy
Write-Host "Running robocopy..."
robocopy @roboArgs

Write-Host "Done."

--- end script code ---

=====================================

PruneRNNodeModules.ps1 script does the following:
  • First does a dry run and lists all folders it would delete.
  • Then for each folder, prompts you individually to delete or skip.
  • The prompt for each folder defaults to No (skip delete).
  • No mass delete, only per-folder with confirmation.
--- start script code ---
# PruneReactNativeNodeModulesWithPrompt.ps1
# Dry run listing first, then for each folder, ask user to delete with default No.

$ErrorActionPreference = "Stop"

Write-Host "Scanning for android build-related folders inside node_modules..."

# Find folders matching android/build or android/.cxx under node_modules
$foldersToDelete = Get-ChildItem -Path .\node_modules -Recurse -Directory |
    Where-Object {
        $_.FullName -match "node_modules[\\/].+?[\\/]android[\\/](build|\.cxx)$"
    }

if ($foldersToDelete.Count -eq 0) {
    Write-Host "No android/build or android/.cxx folders found inside node_modules."
    exit 0
}

Write-Host "Found the following folders that would be candidates for deletion:`n"
foreach ($folder in $foldersToDelete) {
    Write-Host $folder.FullName
}

Write-Host "`nNow you will be prompted for each folder whether to delete it or not. Default is No (skip delete)."

foreach ($folder in $foldersToDelete) {
    $prompt = "Delete folder:`n $($folder.FullName) ? (y/N) [Default: No]: "
    Write-Host $prompt -NoNewline
    $response = Read-Host

    if ($response -match '^(y|Y|yes|YES)$') {
        try {
            Remove-Item -Path $folder.FullName -Recurse -Force
            Write-Host "Deleted: $($folder.FullName)`n"
        }
        catch {
            Write-Warning "Failed to delete: $($folder.FullName) - $_"
        }
    } else {
        Write-Host "Skipped: $($folder.FullName)`n"
    }
}

Write-Host "Pruning complete."
--- end Powershell script ---

Comments