Getting an environment ready for React Native development can take some time and is error prone. Developers have also problems setting up all the Android environment and emulators and on Windows it's even worse with the mixed messages about Hyper-V and HAXM.
After talking with a few RN developers from different projects and companies, it seems like the average to get a new machine up and running is between 1/2-1 day 😓
doctor is great to help with this, and I think we can take it even further by automatically installing and configuring the required dependencies if missing.
My tests were mainly on Windows because I believe it's going to be the most complicated platform. My goal is to not require admin privileges so the developer doesn't see the UAC prompt. I think it's doable.
The list of dependencies from the docs are:
Node 10+
Script runs on node so not a lot to check other than the version via process.version for completeness?
Python 2
We can use the same approach as windows-build-tools.
The installation on Windows should be under %LOCALAPPDATA%/python2
msiexec.exe /i "${pythonInstaller}" TARGETDIR="${targetDir}" /qn /L*P "python-log.txt"JDK
Version 8 or later is recommended in the docs. I'd rather use a later one as the installation without admin privileges will be a lot easier.
https://javadl.oracle.com/webapps/download/GetFile/${JAVA_VERSION}-b${BUILD}/${ID}/windows-i586/jdk-${JDK_VERSION}-windows-x64.exe (need to add some extra stuff in that URL...)"${jdkInstaller}" /s INSTALLDIR="${targetDir}" ADDLOCAL="ToolsFeature,SourceFeature";Android packages
My initial tests where without Android Studio and going directly with the Android SDK Tools (https://dl.google.com/android/repository/sdk-tools-windows-4333796.zip). It looks like a lot of developers still need AS for native debugging and other scenarios so I think we should start with it and then maybe add an option to only download the SDK tools.
The biggest problem here was that user needs to accept licenses when using the CLI or nothing gets downloaded/installed. I ended up doing the following to auto-accept:
const installDependency = (command) => {
return new Promise((done, error) => {
const child = exec(command, { maxBuffer: 1024 * 500 });
child.stdout.on('data', (data) => {
if (data.includes('(y/N):')) {
console.log(`Accepting License for ${command}`);
child.stdin.write('y\n');
}
});
child.stderr.on('data', (data) => {
console.error(data);
});
child.on('close', done);
child.on('error', error);
});
};
Hyper-V vs HAXM vs WHPX
I know there's a command to know if Hyper-V is active or not. I'll check with other teams in Microsoft (Xamarin?) to know exactly what the best configuration is for running the Android emulators.
Setting and updating environment variables
The approaches that worked for me are:
// https://superuser.com/a/601034
// Set
const command = `setx ${variable} "${value}"`;
// Update
const command = `for /f "skip=2 tokens=3*" %a in ('reg query HKCU\\Environment /v ${variable}') do @if [%b]==[] ( @setx ${variable} "${value};%~a" ) else ( @setx ${variable} "${value};%~a %~b" )
`;
And execute it via require('child_process').exec
This will only modify the user ones, which was one of my goals.
Open questions
For reference, my testing project is in here.
Hope this is enough to get the conversation started and identify any other issues or conflicts!
Thanks for the thorough proposal! I think we could definitely make it a part of doctor. Furthermore, we could detect some specific issues and advise people to run doctor to help resolve them.
I'm starting to look at this in more depth and here is my current proposal.
I've look at the current code and there's a tools/install.ts that defaults to hombrew for macOS. Even though Windows has chocolatey, it's not installed by default and as widely use. I think I prefer to stick to my plan of "manual" download and install. What I'm thinking is that instead of trying to abstract everything under install in the runAutomaticFix, each healthcheck should know how to get solved on each platform. An quick example could be:
export default {
label: 'Python',
getDiagnostics: async ({Languages}) => ({
// ...
}),
runAutomaticFix: async ({loader}) => {
switch(process.platform) {
case 'win32': await windowsInstall(urlToDownload, command, label, loader); break;
case 'darwin': await brewInstall({pkg, label, loader}); break;
default: logManualInstallation(...); break;
},
},
} as HealthCheckInterface;
Another option (that I think I prefer) would be to have specific actions per platform and a default one in case it is not supported. That way we remove the switch (that will be repeated in all healthchecks). It will be the responsibility of whoever is calling runAutomaticFix to decide which one to run.
export default {
label: 'Python',
getDiagnostics: async ({Languages}) => ({
// ...
}),
win32AutomaticFix: async () => { },
darwinAutomaticFix: async () => { },
runAutomaticFix: async () => { /* fallback scenario */ },
} as HealthCheckInterface;
One of the pros of the latest approach is that it should be easy to look at a file and know what platform doesn't have an automatic fix.
Create a downloader.ts tool under cli/src/tools that will download any given URL to the OS tmp folder (and returning that path) using got (has progress events but it's 1.21MB) or node-fetch (no progress events and 153kB). I see you are using ora so I'm not sure about how to add a real progress bar. Maybe having the spinner and saying it might take a while is enough?
I don't think it makes a lot of sense to add a windowsInstall.ts. Each package will be installed differently (.msi, .exe, .zip, different commands, some require fake "user input", etc.). I'm planning on using execa just so there's less boilerplate. Not too big and should make the code more readable.
Create a updateWindowsEnvVariables.ts (or similar) under tools to update/create the user env variables.
envinfo can tell the installed Python and Java versions so I'll just expand cli/src/info/info.ts to request that information (and make whatever changes are needed).
For the testing strategy I'm thinking about using some mocks and look at:
Let me know what you think and if everything looks fine I'll start working on the Python healthcheck and make a draft PR to start looking at the changes!
Most helpful comment
Thanks for the thorough proposal! I think we could definitely make it a part of
doctor. Furthermore, we could detect some specific issues and advise people to rundoctorto help resolve them.