UNPKG

nwb

Version:

A toolkit for React, Preact & Inferno apps, React libraries and other npm modules for the web, with no configuration (until you need it)

287 lines (236 loc) 8.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getNpmModulePrefs = getNpmModulePrefs; exports.validateProjectType = validateProjectType; exports.default = createProject; var _child_process = require("child_process"); var _fs = _interopRequireDefault(require("fs")); var _path = _interopRequireDefault(require("path")); var _chalk = _interopRequireDefault(require("chalk")); var _copyTemplateDir = _interopRequireDefault(require("copy-template-dir")); var _inquirer = _interopRequireDefault(require("inquirer")); var _ora = _interopRequireDefault(require("ora")); var _runSeries = _interopRequireDefault(require("run-series")); var _constants = require("./constants"); var _errors = require("./errors"); var _package = _interopRequireDefault(require("../package.json")); var _utils = require("./utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // TODO Change if >= 1.0.0 ever happens const NWB_VERSION = _package.default.version.split('.').slice(0, 2).concat('x').join('.'); /** * Copy a project template and log created files if successful. */ function copyTemplate(templateDir, targetDir, templateVars, cb) { (0, _copyTemplateDir.default)(templateDir, targetDir, templateVars, (err, createdFiles) => { if (err) return cb(err); createdFiles.sort().forEach(createdFile => { let relativePath = _path.default.relative(targetDir, createdFile); console.log(` ${_chalk.default.green('create')} ${relativePath}`); }); cb(); }); } /** * Prompt the user for preferences related to publishing a module to npm, unless * they've asked us not to or have already provided all the possible options via * arguments. */ function getNpmModulePrefs(args, cb) { // An ES modules build is enabled by default, but can be disabled with // --no-es-modules or --es-modules=false (or a bunch of other undocumented // stuff) let esModules = args['es-modules'] !== false && !/^(0|false|no|nope|off)$/.test(args['es-modules']); // Pass a UMD global variable name with --umd=MyThing, or pass --no-umd to // indicate you don't want a UMD build. let umd = (0, _utils.typeOf)(args.umd) === 'string' ? args.umd : false; // Don't ask questions if the user doesn't want them, or already told us all // the answers. if (args.f || args.force || 'umd' in args && 'es-modules' in args) { return process.nextTick(cb, null, { umd, esModules }); } _inquirer.default.prompt([{ when: () => !('es-modules' in args), type: 'confirm', name: 'esModules', message: 'Do you want to create an ES modules build for use by compatible bundlers?', default: esModules }, { when: () => !('umd' in args), type: 'confirm', name: 'createUMD', message: 'Do you want to create a UMD build for global usage via <script> tag?', default: umd }, { when: ({ createUMD }) => createUMD, type: 'input', name: 'umd', message: 'Which global variable should the UMD build set?', validate(input) { return input.trim() ? true : 'Required to create a UMD build'; }, default: umd || '' }]).then(answers => cb(null, answers), err => cb(err)); } /** * Initialise a Git repository if the user has Git, unless there's already one * present or the user has asked us could we not. */ function initGit(args, cwd, cb) { // Allow git init to be disabled with a --no-git flag if (args.git === false) { return process.nextTick(cb); } // Bail if a git repo already exists (e.g. nwb init in an existing repo) if ((0, _utils.directoryExists)(_path.default.join(cwd, '.git'))) { return process.nextTick(cb); } (0, _child_process.exec)('git --version', { cwd, stdio: 'ignore' }, err => { if (err) return cb(); let spinner = (0, _ora.default)('Initing Git repo').start(); (0, _runSeries.default)([cb => (0, _child_process.exec)('git init', { cwd }, cb), cb => (0, _child_process.exec)('git add .', { cwd }, cb), cb => (0, _child_process.exec)(`git commit -m "Initial commit from nwb v${_package.default.version}"`, { cwd }, cb)], err => { if (err) { spinner.fail(); console.log(_chalk.default.red(err.message)); return cb(); } spinner.succeed(); cb(); }); }); } /** * Validate a user-supplied project type. */ function validateProjectType(projectType) { if (!projectType) { throw new _errors.UserError(`A project type must be provided, one of: ${Array.from(_constants.PROJECT_TYPES).join(', ')}`); } if (!_constants.PROJECT_TYPES.has(projectType)) { throw new _errors.UserError(`Project type must be one of: ${Array.from(_constants.PROJECT_TYPES).join(', ')}`); } } /** * Write an nwb config file. */ function writeConfigFile(dir, config, cb) { _fs.default.writeFile(_path.default.join(dir, _constants.CONFIG_FILE_NAME), `module.exports = ${(0, _utils.toSource)(config)}\n`, cb); } const MODULE_PROJECT_CONFIG = { [_constants.REACT_COMPONENT]: { devDependencies: ['react', 'react-dom'], externals: { react: 'React' } }, [_constants.WEB_MODULE]: {} }; /** * Create an app project skeleton. */ function createAppProject(args, projectType, name, targetDir, cb) { let appType = projectType.split('-')[0]; let projectConfig = require(`./${appType}`)(args); let dependencies = null; let tasks = [cb => { let templateDir = _path.default.join(__dirname, `../templates/${projectType}`); let templateVars = { name, nwbVersion: NWB_VERSION }; copyTemplate(templateDir, targetDir, templateVars, cb); }, cb => { // Allow specification of the exact version, e.g. --react=16.2 if (dependencies.length !== 0 && args[appType]) { dependencies = dependencies.map(pkg => `${pkg}@${args[appType]}`); } (0, _utils.install)(dependencies, { cwd: targetDir, save: true }, cb); }, cb => initGit(args, targetDir, cb)]; let questions = projectConfig.getProjectQuestions(); if (questions) { // Don't ask questions if the user doesn't want them if (args.f || args.force) { dependencies = projectConfig.getProjectDependencies(projectConfig.getProjectDefaults()); } else { tasks.unshift(cb => { _inquirer.default.prompt(questions).then(answers => { dependencies = projectConfig.getProjectDependencies(answers); cb(null); }, err => cb(err)); }); } } else { dependencies = projectConfig.getProjectDependencies(); } (0, _runSeries.default)(tasks, cb); } /** * Create an npm module project skeleton. */ function createModuleProject(args, projectType, name, targetDir, cb) { let { devDependencies = [], externals = {} } = MODULE_PROJECT_CONFIG[projectType]; getNpmModulePrefs(args, (err, prefs) => { if (err) return cb(err); let { umd, esModules } = prefs; let templateDir = _path.default.join(__dirname, `../templates/${projectType}`); let templateVars = { name, esModules, esModulesPackageConfig: esModules ? '\n "module": "es/index.js",' : '', nwbVersion: NWB_VERSION }; let nwbConfig = { type: projectType, npm: { esModules, umd: umd ? { global: umd, externals } : false } }; // CBA making this part generic until it's needed if (projectType === _constants.REACT_COMPONENT) { if (args.react) { devDependencies = devDependencies.map(pkg => `${pkg}@${args.react}`); templateVars.reactPeerVersion = `^${args.react}`; // YOLO } else { // TODO Get from npm so we don't have to manually update on major releases templateVars.reactPeerVersion = '16.x'; } } (0, _runSeries.default)([cb => copyTemplate(templateDir, targetDir, templateVars, cb), cb => writeConfigFile(targetDir, nwbConfig, cb), cb => (0, _utils.install)(devDependencies, { cwd: targetDir, save: true, dev: true }, cb), cb => initGit(args, targetDir, cb)], cb); }); } function createProject(args, projectType, name, dir, cb) { if (/-app$/.test(projectType)) { return createAppProject(args, projectType, name, dir, cb); } else { createModuleProject(args, projectType, name, dir, cb); } }