Skip to content

Commit

Permalink
Auto-install peerDependencies (#622)
Browse files Browse the repository at this point in the history
* Auto-install peerDependencies on local require

* Install all peer dependencies at once

* Minor clean up
  • Loading branch information
brandon93s authored and devongovett committed Jan 29, 2018
1 parent deba5ef commit 93315f2
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 8 deletions.
50 changes: 43 additions & 7 deletions src/utils/installPackage.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const spawn = require('cross-spawn');
const config = require('./config');
const path = require('path');
const promisify = require('./promisify');
const resolve = promisify(require('resolve'));

module.exports = async function(dir, name) {
async function install(dir, modules, installPeers = true) {
let location = await config.resolve(dir, ['yarn.lock', 'package.json']);

return new Promise((resolve, reject) => {
Expand All @@ -12,19 +14,53 @@ module.exports = async function(dir, name) {
};

if (location && path.basename(location) === 'yarn.lock') {
install = spawn('yarn', ['add', name, '--dev'], options);
install = spawn('yarn', ['add', ...modules, '--dev'], options);
} else {
install = spawn('npm', ['install', name, '--save-dev'], options);
install = spawn('npm', ['install', ...modules, '--save-dev'], options);
}

install.stdout.pipe(process.stdout);
install.stderr.pipe(process.stderr);

install.on('close', code => {
install.on('close', async code => {
if (code !== 0) {
return reject(new Error(`Failed to install ${name}.`));
return reject(new Error(`Failed to install ${modules.join(', ')}.`));
}
return resolve();

if (!installPeers) {
return resolve();
}

try {
await Promise.all(modules.map(m => installPeerDependencies(dir, m)));
} catch (err) {
return reject(
new Error(
`Failed to install peerDependencies for ${modules.join(', ')}.`
)
);
}

resolve();
});
});
};
}

async function installPeerDependencies(dir, name) {
let basedir = path.dirname(dir);

const [resolved] = await resolve(name, {basedir});
const pkg = await config.load(resolved, ['package.json']);
const peers = pkg.peerDependencies || {};

const modules = [];
for (const peer in peers) {
modules.push(`${peer}@${peers[peer]}`);
}

if (modules.length) {
await install(dir, modules, false);
}
}

module.exports = install;
2 changes: 1 addition & 1 deletion src/utils/localRequire.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async function localRequire(name, path, triedInstall = false) {
resolved = resolve.sync(name, {basedir});
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND' && !triedInstall) {
await install(path, name);
await install(path, [name]);
return localRequire(name, path, true);
}
throw e;
Expand Down
6 changes: 6 additions & 0 deletions test/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ describe('css', function() {
let package = require('./input/package.json');
assert(package.devDependencies['postcss-cssnext']);

// peer dependency caniuse-lite was installed
assert(package.devDependencies['caniuse-lite']);

// cssnext is applied
let css = fs.readFileSync(__dirname + '/dist/index.css', 'utf8');
assert(css.includes('rgba'));
Expand All @@ -217,6 +220,9 @@ describe('css', function() {
let package = require('./input/package.json');
assert(package.devDependencies['postcss-cssnext']);

// peer dependency caniuse-lite was installed
assert(package.devDependencies['caniuse-lite']);

// appveyor is not currently writing to the yarn.lock file and will require further investigation
// let lockfile = fs.readFileSync(__dirname + '/input/yarn.lock', 'utf8');
// assert(lockfile.includes('postcss-cssnext'));
Expand Down

0 comments on commit 93315f2

Please sign in to comment.