From f292743b9ea247b6accc4010eee7c4064823e14e Mon Sep 17 00:00:00 2001 From: Ryan Roemer Date: Fri, 14 Dec 2018 20:30:53 -0800 Subject: [PATCH 1/4] Hone down signature, add history. --- HISTORY.md | 4 ++++ src/lib/actions/base.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index eb957566..48604859 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,10 @@ History ======= +## UNRELEASED + +- Add `fullPath` processed module field internally and to output reports. + ## 4.1.2 - BUG: Use `name` field to better process `identifier` to remove things like diff --git a/src/lib/actions/base.ts b/src/lib/actions/base.ts index 86c79f5e..1be4d630 100644 --- a/src/lib/actions/base.ts +++ b/src/lib/actions/base.ts @@ -101,7 +101,7 @@ export const _normalizeWebpackPath = (identifier: string, name?: string): string // Normalizations: // - Remove starting path if `./` // - Switch Windows paths to Mac/Unix style. -export const _getBaseName = (name: string): string | null => { +export const _getBaseName = (name: string): string => { // Slice to just after last occurrence of node_modules. const parts = nodeModulesParts(name); const lastName = parts[parts.length - 1]; From 4c6667644d810b3a88d73f6a48ace95a58149b95 Mon Sep 17 00:00:00 2001 From: Ryan Roemer Date: Fri, 14 Dec 2018 20:34:41 -0800 Subject: [PATCH 2/4] WIP: Start working again on _getFullPath --- src/lib/actions/base.ts | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/lib/actions/base.ts b/src/lib/actions/base.ts index 1be4d630..54349fd1 100644 --- a/src/lib/actions/base.ts +++ b/src/lib/actions/base.ts @@ -128,6 +128,44 @@ export const _getBaseName = (name: string): string => { return toPosixPath(candidate); }; +// Convert an identifier into a full path. +// +// Uses the (normalized) `name` field to assess that the (normalized) identifier +// is indeed a real file on disk. +export const _getFullPath = (identifier: string, name: string): string => { + const posixIdentifier = toPosixPath(identifier); + + // Start some normalization. + let posixName = toPosixPath(name); + if (posixName.startsWith("./")) { + // Remove dot-slash relative part. + posixName = posixName.slice(2); + } + + // If the name is not the end of the identifier, it probably is webpack v1-2 + // with `~` instead of `node_modules` + const idxOfName = posixIdentifier.indexOf(posixName); + if (idxOfName === 0) { + // Direct match. We're done. + return normalize(posixName); + } else if (idxOfName === posixIdentifier.length - posixName.length) { + // Suffix match. + // TODO(FULL_PATH): COMBINE WITH PREVIOUS + // TODO(FULL_PATH): Combine multiple processing fns + return normalize(posixName); + } + if (identifier.lastIndexOf(name) !== identifier.length - name.length) { + console.log("TODO MISMATCH", JSON.stringify({ + posixIdentifier, + posixName, + normalize: normalize(posixIdentifier) + }, null, 2)); + } + + // TODO: HERE -- this stuff isn't even remotely done. Above or below :). + return "TODO"; +}; + export abstract class Action { public stats: IWebpackStats; private _data?: object; @@ -218,6 +256,9 @@ export abstract class Action { const isNodeModules = _isNodeModules(normalizedId); const baseName = isNodeModules ? _getBaseName(normalizedId) : null; + // TODO(FULL_PATH): Add into data + _getFullPath(normalizedId, normalizedName); + return list.concat([{ baseName, chunks, From a013cd3a657c140d36512c7f9cb1765a6f633eb1 Mon Sep 17 00:00:00 2001 From: Ryan Roemer Date: Mon, 17 Dec 2018 16:07:10 -0800 Subject: [PATCH 3/4] Add _removePrepath --- src/lib/actions/base.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/lib/actions/base.ts b/src/lib/actions/base.ts index 54349fd1..5eef6494 100644 --- a/src/lib/actions/base.ts +++ b/src/lib/actions/base.ts @@ -45,6 +45,9 @@ export const nodeModulesParts = (name: string) => toPosixPath(name).split(NM_RE) // True if name is part of a `node_modules` path. export const _isNodeModules = (name: string): boolean => nodeModulesParts(name).length > 1; +// Remove all relative higher-up paths (`./` or `../../../`). +const _removePrepath = (val) => val.replace(/^(\.+(\/|\\)+)+/g, ""); + // Attempt to "unwind" webpack paths in `identifier` and `name` to remove // prefixes and produce a normal, usable filepath. // @@ -75,15 +78,11 @@ export const _normalizeWebpackPath = (identifier: string, name?: string): string // - v3: "/PATH/TO/ROOT/node_modules/pkg/index.js" // - v4: "./node_modules/pkg/index.js" if (name) { - name = name + // Expand `node_modules`, remove prefix `./`, `../`, etc. + name = _removePrepath(name) .replace("/~/", "/node_modules/") .replace("\\~\\", "\\node_modules\\"); - if (name.startsWith("./") || name.startsWith(".\\")) { - // Remove dot-slash relative part. - name = name.slice(2); - } - // Now, truncate suffix of the candidate if name has less. const nameLastIdx = candidate.lastIndexOf(name); if (nameLastIdx > -1 && candidate.length !== nameLastIdx + name.length) { @@ -132,11 +131,11 @@ export const _getBaseName = (name: string): string => { // // Uses the (normalized) `name` field to assess that the (normalized) identifier // is indeed a real file on disk. -export const _getFullPath = (identifier: string, name: string): string => { +export const _getFullPath = (identifier: string, name: string, TODO_REMOVE_OBJ: any): string => { const posixIdentifier = toPosixPath(identifier); // Start some normalization. - let posixName = toPosixPath(name); + let posixName = _removePrepath(toPosixPath(name)); if (posixName.startsWith("./")) { // Remove dot-slash relative part. posixName = posixName.slice(2); @@ -158,7 +157,11 @@ export const _getFullPath = (identifier: string, name: string): string => { console.log("TODO MISMATCH", JSON.stringify({ posixIdentifier, posixName, - normalize: normalize(posixIdentifier) + normalize: normalize(posixIdentifier), + TODO_REMOVE_OBJ: { + issuer: TODO_REMOVE_OBJ.issuer, + source: TODO_REMOVE_OBJ.source || "NO_SOURCE", + } }, null, 2)); } @@ -257,7 +260,7 @@ export abstract class Action { const baseName = isNodeModules ? _getBaseName(normalizedId) : null; // TODO(FULL_PATH): Add into data - _getFullPath(normalizedId, normalizedName); + _getFullPath(normalizedId, normalizedName, mod); return list.concat([{ baseName, From b8861c5056f0e37c44bbd296b1ee93fed98b6a69 Mon Sep 17 00:00:00 2001 From: Ryan Roemer Date: Tue, 18 Dec 2018 14:38:52 -0800 Subject: [PATCH 4/4] typo --- README.md | 2 +- src/lib/actions/base.ts | 21 +++++++++++---------- src/lib/actions/duplicates.ts | 1 + src/lib/actions/sizes.ts | 6 ++++-- src/lib/actions/versions.ts | 1 + src/lib/interfaces/modules.ts | 8 +++++++- 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 0854af55..936fe62a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ inspectpack An inspection tool for Webpack frontend JavaScript bundles. -`inspectpack` provides insight into your webpack-built JS bundles and detailed analysis of opportunites to reduce module sizes, unneeded duplicates, etc. It can be used as a webpack **plugin** during your compliations or as an **offline CLI tool** to report on your previous builds. +`inspectpack` provides insight into your webpack-built JS bundles and detailed analysis of opportunites to reduce module sizes, unneeded duplicates, etc. It can be used as a webpack **plugin** during your compilations or as an **offline CLI tool** to report on your previous builds. It is also the engine for the handy [`webpack-dashboard`](https://github.com/FormidableLabs/webpack-dashboard) plugin. diff --git a/src/lib/actions/base.ts b/src/lib/actions/base.ts index 5eef6494..c87976a0 100644 --- a/src/lib/actions/base.ts +++ b/src/lib/actions/base.ts @@ -46,7 +46,7 @@ export const nodeModulesParts = (name: string) => toPosixPath(name).split(NM_RE) export const _isNodeModules = (name: string): boolean => nodeModulesParts(name).length > 1; // Remove all relative higher-up paths (`./` or `../../../`). -const _removePrepath = (val) => val.replace(/^(\.+(\/|\\)+)+/g, ""); +const _removePrepath = (val: string) => val.replace(/^(\.+(\/|\\)+)+/g, ""); // Attempt to "unwind" webpack paths in `identifier` and `name` to remove // prefixes and produce a normal, usable filepath. @@ -144,16 +144,16 @@ export const _getFullPath = (identifier: string, name: string, TODO_REMOVE_OBJ: // If the name is not the end of the identifier, it probably is webpack v1-2 // with `~` instead of `node_modules` const idxOfName = posixIdentifier.indexOf(posixName); - if (idxOfName === 0) { - // Direct match. We're done. - return normalize(posixName); - } else if (idxOfName === posixIdentifier.length - posixName.length) { + if ( + // Direct match. + idxOfName === 0 || // Suffix match. - // TODO(FULL_PATH): COMBINE WITH PREVIOUS - // TODO(FULL_PATH): Combine multiple processing fns - return normalize(posixName); + idxOfName === posixIdentifier.length - posixName.length + ) { + return normalize(posixIdentifier); } - if (identifier.lastIndexOf(name) !== identifier.length - name.length) { + + if (identifier.lastIndexOf(name) !== identifier.length - name.length) { console.log("TODO MISMATCH", JSON.stringify({ posixIdentifier, posixName, @@ -260,11 +260,12 @@ export abstract class Action { const baseName = isNodeModules ? _getBaseName(normalizedId) : null; // TODO(FULL_PATH): Add into data - _getFullPath(normalizedId, normalizedName, mod); + const fullPath = _getFullPath(normalizedId, normalizedName, mod); return list.concat([{ baseName, chunks, + fullPath, identifier, isNodeModules, isSynthetic, diff --git a/src/lib/actions/duplicates.ts b/src/lib/actions/duplicates.ts index def53506..7c444e66 100644 --- a/src/lib/actions/duplicates.ts +++ b/src/lib/actions/duplicates.ts @@ -132,6 +132,7 @@ class Duplicates extends Action { modules: modsMap[baseName][source].map((mod) => ({ baseName: mod.baseName, fileName: mod.identifier, + fullPath: mod.fullPath, size: { full: mod.size, }, diff --git a/src/lib/actions/sizes.ts b/src/lib/actions/sizes.ts index 74dd8538..6c2780e7 100644 --- a/src/lib/actions/sizes.ts +++ b/src/lib/actions/sizes.ts @@ -38,6 +38,7 @@ class Sizes extends Action { files: assets[name].mods.map((mod) => ({ baseName: mod.baseName, fileName: mod.identifier, + fullPath: mod.fullPath, size: { full: mod.size, }, @@ -73,7 +74,7 @@ class SizesTemplate extends Template { .then(({ meta, assets }) => { const files = (mods: IActionModule[]) => mods .map((obj) => this.trim(chalk` - * {gray ${obj.fileName}} + * {gray ${obj.fullPath || obj.fileName}} * Size: ${numF(obj.size.full)} `, 12)) .join("\n"); @@ -103,12 +104,13 @@ class SizesTemplate extends Template { public tsv(): Promise { return Promise.resolve() .then(() => this.action.getData() as Promise) - .then(({ assets }) => ["Asset\tFull Name\tShort Name\tSize"] + .then(({ assets }) => ["Asset\tFull Path\tFile Name\tShort Name\tSize"] .concat(Object.keys(assets) // Get items .map((name) => assets[name].files .map((obj) => [ name, + obj.fullPath, obj.fileName, obj.baseName === null ? "(source)" : obj.baseName, obj.size.full, diff --git a/src/lib/actions/versions.ts b/src/lib/actions/versions.ts index c3782f76..c21381cf 100644 --- a/src/lib/actions/versions.ts +++ b/src/lib/actions/versions.ts @@ -270,6 +270,7 @@ const getAssetData = ( const modules = (modsToFilePath[filePath] || []).map((mod) => ({ baseName: mod.baseName, fileName: mod.identifier, + fullPath: mod.fullPath, size: { full: mod.size, }, diff --git a/src/lib/interfaces/modules.ts b/src/lib/interfaces/modules.ts index 6774c943..e7b2d613 100644 --- a/src/lib/interfaces/modules.ts +++ b/src/lib/interfaces/modules.ts @@ -6,10 +6,15 @@ export interface IModule extends IWebpackStatsModuleBase { // Is `null` if not a `node_modules` package module. baseName: string | null; + // Inferred path to a real file on disk (app or `node_modules`). + // Is `null` if no real, single base file or in a loader/generated code + // context a "better" contender exists as "the original". + fullPath: string | null; + // Is a vendor module / is part of a `node_modules` path. isNodeModules: boolean; - // Is a vendor module / is part of a `node_modules` path. + // Is a "made up" module without actual source. isSynthetic: boolean; // We **change** `source` to allow `null` for synthetic modules. @@ -23,6 +28,7 @@ export const SYNTHETIC_SOURCE_TOKEN = "synthetic"; export interface IActionModule { baseName: string | null; fileName: string; + fullPath: string | null; size: { full: number, };