Skip to content

Commit

Permalink
feat: support --no-optional on install process (#282)
Browse files Browse the repository at this point in the history
Don’t install optional dependencies.

like yarn does: https://yarnpkg.com/lang/en/docs/cli/install/#toc-yarn-install-ignore-optional
  • Loading branch information
fengmk2 committed Nov 22, 2018
1 parent 4166ccf commit 1c74e7d
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 24 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Options:
-d, --detail: show detail log of installation
--trace: show memory and cpu usages traces of installation
--ignore-scripts: ignore all preinstall / install and postinstall scripts during the installation
--no-optional: ignore optionalDependencies during the installation
--forbidden-licenses: forbit install packages which used these licenses
--engine-strict: refuse to install (or even consider installing) any package that claims to not be compatible with the current Node.js version.
--flatten: flatten dependencies by matching ancestors dependencies
Expand Down
7 changes: 7 additions & 0 deletions bin/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const argv = parseArgs(orignalArgv, {
'save-exact',
'china',
'ignore-scripts',
// install ignore optionalDependencies
'optional',
'detail',
'trace',
'engine-strict',
Expand All @@ -58,6 +60,9 @@ const argv = parseArgs(orignalArgv, {
// please don't use on frontend project
'disable-dedupe',
],
default: {
optional: true,
},
alias: {
// npm install [-S|--save|-D|--save-dev|-O|--save-optional] [-E|--save-exact] [-d|--detail]
S: 'save',
Expand Down Expand Up @@ -109,6 +114,7 @@ Options:
-d, --detail: show detail log of installation
--trace: show memory and cpu usages traces of installation
--ignore-scripts: ignore all preinstall / install and postinstall scripts during the installation
--no-optional: ignore all optionalDependencies during the installation
--forbidden-licenses: forbit install packages which used these licenses
--engine-strict: refuse to install (or even consider installing) any package that claims to not be compatible with the current Node.js version.
--flatten: flatten dependencies by matching ancestors' dependencies
Expand Down Expand Up @@ -232,6 +238,7 @@ co(function* () {
};
config.strictSSL = getStrictSSL();
config.ignoreScripts = argv['ignore-scripts'] || getIgnoreScripts();
config.ignoreOptionalDependencies = !argv.optional;
config.detail = argv.detail;
config.trace = argv.trace;
config.engineStrict = argv['engine-strict'];
Expand Down
11 changes: 8 additions & 3 deletions lib/dependencies.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

module.exports = function dependencies(pkg) {
module.exports = function dependencies(pkg, options) {
const all = {};
const prod = {};
const client = {};
Expand Down Expand Up @@ -32,8 +32,13 @@ module.exports = function dependencies(pkg) {
}
// follow npm, optionalDependencies will rewrite dependencies
for (const name in optionalDependencies) {
all[name] = optionalDependencies[name];
prod[name] = optionalDependencies[name];
if (options.ignoreOptionalDependencies) {
delete all[name];
delete prod[name];
} else {
all[name] = optionalDependencies[name];
prod[name] = optionalDependencies[name];
}
}
for (const name in devDependencies) {
if (!all.hasOwnProperty(name)) {
Expand Down
2 changes: 1 addition & 1 deletion lib/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ function* _install(parentDir, pkg, ancestors, options) {
const bundledDependencies = yield getBundleDependencies(realPkg, realPkgDir);
yield bundledDependencies.map(name => bundleBin(name, realPkgDir, options));

const deps = dependencies(realPkg);
const deps = dependencies(realPkg, options);
const pkgs = deps.prod;
const pkgMaps = deps.prodMap;

Expand Down
11 changes: 7 additions & 4 deletions lib/local_install.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ function* _install(options) {
const rootPkg = yield utils.readJSON(rootPkgFile);
const displayName = `${rootPkg.name}@${rootPkg.version}`;
let pkgs = options.pkgs;
const rootPkgDependencies = dependencies(rootPkg);
const rootPkgDependencies = dependencies(rootPkg, options);
options.rootPkgDependencies = rootPkgDependencies;
if (pkgs.length === 0) {
if (options.production) {
Expand Down Expand Up @@ -147,9 +147,12 @@ function* _install(options) {
options.spinner && options.spinner.succeed(`Installed ${tasks.length} packages`);

if (!options.disableDedupe) {
// dedupe mode https://docs.npmjs.com/cli/dedupe
// link every packages' latest version to target directory
yield linkAllLatestVersion(rootPkgsMap, options);
// don't link latest versions on `npminstall pkgName` way
if (options.pkgs.length === 0) {
// dedupe mode https://docs.npmjs.com/cli/dedupe
// link every packages' latest version to target directory
yield linkAllLatestVersion(rootPkgsMap, options);
}
} else {
options.spinner && options.spinner.succeed('disable dedupe mode');
}
Expand Down
37 changes: 26 additions & 11 deletions test/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,36 @@ const semver = require('semver');
const spawn = require('child_process').spawn;
const npminstall = require('./npminstall');

if (semver.satisfies(process.version, '< 6.0.0')) {
process.exit(0);
}

const names = [
'express', 'koa', 'browserify',
'express',
'koa',
'browserify',
'pm2',
'grunt-cli',
'npm', 'karma',
'npm',
'karma',
'bower',
'coffee-script',
'gulp',
'forever',
'grunt', 'less',
'grunt',
'less',
'yo',
'lodash', 'bluebird', 'async', 'commander',
'q', 'request', 'debug', 'mkdirp', 'underscore', 'chalk', 'colors',
'lodash',
'bluebird',
'async',
'commander',
'q',
'request',
'debug',
'mkdirp',
'underscore',
'chalk',
'colors',
'webpack',
'antd',
'cnpm',
Expand Down Expand Up @@ -56,12 +73,10 @@ co(function* () {
detail: true,
});

if (semver.satisfies(process.version, '>= 6')) {
const installer = spawn('sh', [ path.join(__dirname, 'git-clone-install.sh') ], {
stdio: 'inherit',
});
installer.on('exit', code => process.exit(code));
}
const installer = spawn('sh', [ path.join(__dirname, 'git-clone-install.sh') ], {
stdio: 'inherit',
});
installer.on('exit', code => process.exit(code));
}).catch(err => {
console.error(err);
console.error(err.stack);
Expand Down
38 changes: 34 additions & 4 deletions test/dependencies.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('test/dependencies.test.js', () => {
},
};

const parsed = dependencies(pkg);
const parsed = dependencies(pkg, {});
assert.deepEqual(parsed.all, [
{ name: 'koa', version: '1', optional: false },
{ name: 'express', version: '2', optional: false },
Expand Down Expand Up @@ -49,7 +49,7 @@ describe('test/dependencies.test.js', () => {
},
};

const parsed = dependencies(pkg);
const parsed = dependencies(pkg, {});
assert.deepEqual(parsed.all, [
{ name: 'koa', version: '1', optional: false },
{ name: 'express', version: '3', optional: true },
Expand All @@ -66,6 +66,36 @@ describe('test/dependencies.test.js', () => {
assert.deepEqual(parsed.prodMap, { koa: '1', express: '3', hapi: '1' });
});

it('should ignore optionalDependencies', () => {
const pkg = {
dependencies: {
koa: '1',
express: '2',
},
devDependencies: {
connect: '3',
egg: '4',
koa: '5',
},
optionalDependencies: {
express: '3',
hapi: '1',
},
};

const parsed = dependencies(pkg, { ignoreOptionalDependencies: true });
assert.deepEqual(parsed.all, [
{ name: 'koa', version: '1', optional: false },
{ name: 'connect', version: '3', optional: false },
{ name: 'egg', version: '4', optional: false },
]);
assert.deepEqual(parsed.allMap, { koa: '1', connect: '3', egg: '4' });
assert.deepEqual(parsed.prod, [
{ name: 'koa', version: '1', optional: false },
]);
assert.deepEqual(parsed.prodMap, { koa: '1' });
});

it('should work with dependencies, devDependencies, clientDependencies, buildDependencies and isomorphicDependencies', () => {
const pkg = {
dependencies: {
Expand All @@ -90,7 +120,7 @@ describe('test/dependencies.test.js', () => {
},
};

const parsed = dependencies(pkg);
const parsed = dependencies(pkg, {});
assert.deepEqual(parsed.all, [
{ name: 'koa', version: '1', optional: false },
{ name: 'express', version: '2', optional: false },
Expand Down Expand Up @@ -166,7 +196,7 @@ describe('test/dependencies.test.js', () => {
};

try {
dependencies(pkg);
dependencies(pkg, {});
throw new Error('should not excute');
} catch (err) {
assert(err.message === `duplicate dependencies error, put isomorphic dependency into isomorphicDependencies:
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/ignore-optional/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "ignore-optional",
"dependencies": {
"pinyin": "2.8.3"
}
}
3 changes: 3 additions & 0 deletions test/fixtures/local-install-pkgs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "local-install-pkgs"
}
2 changes: 1 addition & 1 deletion test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ describe('test/index.test.js', () => {
yield npminstall({
root: tmp,
pkgs: [
{ name: 'chromedriver' },
{ name: 'chromedriver', version: '2.10.0' },
],
});
});
Expand Down
31 changes: 31 additions & 0 deletions test/install-ignore-optional.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const assert = require('assert');
const fs = require('fs');
const path = require('path');
const coffee = require('coffee');
const rimraf = require('rimraf');
const npminstall = path.join(__dirname, '..', 'bin', 'install.js');

describe('test/install-ignore-optional.test.js', () => {
let cwd;
function cleanup() {
cwd && rimraf.sync(path.join(cwd, 'node_modules'));
cwd = null;
}

before(() => cleanup());
after(() => cleanup());

it('should install ignore optionalDependencies', function* () {
cwd = path.join(__dirname, 'fixtures', 'ignore-optional');
yield coffee.fork(npminstall, [ '--no-optional', '--production', '-d' ], { cwd })
.debug()
.notExpect('stderr', /optional install error/)
.notExpect('stderr', /node-gyp rebuild/)
.expect('stdout', /pinyin@2.8.3 installed/)
.expect('code', 0)
.end();
assert(!fs.existsSync(path.join(cwd, 'node_modules/pinyin/node_modules/nodejieba')));
});
});
31 changes: 31 additions & 0 deletions test/local-install-pkgs.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const assert = require('assert');
const fs = require('fs');
const rimraf = require('rimraf');
const path = require('path');
const coffee = require('coffee');
const npminstall = path.join(__dirname, '..', 'bin', 'install.js');

describe('test/local-install-pkgs.test.js', () => {
const root = path.join(__dirname, 'fixtures', 'local-install-pkgs');

function cleanup() {
rimraf.sync(path.join(root, 'node_modules'));
}

beforeEach(cleanup);
afterEach(cleanup);

it('should install pkg and dont link latestVersions', function* () {
yield coffee.fork(npminstall, [ 'koa' ], { cwd: root })
.debug()
.expect('code', 0)
.notExpect('stdout', /Linked \d+ latest versions/)
.end();
const names = fs.readdirSync(path.join(root, 'node_modules'))
.filter(n => !/^[\.\_]/.test(n));
assert(names.length === 1);
assert(names[0] === 'koa');
});
});

0 comments on commit 1c74e7d

Please sign in to comment.