closure-calculate-chunks
Advanced tools
Comparing version
106
cli.js
#!/usr/bin/env node | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const parseArgs = require('minimist'); | ||
const temp = require('temp'); | ||
const open = require('open'); | ||
const yargs = require('yargs'); | ||
const ChunkGraph = require('./lib/chunk-graph'); | ||
@@ -11,39 +11,73 @@ const parseGoogDeps = require('./lib/parse-goog-deps'); | ||
const generateHtml = require('./lib/generate-html'); | ||
const packageJson = require('./package.json'); | ||
const rawFlags = parseArgs(process.argv.slice(2)); | ||
const argv = yargs(process.argv) | ||
.version(packageJson.version) | ||
.option('entrypoint', { | ||
demandOption: true, | ||
describe: 'Format: <path/to/file>. Main entrypoint for the program. The first occurrence will be treated as the primary entrypoint. Additional entrypoints will be added as children of the primary entrypoint. Multiple files may be listed for a single entrypoint, separated by commas, to indicate they are both part of the same chunk.', | ||
type: 'string' | ||
}) | ||
.option('manual-entrypoint', { | ||
describe: 'Format: <path/to/Parent>:<path/to/Child>. Add an arbitrary chunk entrypoint to the graph. Multiple children may be listed separated by commas.', | ||
type: 'string' | ||
}) | ||
.option('root', { | ||
describe: 'Format: <path/to/project/root>. Path to the project root directory. The current working directory of the process is used by default.', | ||
type: 'string' | ||
}) | ||
.option('closure-library-base-js-path', { | ||
describe: 'Format: <path/to/base.js>. Path to closure-library\'s base.js file. Required if closure-library or goog.module references are used.', | ||
type: 'string' | ||
}) | ||
.option('deps-file', { | ||
describe: 'Fomrat: <path/to/deps.js>. Path to closure-library deps.js file or custom deps.js file. Used to find paths to closure-library namespaces.', | ||
type: 'string', | ||
requiresArg: 'closure-library-base-js-path' | ||
}) | ||
.option('extra-deps', { | ||
describe: 'Format: <namespace>:<path/to/file>. Namespace and path to a file providing a closure namespace or module.', | ||
type: 'string', | ||
requiresArg: 'closure-library-base-js-path' | ||
}) | ||
.option('visualize', { | ||
describe: 'Create and open an html page to visualize the graph.', | ||
type: 'boolean' | ||
}) | ||
.option('package-json-entry-names', { | ||
describe: 'Ordered list of entries to look for in package.json files when resolving modules', | ||
default: 'browser,module,main', | ||
type: 'string' | ||
}) | ||
.strict() | ||
.help() | ||
.coerce('package-json-entry-names', (arg) => arg.split(/,\s*/g)) | ||
.check((argv) => { | ||
if (argv.manualEntrypoint) { | ||
const manualEntrypoints = Array.isArray(argv.manualEntrypoint) ? argv.manualEntrypoint : [argv.manualEntrypoint]; | ||
manualEntrypoints.forEach((manualEntrypoint) => { | ||
const parts = manualEntrypoint.split(':'); | ||
if (parts.length < 2) { | ||
throw new Error('manual-entrypoints must be of the form "<path/to/Parent>:<path/to/Child>"'); | ||
} | ||
}); | ||
} else if (argv['extra-deps']) { | ||
const extraDeps = Array.isArray(argv['extra-deps']) ? argv['extra-deps'] : [argv['extra-deps']]; | ||
extraDeps.forEach(dep => { | ||
const depParts = dep.split(':'); | ||
if (depParts.length !== 2) { | ||
throw new Error('extra-deps must be of the form "<namespace>:<path/to/file>"'); | ||
} | ||
}); | ||
} | ||
return true; | ||
}) | ||
.usage('Usage: node --preserve-symlinks $0 --entrypoint src/main.js') | ||
.argv; | ||
if (rawFlags.help) { | ||
process.stdout.write(`Usage: node --preserve-symlinks node_modules/.bin/closure-calculate-chunks --entrypoint src/main.js | ||
Create a chunk graph from an entrypoint. New chunks are created when a dynamic import statement is encountered. | ||
Options: | ||
--entrypoint <path/to/file> Required: Main entrypoint for the program. The first occurrence | ||
will be treated as the primary entrypoint. Additional | ||
entrypoints will be added as children of the primary entrypoint. | ||
Multiple files may be listed for a single entrypoint, | ||
separated by commas, to indicate they are both part of the same chunk. | ||
--manual-entrypoint <path/to/Parent>:<path/to/Child> Optional: Add an arbitrary chunk entrypoint to the graph. | ||
Multiple children may be listed separated by commas. | ||
--root <path/to/project/root> Optional: Path to the project root directory. The current | ||
working directory of the process is used by default. | ||
--closure-library-base-js-path <path/to/base.js> Optional: Path to closure-library's base.js file. Required if | ||
closure-library or goog.module references are used. | ||
--deps-file <path/to/deps.js> Optional: Path to closure-library deps.js file or custom deps.js | ||
file. Used to find paths to closure-libary namespaces. | ||
--extra-deps <namespace>:<path/to/file> Optional: Namespace and path to a file providing a closure | ||
namespace or module. | ||
--visualize Create and open an html page to visualize the graph. | ||
--help Output usage information | ||
`); | ||
process.exit(0); | ||
} | ||
function convertToCamelCase(value) { | ||
return value.replace(/[-_][a-z]/g, (match) => match.substr(1).toUpperCase()); | ||
} | ||
const flags = {}; | ||
Object.keys(rawFlags).forEach((rawFlag) => { | ||
flags[convertToCamelCase(rawFlag)] = rawFlags[rawFlag]; | ||
Object.keys(argv).forEach((option) => { | ||
if (/^[a-z]/.test(option) && !/-/.test(option)) { | ||
flags[option] = argv[option]; | ||
} | ||
}); | ||
@@ -106,3 +140,3 @@ | ||
const chunkGraph = | ||
ChunkGraph.buildFromEntrypoints(entrypoints, manualEntrypoints, rootDir, googBasePath, googPathsByNamespace); | ||
ChunkGraph.buildFromEntrypoints(flags.packageJsonEntryNames, entrypoints, manualEntrypoints, rootDir, googBasePath, googPathsByNamespace); | ||
@@ -109,0 +143,0 @@ if (flags.visualize) { |
@@ -158,2 +158,3 @@ const graphlib = require('graphlib'); | ||
* | ||
* @param {!Array<string>} packageJsonEntryNames prefence order of fields to look for in package.json files for the main file | ||
* @param {!Array<{name:string, files: !Array<string>}>} entrypoints paths from which to start building the graph. | ||
@@ -167,5 +168,6 @@ * The first entry is the primary entrypoint. | ||
*/ | ||
static buildFromEntrypoints(entrypoints, manualEntrypoints, baseDirectory, googBasePath = null, googDepsMap = null) { | ||
static buildFromEntrypoints(packageJsonEntryNames, entrypoints, manualEntrypoints, baseDirectory, googBasePath = null, googDepsMap = null) { | ||
const fileDepsCache = new Map(); | ||
let graphData = findDependencies( | ||
packageJsonEntryNames, | ||
entrypoints, | ||
@@ -190,2 +192,3 @@ manualEntrypoints, | ||
graphData = findDependencies( | ||
packageJsonEntryNames, | ||
entrypoints, | ||
@@ -192,0 +195,0 @@ manualEntrypoints, |
@@ -35,2 +35,3 @@ const acorn = require('acorn'); | ||
* | ||
* @param {!Array<string>} packageJsonEntryNames prefence order of fields to look for in package.json files for the main file | ||
* @param {string} filepath | ||
@@ -43,3 +44,3 @@ * @param {!Object} ast | ||
*/ | ||
function findDeps(filepath, ast, baseDirectory, googBasePath = null, googDepsMap = null) { | ||
function findDeps(packageJsonEntryNames, filepath, ast, baseDirectory, googBasePath = null, googDepsMap = null) { | ||
const deps = [filepath]; | ||
@@ -109,5 +110,5 @@ const childChunks = []; | ||
} else if (pathParts.length === 2 && pathParts[0][0] === '@') { | ||
depsPlusPackageJsonFiles.push(resolveFrom(`${baseDirectory}/package.json`, `${dep}/package.json`)); | ||
depsPlusPackageJsonFiles.push(resolveFrom( `${baseDirectory}/package.json`, `${dep}/package.json`)); | ||
} | ||
depsPlusPackageJsonFiles.push(resolveFrom(filepath, dep) || dep); | ||
depsPlusPackageJsonFiles.push(resolveFrom(filepath, dep, packageJsonEntryNames) || dep); | ||
}); | ||
@@ -120,3 +121,3 @@ return depsPlusPackageJsonFiles; | ||
new Set(addPackageJsonFiles(deps)), | ||
new Set(childChunks.map(dep => resolveFrom(filepath, dep))) | ||
new Set(childChunks.map(dep => resolveFrom(filepath, dep, packageJsonEntryNames))) | ||
); | ||
@@ -126,2 +127,3 @@ } | ||
/** | ||
* @param {!Array<string>} packageJsonEntryNames prefence order of fields to look for in package.json files for the main file | ||
* @param {string} filepath | ||
@@ -137,2 +139,3 @@ * @param {!Map<string, !GraphNode>} cache | ||
function getDependenciesForFile( | ||
packageJsonEntryNames, | ||
filepath, | ||
@@ -161,3 +164,3 @@ cache, | ||
}); | ||
const depInfo = findDeps(filepath, ast, baseDirectory, googBasePath, googDepsMap); | ||
const depInfo = findDeps(packageJsonEntryNames, filepath, ast, baseDirectory, googBasePath, googDepsMap); | ||
parsedDeps = Array.from(depInfo.deps); | ||
@@ -179,3 +182,3 @@ childChunks = Array.from(depInfo.childChunks); | ||
let transientDepInfo = getDependenciesForFile( | ||
parsedDeps[i], cache, baseDirectory, googBasePath, googDepsMap, dependenciesToHoist, visitedFiles); | ||
packageJsonEntryNames, parsedDeps[i], cache, baseDirectory, googBasePath, googDepsMap, dependenciesToHoist, visitedFiles); | ||
const transientDeps = Array.from(transientDepInfo.deps); | ||
@@ -203,2 +206,3 @@ transientDeps.unshift(parsedDeps[i]); | ||
/** | ||
* @param {!Array<string>} packageJsonEntryNames prefence order of fields to look for in package.json files for the main file | ||
* @param {!Array<{name:string, files: !Array<string>}>} entrypoints paths from which to start building the graph | ||
@@ -217,2 +221,3 @@ * @param {!Array<{parent: string, child: {name: string, files: !Array<string>}}>} manualEntrypoints paths from which to start building the graph | ||
function findDepsFromEntryPoints( | ||
packageJsonEntryNames, | ||
entrypoints, | ||
@@ -248,3 +253,3 @@ manualEntrypoints, | ||
const {deps, childChunks} = getDependenciesForFile( | ||
entrypoint.files[i], fileDepsCache, baseDirectory, googBasePath, googDepsMap, dependenciesToHoist); | ||
packageJsonEntryNames, entrypoint.files[i], fileDepsCache, baseDirectory, googBasePath, googDepsMap, dependenciesToHoist); | ||
deps.forEach(dep => { | ||
@@ -251,0 +256,0 @@ currentChunk.sources.add(dep); |
const Module = require('module'); | ||
module.exports = (filepath, moduleId) => { | ||
function findMainEntryWithPackageJsonEntryNames(requireFrom, packageJsonEntryNames, moduleId) { | ||
try { | ||
const packageJson = requireFrom(`${moduleId}/package.json`); | ||
for (let i = 0; i < packageJsonEntryNames.length; i++) { | ||
if (packageJson[packageJsonEntryNames[i]]) { | ||
return `${moduleId}/${packageJson[packageJsonEntryNames[i]]}`; | ||
} | ||
} | ||
} catch (e) {} | ||
return moduleId; | ||
} | ||
module.exports = (filepath, moduleId, packageJsonEntryNames = []) => { | ||
const requireFrom = Module.createRequire(filepath); | ||
return requireFrom.resolve(moduleId); | ||
if (/^[\.\/]/.test(moduleId)) { | ||
return requireFrom.resolve(moduleId); | ||
} | ||
const pathParts = moduleId.split(/\/|\\/); | ||
let moduleIdFromPackageEntryNames = moduleId; | ||
if (/^d3-/.test(moduleId)) debugger; | ||
if (pathParts.length === 1) { | ||
moduleIdFromPackageEntryNames = | ||
findMainEntryWithPackageJsonEntryNames(requireFrom, packageJsonEntryNames, moduleId); | ||
} else if (pathParts.length === 2 && pathParts[0][0] === '@') { | ||
moduleIdFromPackageEntryNames = | ||
findMainEntryWithPackageJsonEntryNames(requireFrom, packageJsonEntryNames, moduleId); | ||
} | ||
return requireFrom.resolve(moduleIdFromPackageEntryNames); | ||
}; |
{ | ||
"name": "closure-calculate-chunks", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Analyze dependencies from entry points and split code for closure-compiler", | ||
@@ -16,6 +16,6 @@ "bin": { | ||
"graphlib": "2.x", | ||
"minimist": "1.x", | ||
"open": "^7.0.4", | ||
"sigma": "1.x", | ||
"temp": "^0.9.1" | ||
"temp": "^0.9.1", | ||
"yargs": "^16.2.0" | ||
}, | ||
@@ -22,0 +22,0 @@ "engines": { |
@@ -27,2 +27,4 @@ # closure-calculate-chunks | ||
- **--package-json-entry-names field1,field2,...** Ordered list of entries to look for in package.json files when resolving modules. | ||
- **--visualize** Instead of outputting the closure compiler flags, open an HTML page to visualize the graph. | ||
@@ -29,0 +31,0 @@ |
Sorry, the diff of this file is not supported yet
66728
6.85%1014
7.53%51
4.08%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed