Skip to content

Commit bd0658f

Browse files
authored
Merge pull request #225 from developit/feature/yarn-support
feature: yarn support. You can use yarn by `preact create test --yarn`
2 parents 04cf79b + a0624ef commit bd0658f

File tree

5 files changed

+99
-31
lines changed

5 files changed

+99
-31
lines changed

src/commands/create.js

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import promisify from 'es6-promisify';
99
import spawn from 'cross-spawn-promise';
1010
import path from 'path';
1111
import which from 'which';
12+
import { install, initialize, pkgScripts } from './../lib/setup';
1213

1314
const TEMPLATES = {
1415
full: 'examples/full',
@@ -44,6 +45,11 @@ export default asyncCommand({
4445
],
4546
default: 'full'
4647
},
48+
yarn: {
49+
description: "Use 'yarn' instead of 'npm'",
50+
type: 'boolean',
51+
default: false
52+
},
4753
less: {
4854
description: 'Pre-install LESS support',
4955
type: 'boolean',
@@ -126,18 +132,11 @@ export default asyncCommand({
126132

127133
spinner.text = 'Initializing project';
128134

129-
await npm(target, ['init', '-y']);
135+
await initialize(argv.yarn, target);
130136

131137
let pkg = JSON.parse(await fs.readFile(path.resolve(target, 'package.json')));
132138

133-
pkg.scripts = {
134-
...(pkg.scripts || {}),
135-
start: 'if-env NODE_ENV=production && npm run -s serve || npm run -s dev',
136-
build: 'preact build',
137-
serve: 'preact build && preact serve',
138-
dev: 'preact watch',
139-
test: 'eslint src && preact test'
140-
};
139+
pkg.scripts = await pkgScripts(argv.yarn, pkg);
141140

142141
try {
143142
await fs.stat(path.resolve(target, 'src'));
@@ -155,8 +154,7 @@ export default asyncCommand({
155154
if (argv.install) {
156155
spinner.text = 'Installing dev dependencies';
157156

158-
await npm(target, [
159-
'install', '--save-dev',
157+
await install(argv.yarn, target, [
160158
'preact-cli',
161159
'if-env',
162160
'eslint',
@@ -179,12 +177,11 @@ export default asyncCommand({
179177
'stylus',
180178
'stylus-loader'
181179
] : [])
182-
].filter(Boolean));
180+
], 'dev');
183181

184182
spinner.text = 'Installing dependencies';
185183

186-
await npm(target, [
187-
'install', '--save',
184+
await install(argv.yarn, target, [
188185
'preact',
189186
'preact-compat',
190187
'preact-router'
@@ -202,21 +199,19 @@ export default asyncCommand({
202199
\u001b[32mcd ${path.relative(process.cwd(), target)}\u001b[39m
203200
204201
To start a development live-reload server:
205-
\u001b[32mnpm start\u001b[39m
202+
\u001b[32m${argv.yarn === true ? 'yarnpkg start' : 'npm start'}\u001b[39m
206203
207204
To create a production build (in ./build):
208-
\u001b[32mnpm run build\u001b[39m
205+
\u001b[32m${argv.yarn === true ? 'yarnpkg build' : 'npm run build'}\u001b[39m
209206
210207
To start a production HTTP/2 server:
211-
\u001b[32mnpm run serve\u001b[39m
208+
\u001b[32m${argv.yarn === true ? 'yarnpkg serve' : 'npm run serve'}\u001b[39m
212209
`) + '\n';
213210
}
214211
});
215212

216213
const trimLeft = (string) => string.trim().replace(/^\t+/gm, '');
217214

218-
const npm = (cwd, args) => spawn('npm', args, { cwd, stdio: 'ignore' });
219-
220215
// Initializes the folder using `git init` and a proper `.gitignore` file
221216
// if `git` is present in the $PATH.
222217
async function initializeVersionControl(target) {

src/lib/setup.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import path from 'path';
2+
import fs from 'fs.promised';
3+
import spawn from 'cross-spawn-promise';
4+
import { commandExists } from './shell';
5+
6+
const initialize = async (yarn, cwd) => {
7+
let isYarnAvailable = await commandExists('yarn');
8+
9+
if (isYarnAvailable && yarn) {
10+
return await spawn('yarn', ['init', '-y'], { cwd, stdio: 'ignore' });
11+
}
12+
13+
await spawn('npm', ['init', '-y'], { cwd, stdio: 'ignore' });
14+
};
15+
16+
const install = async (yarn, cwd, packages, env) => {
17+
let isDev = env === 'dev' ? true : false;
18+
let isYarnAvailable = await commandExists('yarn');
19+
let toInstall = packages.filter(Boolean);
20+
21+
// pass null to use yarn only if yarn.lock is present
22+
if (!yarn) {
23+
try { yarn = await fs.stat(path.resolve(cwd, 'yarn.lock')).isFile(); }
24+
catch (e) { yarn = false; }
25+
}
26+
27+
if (isYarnAvailable && yarn) {
28+
let args = ['add'];
29+
if (isDev) {
30+
args.push('-D');
31+
}
32+
33+
return await spawn('yarn', [...args, ...toInstall], { cwd, stdio: 'ignore' });
34+
}
35+
36+
await spawn('npm', ['install', isDev ? '--save-dev' : '--save', ...toInstall], { cwd, stdio: 'ignore' });
37+
};
38+
39+
const pkgScripts = async (yarn, pkg) => {
40+
let isYarnAvailable = await commandExists('yarn');
41+
42+
if (isYarnAvailable && yarn) {
43+
return {
44+
...(pkg.scripts || {}),
45+
start: 'if-env NODE_ENV=production && yarnpkg -s serve || yarnpkg -s dev',
46+
build: 'preact build',
47+
serve: 'preact build && preact serve',
48+
dev: 'preact watch',
49+
test: 'eslint src && preact test'
50+
};
51+
}
52+
53+
return {
54+
...(pkg.scripts || {}),
55+
start: 'if-env NODE_ENV=production && npm run -s serve || npm run -s dev',
56+
build: 'preact build',
57+
serve: 'preact build && preact serve',
58+
dev: 'preact watch',
59+
test: 'eslint src && preact test'
60+
};
61+
};
62+
63+
export { install, initialize, pkgScripts };

src/lib/shell.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import promisify from 'es6-promisify';
2+
import which from 'which';
3+
4+
const commandExists = async cmd => {
5+
try {
6+
await promisify(which)(cmd);
7+
return true;
8+
} catch (e){
9+
return false;
10+
}
11+
};
12+
13+
export { commandExists };

src/lib/webpack/npm-install-loader.js renamed to src/lib/webpack/dependency-install-loader.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import loaderUtils from 'loader-utils';
22
import fs from 'fs';
3-
import spawn from 'cross-spawn-promise';
3+
import path from 'path';
4+
import { install } from './../setup';
45

56
/**
67
* This is a pass-through loader that runs `npm install --save` for the specified dependencies when invoked.
78
* Chain it before loaders to conditionally install them on first use.
89
* Quickly checks if any modules are alread installed and skips them.
910
* @param {object} options
10-
* @param {boolean|string} [options.save=false] If `true`, runs `npm i --save`. If `"dev"`, runs `npm i --save-dev`.
11-
* @param {Array<String>|String} modules A list of modules to install.
11+
* @param {boolean|string} [options.save=false] If `true`, runs `npm i --save`. If `"dev"`, runs `npm i --save-dev`.
12+
* @param {Array<String>|String} modules A list of modules to install.
1213
*
1314
* @example // Install and use less-loader and less when encountering `.less` files:
1415
*
@@ -30,19 +31,15 @@ const CACHE = {};
3031

3132
function isInstalled(dep) {
3233
return CACHE[dep] || (CACHE[dep] = new Promise( resolve => {
33-
fs.stat(resolve('node_modules', dep), err => {
34+
fs.stat(path.resolve('node_modules', dep), err => {
3435
resolve(!err);
3536
});
3637
}));
3738
}
3839

3940
function installDeps(deps, save) {
4041
process.stdout.write(`\nInstalling ${deps.join(' ')}..`);
41-
return spawn('npm', [
42-
'install', save && (save==='dev' ? '--save-dev' : '--save'),
43-
'--prefix', process.cwd(),
44-
...deps
45-
].filter(Boolean)).then( () => {
42+
return install(false, process.cwd(), deps, save).then( () => {
4643
process.stdout.write(` ..${deps.length} installed.\n`);
4744
});
4845
}

src/lib/webpack/webpack-base-config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export default (env) => {
109109
test: /\.less$/,
110110
use: [
111111
{
112-
loader: resolve(__dirname, './npm-install-loader'),
112+
loader: resolve(__dirname, './dependency-install-loader'),
113113
options: {
114114
modules: ['less', 'less-loader'],
115115
save: true
@@ -126,7 +126,7 @@ export default (env) => {
126126
test: /\.s[ac]ss$/,
127127
use: [
128128
{
129-
loader: resolve(__dirname, './npm-install-loader'),
129+
loader: resolve(__dirname, './dependency-install-loader'),
130130
options: {
131131
modules: ['node-sass', 'sass-loader'],
132132
save: true
@@ -143,7 +143,7 @@ export default (env) => {
143143
test: /\.styl$/,
144144
use: [
145145
{
146-
loader: resolve(__dirname, './npm-install-loader'),
146+
loader: resolve(__dirname, './dependency-install-loader'),
147147
options: {
148148
modules: ['stylus', 'stylus-loader'],
149149
save: true

0 commit comments

Comments
 (0)