diff --git a/plugin/index.ts b/plugin/index.ts index c1bbfef..9e809a7 100644 --- a/plugin/index.ts +++ b/plugin/index.ts @@ -10,7 +10,7 @@ import { version } from "./version"; import { createGzipSizeGetter, createBrotliSizeGetter, SizeGetter } from "./compress"; import { TemplateType } from "./template-types"; -import { ModuleMapper } from "./module-mapper"; +import { ModuleMapper, replaceHashPlaceholders } from "./module-mapper"; import { addLinks, buildTree, mergeTrees } from "./data"; import { getSourcemapModules } from "./sourcemap"; import { renderTemplate } from "./render-template"; @@ -281,9 +281,11 @@ export const visualizer = ( }, }; + const stringData = replaceHashPlaceholders(data); + const fileContent: string = await renderTemplate(template, { title, - data, + data: stringData, }); if (opts.emitFile) { diff --git a/plugin/module-mapper.ts b/plugin/module-mapper.ts index cc8ac53..07a7c5d 100644 --- a/plugin/module-mapper.ts +++ b/plugin/module-mapper.ts @@ -1,12 +1,15 @@ -import { ModuleImport, ModuleMeta, ModulePart, ModuleLengths, ModuleUID } from "../shared/types"; -import { getUid } from "./uid"; - -const nanoid = getUid("1234567890abcdef", 4); - -const UNIQUE_PREFIX = nanoid(); -let COUNTER = 0; - -const uniqueId = (): ModuleUID => `${UNIQUE_PREFIX}-${COUNTER++}`; +import { + ModuleImport, + ModuleMeta, + ModulePart, + ModuleLengths, + ModuleUID, + VisualizerData, +} from "../shared/types"; +import * as crypto from "crypto"; + +const HASH_PLACEHOLDER = "!{ROLLUP_VISUALIZER_HASH_PLACEHOLDER}"; +const HASH_PLACEHOLDER_REGEXP = new RegExp(`"${HASH_PLACEHOLDER}-(\\d+)"`, "g"); type ModuleIdStorage = { uid: ModuleUID; @@ -16,9 +19,23 @@ type ModuleIdStorage = { }; }; +export const getDataHash = (json: string) => { + const hash = crypto.createHash("sha1").update(json).digest("hex"); + const hashSub = hash.substring(0, 8); + return hashSub; +}; + +export const replaceHashPlaceholders = (data: VisualizerData) => { + const json = JSON.stringify(data); + const hash = getDataHash(json); + const jsonWithHash = json.replace(HASH_PLACEHOLDER_REGEXP, (_, num) => `"${hash}-${num}"`); + return jsonWithHash; +}; + export class ModuleMapper { private nodeParts: Record = {}; private nodeMetas: Record = {}; + private counter: number = 0; constructor(private projectRoot: string | RegExp) {} @@ -29,10 +46,14 @@ export class ModuleMapper { return moduleId.replace(this.projectRoot, ""); } + uniqueId(): ModuleUID { + return `${HASH_PLACEHOLDER}-${this.counter++}`; + } + getModuleUid(moduleId: string): ModuleUID { if (!(moduleId in this.nodeMetas)) { this.nodeMetas[moduleId] = { - uid: uniqueId(), + uid: this.uniqueId(), meta: { id: this.trimProjectRootId(moduleId), moduleParts: {}, @@ -48,7 +69,7 @@ export class ModuleMapper { getBundleModuleUid(bundleId: string, moduleId: string): ModuleUID { if (!(moduleId in this.nodeMetas)) { this.nodeMetas[moduleId] = { - uid: uniqueId(), + uid: this.uniqueId(), meta: { id: this.trimProjectRootId(moduleId), moduleParts: {}, @@ -58,7 +79,7 @@ export class ModuleMapper { }; } if (!(bundleId in this.nodeMetas[moduleId].meta.moduleParts)) { - this.nodeMetas[moduleId].meta.moduleParts[bundleId] = uniqueId(); + this.nodeMetas[moduleId].meta.moduleParts[bundleId] = this.uniqueId(); } return this.nodeMetas[moduleId].meta.moduleParts[bundleId]; diff --git a/plugin/render-template.ts b/plugin/render-template.ts index b266e48..ec00450 100644 --- a/plugin/render-template.ts +++ b/plugin/render-template.ts @@ -55,7 +55,7 @@ ${script} `; export type RenderTemplateOptions = { - data: VisualizerData; + data: string; title: string; }; @@ -67,12 +67,16 @@ const buildHtml = fs.readFile(path.join(__dirname, "..", "lib", `${template}.css`), "utf8"), ]); - return buildHtmlTemplate(title, script, JSON.stringify(data), style); + return buildHtmlTemplate(title, script, data, style); }; -const outputRawData = (data: VisualizerData) => JSON.stringify(data, null, 2); +const outputRawData = (strData: string) => { + const data = JSON.parse(strData) as VisualizerData; + return JSON.stringify(data, null, 2); +}; -const outputPlainTextList = (data: VisualizerData) => { +const outputPlainTextList = (strData: string) => { + const data = JSON.parse(strData) as VisualizerData; const bundles: Record = {}; for (const meta of Object.values(data.nodeMetas)) { diff --git a/plugin/uid.ts b/plugin/uid.ts deleted file mode 100644 index ad56a1e..0000000 --- a/plugin/uid.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const getUid = (alphabit: string | string[], size: number) => () => { - let result = ""; - for (let i = 0; i < size; i++) { - result += alphabit[(Math.random() * alphabit.length) | 0]; - } - return result; -};