Donmclean/riko

View on GitHub
src/actions/run.js

Summary

Maintainability
A
0 mins
Test Coverage
import { processExitHandler, assignEnvironmentVariablesBasedOnRunCommand, doRunCommandValidations, validateRikoConfig,
    logElectronRunServerError, removeDir, genericLog, checkForNewPackageVersion, getElectronPackagerOptions,
    applyWebpackEventHooks, getDefaultStats } from '../utils/functions';
import { cwd, baseDir } from '../utils/variables';
import fs from 'fs-extra';
import os from 'os';
import path from 'path';
import { find } from 'lodash';
import { runCommands } from '../constants';
import spawn from 'cross-spawn';
const spawnSync = spawn.sync;

export default async (runCommand) => {
    //add exit handler
    processExitHandler();

    checkForNewPackageVersion();

    //assign environment variables
    assignEnvironmentVariablesBasedOnRunCommand(runCommands, runCommand);

    doRunCommandValidations();

    const { rikoConfig, config} = await import('../utils/coreRikoConfig').then((m) => m.default);

    validateRikoConfig(rikoConfig, runCommand);

    //TODO: extract these cases in functional components
    switch (runCommand) {
        case 'electron-server': {
            process.env.NODE_ENV = 'production';
            const { webpackConfig } = rikoConfig.setWebpackConfig('electron');
            let electronDistfiles;

            try {
                const electronPackagerOptions = getElectronPackagerOptions(rikoConfig.setElectronPackagerOptions(), webpackConfig, config);
                electronDistfiles = await fs.readdir(electronPackagerOptions.out);

                switch (os.platform()) {
                    case 'darwin': {
                        //handles open electron app on MAC
                        const macFile = find(electronDistfiles, (file) => file.match(/\b(darwin)\b/i));

                        if(macFile && electronPackagerOptions) {
                            spawn('open', [`-a`, `${cwd}/${path.basename(electronPackagerOptions.out)}/${macFile}/${electronPackagerOptions.name}.app`], {stdio: 'inherit'});
                        } else {
                            logElectronRunServerError();
                        }

                        break;
                    }
                    //TODO: add support for more os platforms like: Windows, Linux.
                    default: {
                        break;
                    }
                }

            } catch (err) {
                logElectronRunServerError();
                console.error(`ERROR > error reading electronPackagerOptions out path`, err);
            }

            break;
        }
        case 'react-prod': {
            const { webpack, webpackConfig, statsOptions = {} } = rikoConfig.setWebpackConfig('web');

            const webpackEventHooks = rikoConfig.setWebpackEventHooks(process.env.NODE_ENV);

            const compiler = applyWebpackEventHooks(webpackEventHooks, webpack(webpackConfig));

            return compiler.run((err, stats) => {
                if(err) {
                    console.error('ERROR > webpack compilation > : ', err);
                } else {
                    process.stdout.write(stats.toString(Object.assign({}, getDefaultStats(process.env.NODE_ENV), statsOptions)) + "\n");
                }
            });
        }
        case 'electron-prod': {
            const { webpack, webpackConfig } = rikoConfig.setWebpackConfig('electron');
            const electronPackagerOptions = getElectronPackagerOptions(rikoConfig.setElectronPackagerOptions(), webpackConfig, config);

            if(JSON.parse(process.env.isElectron) && electronPackagerOptions) {
                const electronPackager = await import('electron-packager');
                const createDMG = await import('electron-installer-dmg');

                genericLog('Compiling js build assets...');

                return webpack(webpackConfig, (err, stats) => {
                    if(err) {
                        console.error('ERROR: ', err);
                    } else {
                        process.stdout.write(stats.toString() + "\n");

                        //Compile The Electron Application
                        genericLog('Compiling electron app...');
                        electronPackager(electronPackagerOptions, async (err) => {
                            if(err) {
                                console.error('ERROR > electronPackager > in electron build', err);
                                throw err;
                            } else {
                                //build is targeting mac platform
                                const isTargetingMacPlatform = (electronPackagerOptions.platform === 'all' || electronPackagerOptions.platform === 'darwin');

                                if(isTargetingMacPlatform) {
                                    const electronDistfiles = await fs.readdir(electronPackagerOptions.out);
                                    const macFile = find(electronDistfiles, (file) => file.match(/\b(darwin)\b/i));

                                    const dmgOptions = {
                                        name: electronPackagerOptions.name,
                                        appPath: `${cwd}/${path.basename(electronPackagerOptions.out)}/${macFile}/${electronPackagerOptions.name}.app`,
                                        debug: true,
                                        overwrite: true,
                                        out: electronPackagerOptions.out,
                                        icon: electronPackagerOptions.icon
                                    };

                                    createDMG(dmgOptions, (err) => {
                                        if(err) {
                                            console.error('ERROR > createDMG > in electron build', err);
                                            throw err;
                                        }
                                        genericLog(`DMG for ${electronPackagerOptions.name} built successfully!`);
                                        removeDir(config.tempDir).then(() => {
                                            genericLog(`${electronPackagerOptions.name} built successfully!`);
                                        });
                                    });
                                } else {
                                    removeDir(config.tempDir).then(() => {
                                        genericLog(`${electronPackagerOptions.name} built successfully!`);
                                    });
                                }
                            }
                        });
                    }
                });
            } else if(!electronPackagerOptions) {
                genericLog(`ERROR: no electronPackagerOptions object is undefined port number... `, 'red');
            } else {
                genericLog('ERROR: internal riko error occured... Please report issue', 'red');
            }

            break;
        }
        case 'react-native-ios': {
            return spawn('react-native', ['run-ios'], {stdio: 'inherit'});
        }
        case 'react-native-launch-android': {
            genericLog('launching android emulator...', 'blue');
            return spawn(`sh`, [`${cwd}/launch-android-Emulator.sh`, '&'], {stdio: 'ignore'});
        }
        case 'react-native-android': {
            return spawnSync('react-native', ['run-android'], {stdio: 'inherit'});
        }
        case 'electron-dev':
        case 'react-dev': {
            //*******************************************************************
            //HOT RELOADING WITH WEBPACK DEV SERVER
            //*******************************************************************

            const rikoConfigWebpackValues = rikoConfig.setWebpackConfig('web');
            const { webpack, webpackConfig, webpackDevServer } = rikoConfigWebpackValues;

            const webpackEventHooks = rikoConfig.setWebpackEventHooks(process.env.NODE_ENV);

            config.SERVER_PORT = webpackConfig.devServer.port ? webpackConfig.devServer.port : config.SERVER_PORT;

            if(config.SERVER_PORT) {
                //apply webpackEventHooks
                const compiler = applyWebpackEventHooks(webpackEventHooks, webpack(webpackConfig));

                new webpackDevServer(compiler, webpackConfig.devServer).listen(config.SERVER_PORT, 'localhost', (err) => {
                    if (err) { console.error(err); }
                    genericLog(`Launching webpack devServer on ${config.SERVER_PORT}...`);
                });

            } else {
                genericLog('ERROR: missing port number... ', 'red');
                genericLog(`i.e: riko r ${runCommand} <port>`, 'red');
            }

            break;
        }
        case 'node-server-dev': {
            spawn(`${baseDir}/node_modules/.bin/nodemon`, ['--config', `${rikoConfig.nodemonJson}`, `${rikoConfig.entryFile}`], {stdio: 'inherit'});
            break;
        }
        case 'node-server-prod': {
            spawn('node', [`${rikoConfig.entryFile}`], {stdio: 'inherit'});
            break;
        }
        case 'react-server':
        case 'react-prod-server': {
            const browserSync   = require('browser-sync');
            const morgan        = require('morgan');
            const fallback      = require('express-history-api-fallback');
            const express       = require('express');
            const app           = express();

            app.use(morgan('dev'));

            const { webpackConfig } = rikoConfig.setWebpackConfig('web');

            const customRootToBeServed = process.argv[5];
            const root = customRootToBeServed ? path.resolve(cwd, customRootToBeServed) : webpackConfig.output.path;

            app.use(express.static(root));
            app.use(fallback('index.html', { root }));

            if(config.SERVER_PORT) {
                app.listen(config.SERVER_PORT);

                app.use((err, req, res, next) => {
                    genericLog(`ERROR --> : ${err.stack}`);
                    next(err);
                });

                const isProdServer = (runCommand === 'react-prod-server');

                if(isProdServer) {
                    genericLog('Listening on port: ' + config.SERVER_PORT, 'yellow');
                } else {
                    genericLog('Launching Browser Sync proxy of port: ' + config.SERVER_PORT, 'yellow');

                    browserSync.init({
                        proxy: `localhost:${config.SERVER_PORT}`,
                        port: config.SERVER_PORT
                    });
                }
            } else {
                genericLog('ERROR: missing port number... ', 'red');
                genericLog(`i.e: riko r ${runCommand} <port>`, 'red');
            }

            break;
        }
        default: {
            break;
        }
    }
};