UNPKG

ignite-router-flux

Version:

Infinite Red's hot boilerplate for React Native.

264 lines (230 loc) 9.05 kB
const options = require('./options') const { merge, pipe, assoc, omit, __ } = require('ramda') const { getReactNativeVersion } = require('./lib/react-native-version') /** * Is Android installed? * * $ANDROID_HOME/tools folder has to exist. * * @param {*} context - The gluegun context. * @returns {boolean} */ const isAndroidInstalled = function (context) { const androidHome = process.env['ANDROID_HOME'] const hasAndroidEnv = !context.strings.isBlank(androidHome) const hasAndroid = hasAndroidEnv && context.filesystem.exists(`${androidHome}/tools`) === 'dir' return Boolean(hasAndroid) } /** * Let's install. * * @param {any} context - The gluegun context. */ async function install (context) { const { filesystem, parameters, ignite, reactNative, print, system, prompt, template } = context const { colors } = print const { red, yellow, bold, gray, blue } = colors const perfStart = (new Date()).getTime() const name = parameters.third const spinner = print .spin(`using the ${red('Infinite Red')} boilerplate v2 (code name 'Andross')`) .succeed() // attempt to install React Native or die trying const rnInstall = await reactNative.install({ name, version: getReactNativeVersion(context) }) if (rnInstall.exitCode > 0) process.exit(rnInstall.exitCode) // remove the __tests__ directory and App.js that come with React Native filesystem.remove('__tests__') filesystem.remove('App.js') // copy our App, Tests & storybook directories spinner.text = '▸ copying files' spinner.start() filesystem.copy(`${__dirname}/boilerplate/App`, `${process.cwd()}/App`, { overwrite: true, matching: '!*.ejs' }) filesystem.copy(`${__dirname}/boilerplate/Tests`, `${process.cwd()}/Tests`, { overwrite: true, matching: '!*.ejs' }) filesystem.copy(`${__dirname}/boilerplate/storybook`, `${process.cwd()}/storybook`, { overwrite: true, matching: '!*.ejs' }) spinner.stop() // --max, --min, interactive let answers if (parameters.options.max) { answers = options.answers.max } else if (parameters.options.min) { answers = options.answers.min } else { answers = await prompt.ask(options.questions) } // generate some templates spinner.text = '▸ generating files' const templates = [ { template: 'index.js.ejs', target: 'index.js' }, { template: 'README.md', target: 'README.md' }, { template: 'ignite.json.ejs', target: 'ignite/ignite.json' }, { template: '.editorconfig', target: '.editorconfig' }, { template: 'babel.config.js', target: 'babel.config.js' }, { template: 'Tests/Setup.js.ejs', target: 'Tests/Setup.js' }, { template: 'storybook/storybook.ejs', target: 'storybook/storybook.js' }, { template: '.env.example', target: '.env.example' } ] const templateProps = { name, igniteVersion: ignite.version, reactNativeVersion: rnInstall.version, vectorIcons: answers['vector-icons'], animatable: answers['animatable'], i18n: answers['i18n'] } await ignite.copyBatch(context, templates, templateProps, { quiet: true, directory: `${ignite.ignitePluginPath()}/boilerplate` }) /** * Append to files */ // https://github.com/facebook/react-native/issues/12724 await filesystem.appendAsync('.gitattributes', '*.bat text eol=crlf') filesystem.append('.gitignore', '\n# Misc\n#') filesystem.append('.gitignore', '\n.env\n') /** * Merge the package.json from our template into the one provided from react-native init. */ async function mergePackageJsons () { // transform our package.json in case we need to replace variables const rawJson = await template.generate({ directory: `${ignite.ignitePluginPath()}/boilerplate`, template: 'package.json.ejs', props: templateProps }) const newPackageJson = JSON.parse(rawJson) // read in the react-native created package.json const currentPackage = filesystem.read('package.json', 'json') // deep merge, lol const newPackage = pipe( assoc( 'dependencies', merge(currentPackage.dependencies, newPackageJson.dependencies) ), assoc( 'devDependencies', merge(currentPackage.devDependencies, newPackageJson.devDependencies) ), assoc('scripts', merge(currentPackage.scripts, newPackageJson.scripts)), merge( __, omit(['dependencies', 'devDependencies', 'scripts'], newPackageJson) ) )(currentPackage) // write this out filesystem.write('package.json', newPackage, { jsonIndent: 2 }) } await mergePackageJsons() spinner.stop() // react native link -- must use spawn & stdio: ignore or it hangs!! :( spinner.text = `▸ linking native libraries` spinner.start() await system.spawn('react-native link', { stdio: 'ignore' }) spinner.stop() // pass long the debug flag if we're running in that mode const debugFlag = parameters.options.debug ? '--debug' : '' // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // NOTE(steve): I'm re-adding this here because boilerplates now hold permanent files // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= try { // boilerplate adds itself to get plugin.js/generators etc // Could be directory, npm@version, or just npm name. Default to passed in values const boilerplate = parameters.options.b || parameters.options.boilerplate || 'ignite-andross' await system.spawn(`ignite add ${boilerplate} ${debugFlag}`, { stdio: 'inherit' }) // now run install of Ignite Plugins await ignite.addModule('react-navigation', { version: '3.0.0' }) await ignite.addModule('react-native-gesture-handler', { version: '1.0.9', link: true }) ignite.patchInFile(`${process.cwd()}/android/app/src/main/java/com/${name.toLowerCase()}/MainActivity.java`, { after: 'import com.facebook.react.ReactActivity;', insert: ` import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactRootView; import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;` }) ignite.patchInFile(`${process.cwd()}/android/app/src/main/java/com/${name.toLowerCase()}/MainActivity.java`, { after: `public class MainActivity extends ReactActivity {`, insert: '\n @Override\n' + ' protected ReactActivityDelegate createReactActivityDelegate() {\n' + ' return new ReactActivityDelegate(this, getMainComponentName()) {\n' + ' @Override\n' + ' protected ReactRootView createRootView() {\n' + ' return new RNGestureHandlerEnabledRootView(MainActivity.this);\n' + ' }\n' + ' };\n' + ' }' }) if (answers['vector-icons'] === 'react-native-vector-icons') { await system.spawn(`ignite add vector-icons@1.1.1 ${debugFlag}`, { stdio: 'inherit' }) } if (answers['i18n'] === 'react-native-i18n') { await system.spawn(`ignite add i18n@1.2.0 ${debugFlag}`, { stdio: 'inherit' }) } if (answers['animatable'] === 'react-native-animatable') { await system.spawn(`ignite add animatable@1.0.2 ${debugFlag}`, { stdio: 'inherit' }) } // dev-screens be installed after vector-icons and animatable so that it can // conditionally patch its PluginExamplesScreen if (answers['dev-screens'] === 'Yes') { await system.spawn(`ignite add dev-screens@"2.4.3" ${debugFlag}`, { stdio: 'inherit' }) } if (answers['redux-persist'] === 'Yes') { await system.spawn(`ignite add redux-persist@1.1.2 ${debugFlag}`, { stdio: 'inherit' }) } if (parameters.options.lint !== 'false') { await system.spawn(`ignite add standard@1.0.0 ${debugFlag}`, { stdio: 'inherit' }) } } catch (e) { ignite.log(e) throw e } const perfDuration = parseInt(((new Date()).getTime() - perfStart) / 10) / 100 spinner.succeed(`ignited ${yellow(name)} in ${perfDuration}s`) const androidInfo = isAndroidInstalled(context) ? '' : `\n\nTo run in Android, make sure you've followed the latest react-native setup instructions at https://facebook.github.io/react-native/docs/getting-started.html before using ignite.\nYou won't be able to run ${bold('react-native run-android')} successfully until you have.` const successMessage = ` ${red('Ignite CLI')} ignited ${yellow(name)} in ${gray(`${perfDuration}s`)} To get started: cd ${name} react-native run-ios react-native run-android${androidInfo} ignite --help ${gray('Read the walkthrough at https://github.com/infinitered/ignite-andross/blob/master/readme.md#boilerplate-walkthrough')} ${blue('Need additional help? Join our Slack community at http://community.infinite.red.')} ${bold('Now get cooking! 🍽')} ` print.info(successMessage) } module.exports = { install }