From 88f104626c947b38fad5dd00647eda69ca0261d9 Mon Sep 17 00:00:00 2001 From: Stanislav Sysoev Date: Wed, 28 Feb 2018 21:57:01 +1100 Subject: [PATCH] feat: Added --ignore flag to exclude modules from output --- cli.js | 3 ++- commands/by.js | 13 +++++++------ commands/default.js | 4 +++- commands/help.js | 7 +++++-- lib/analyze.js | 29 ++++++++++++++++++++++------- 5 files changed, 39 insertions(+), 17 deletions(-) diff --git a/cli.js b/cli.js index f1fcd09..1c1506a 100755 --- a/cli.js +++ b/cli.js @@ -15,7 +15,8 @@ const knownFlags = [ "duplicatesOnly", "limit", "version", - "help" + "help", + "ignore" ]; const validateFlags = flags => { diff --git a/commands/by.js b/commands/by.js index 6513093..7bdd8f4 100644 --- a/commands/by.js +++ b/commands/by.js @@ -4,18 +4,19 @@ const { analyze, print, getStats } = require("../lib"); module.exports = function byCommand( statsFilePath /*: string */, - flags /*: { limit: number, by: string } */, + flags /*: { limit: number, by: string, ignore?: string } */, pattern /*: string */ ) { const stats = getStats(statsFilePath); - const { by } = flags; - const report = analyze(stats).filter(mod => { + const ignore = flags.ignore ? flags.ignore.split(",") : []; + const report = analyze(stats, ignore).filter(mod => { return ( mod.reasons.some( - reason => reason.moduleName === by || reason.clearName === by - ) || (mod.depsChains || []).some(deps => deps.indexOf(by) !== -1) + reason => + reason.moduleName === flags.by || reason.clearName === flags.by + ) || (mod.depsChains || []).some(deps => deps.indexOf(flags.by) !== -1) ); }); const limit /*: number */ = pattern ? 0 : flags.limit >= 0 ? flags.limit : 20; - print(report, { by }, limit); + print(report, { by: flags.by }, limit); }; diff --git a/commands/default.js b/commands/default.js index ff5b1ac..56c922f 100644 --- a/commands/default.js +++ b/commands/default.js @@ -11,6 +11,7 @@ type Flags = { directOnly?: boolean, transitiveOnly?: boolean, duplicatesOnly?: boolean, + ignore?: string, by?: string } */ @@ -21,7 +22,8 @@ module.exports = function defaultCommand( pattern /*: string*/ ) { const stats = getStats(statsFilePath); - const report = analyze(stats).filter(module => { + const ignore = flags.ignore ? flags.ignore.split(",") : []; + const report = analyze(stats, ignore).filter(module => { if (pattern && mm.isMatch(module.name, pattern)) { return true; } else if (pattern) { diff --git a/commands/help.js b/commands/help.js index 7edca57..3888b0f 100644 --- a/commands/help.js +++ b/commands/help.js @@ -5,11 +5,13 @@ const chalk = require("chalk"); module.exports = function help() { return [ chalk.green("Usage"), - ` $ whybundled stats.json [pattern] ${chalk.dim('[default command]')}`, - ` $ whybundled stats.json --by styled-components ${chalk.dim('[by command]')}`, + ` $ whybundled stats.json [pattern] ${chalk.dim('[default command]')}`, + ` $ whybundled stats.json --ignore babel-runtime,tslib ${chalk.dim('[default command]')}`, + ` $ whybundled stats.json --by styled-components ${chalk.dim('[by command]')}`, "", chalk.green("Default options:"), ` ${chalk.yellow("[pattern]")} Optional pattern used to filter output to only matched modules`, + ` ${chalk.yellow("--ignore")} Comma separated list of glob pattern to exclude modules from final output`, ` ${chalk.yellow("--modulesOnly")} Only include modules`, ` ${chalk.yellow("--filesOnly")} Only include files`, ` ${chalk.yellow("--directOnly")} Only include direct dependencies`, @@ -18,6 +20,7 @@ module.exports = function help() { ` ${chalk.yellow("--limit")} Limits output of reasons and files [default: 20]`, "", chalk.green("By options [--by]:"), + ` ${chalk.yellow("--ignore")} Comma separated list of glob pattern to exclude modules from final output`, ` ${chalk.yellow("--limit")} Limits output of reasons and files [default: 20]`, ``, chalk.green("Other options:"), diff --git a/lib/analyze.js b/lib/analyze.js index a204470..4647583 100644 --- a/lib/analyze.js +++ b/lib/analyze.js @@ -1,7 +1,4 @@ /* @flow */ - -const path = require("path"); - /*:: export type WebpackStats = { chunks: Array @@ -65,6 +62,11 @@ export type SubReason = { */ +const path = require("path"); +const mm = require("micromatch"); + +const DEFAULT_IGNORE = ["multi *", "*-loader*"]; + const toArray = (report /*: { [string]: Module } */) => Object.keys(report).map(name => Object.assign({}, report[name], { name: name }) @@ -207,7 +209,7 @@ const pickFromModules = (modules) /*: Array */ => const buildModuleDepsChains = (modules, name) => { const module = modules[name]; return module.reasons.reduce((acc, reason) => { - if (reason.type !== "module") { + if (reason.type !== "module" || !modules[reason.clearName]) { return acc; } @@ -239,15 +241,28 @@ const postProcessModules = modules => { ).map(chain => chain.split("|")); } - acc[name] = module; + module.reasons = module.reasons.filter( + reason => !!modules[reason.moduleName] + ); + + if (module.reasons.length) { + acc[name] = module; + } return acc; }, {}); }; -module.exports = function analyze(stats /*: WebpackStats */) { +module.exports = function analyze( + stats /*: WebpackStats */, + ignore /*: Array */ = [] +) { const rawModules = flattenChunks(stats); const modules = pickFromModules(rawModules).filter( - m => !m.name.startsWith("multi") && !m.name.match("-loader") + m => + !mm.isMatch( + m.clearName || m.name, + [].concat(DEFAULT_IGNORE).concat(ignore) + ) ); return toArray(postProcessModules(joinModules(modules))); };