diff --git a/src/commands/create.js b/src/commands/create.js index 58dbc3289..fc40631f8 100644 --- a/src/commands/create.js +++ b/src/commands/create.js @@ -6,6 +6,7 @@ import ora from 'ora'; import promisify from 'es6-promisify'; import spawn from 'cross-spawn-promise'; import path from 'path'; +import install from '../lib/install-dependencies'; import which from 'which'; const TEMPLATES = { @@ -90,7 +91,7 @@ export default asyncCommand({ spinner.text = 'Initializing project'; - await npm(target, ['init', '-y']); + await spawn('npm', ['init', '-y'], { cwd: target, stdio: 'ignore' }); let pkg = JSON.parse(await fs.readFile(path.resolve(target, 'package.json'))); @@ -119,8 +120,7 @@ export default asyncCommand({ if (argv.install) { spinner.text = 'Installing dev dependencies'; - await npm(target, [ - 'install', '--save-dev', + await install(target, [ 'preact-cli', 'if-env', 'eslint', @@ -137,12 +137,11 @@ export default asyncCommand({ 'less', 'less-loader' ] : []) - ].filter(Boolean)); + ], 'dev'); spinner.text = 'Installing dependencies'; - await npm(target, [ - 'install', '--save', + await install(target, [ 'preact', 'preact-compat', 'preact-router' diff --git a/src/lib/npm-install-loader.js b/src/lib/dependency-install-loader.js similarity index 87% rename from src/lib/npm-install-loader.js rename to src/lib/dependency-install-loader.js index eff91b406..acbb39acd 100644 --- a/src/lib/npm-install-loader.js +++ b/src/lib/dependency-install-loader.js @@ -1,6 +1,7 @@ import loaderUtils from 'loader-utils'; import fs from 'fs'; -import spawn from 'cross-spawn-promise'; +import path from 'path'; +import install from './install-dependencies'; /** * This is a pass-through loader that runs `npm install --save` for the specified dependencies when invoked. @@ -30,7 +31,7 @@ const CACHE = {}; function isInstalled(dep) { return CACHE[dep] || (CACHE[dep] = new Promise( resolve => { - fs.stat(resolve('node_modules', dep), err => { + fs.stat(path.resolve('node_modules', dep), err => { resolve(!err); }); })); @@ -38,11 +39,7 @@ function isInstalled(dep) { function installDeps(deps, save) { process.stdout.write(`\nInstalling ${deps.join(' ')}..`); - return spawn('npm', [ - 'install', save && (save==='dev' ? '--save-dev' : '--save'), - '--prefix', process.cwd(), - ...deps - ].filter(Boolean)).then( () => { + return install(process.cwd(), deps, save).then(() => { process.stdout.write(` ..${deps.length} installed.\n`); }); } diff --git a/src/lib/install-dependencies.js b/src/lib/install-dependencies.js new file mode 100644 index 000000000..94043e8aa --- /dev/null +++ b/src/lib/install-dependencies.js @@ -0,0 +1,21 @@ +import spawn from 'cross-spawn-promise'; +import { commandExists } from './shell'; + +const install = async (cwd, packages, env) => { + let isDev = env === 'dev' ? true : false; + let isYarnAvailable = await commandExists('yarn'); + let toInstall = packages.filter(Boolean); + + if (isYarnAvailable) { + let args = ['add']; + if (isDev) { + args.push('-D'); + } + + return await spawn('yarn', [...args, ...toInstall], { cwd, stdio: 'ignore' }); + } + + await spawn('npm', ['install', isDev ? '--save-dev' : '--save', ...toInstall], { cwd, stdio: 'ignore' }); +}; + +export default install; diff --git a/src/lib/run-webpack.js b/src/lib/run-webpack.js index 951d4f856..7928fd366 100644 --- a/src/lib/run-webpack.js +++ b/src/lib/run-webpack.js @@ -58,7 +58,7 @@ export function showStats(stats) { return stats; } -export function writeJsonStats(stats) { +export async function writeJsonStats(stats) { const outputPath = resolve(process.cwd(), 'stats.json'); const jsonStats = stats.toJson({ json: true, @@ -69,13 +69,12 @@ export function writeJsonStats(stats) { jsonStats.modules.forEach(normalizeModule); jsonStats.chunks.forEach(c => c.modules.forEach(normalizeModule)); - return fs.writeFile(outputPath, JSON.stringify(jsonStats)) - .then(() => { - process.stdout.write('\nWebpack output stats generated.\n\n'); - process.stdout.write('You can upload your stats.json to:\n'); - process.stdout.write('- https://chrisbateman.github.io/webpack-visualizer/\n'); - process.stdout.write('- https://webpack.github.io/analyse/\n'); - }); + await fs.writeFile(outputPath, JSON.stringify(jsonStats)); + + process.stdout.write('\nWebpack output stats generated.\n\n'); + process.stdout.write('You can upload your stats.json to:\n'); + process.stdout.write('- https://chrisbateman.github.io/webpack-visualizer/\n'); + process.stdout.write('- https://webpack.github.io/analyse/\n'); } const normalizeModule = m => { diff --git a/src/lib/shell.js b/src/lib/shell.js new file mode 100644 index 000000000..b7cdc7380 --- /dev/null +++ b/src/lib/shell.js @@ -0,0 +1,13 @@ +import promisify from 'es6-promisify'; +import which from 'which'; + +const commandExists = async cmd => { + try { + await promisify(which)(cmd); + return true; + } catch (e){ + return false; + } +}; + +export { commandExists }; diff --git a/src/lib/webpack-config.js b/src/lib/webpack-config.js index e766f9eca..cdefa33c0 100644 --- a/src/lib/webpack-config.js +++ b/src/lib/webpack-config.js @@ -165,7 +165,7 @@ export default env => { test: /\.less$/, use: [ { - loader: resolve(__dirname, './npm-install-loader'), + loader: resolve(__dirname, './dependency-install-loader'), options: { modules: ['less', 'less-loader'], save: true @@ -182,7 +182,7 @@ export default env => { test: /\.s[ac]ss$/, use: [ { - loader: resolve(__dirname, './npm-install-loader'), + loader: resolve(__dirname, './dependency-install-loader'), options: { modules: ['node-sass', 'sass-loader'], save: true