mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			184 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| const path = require("path");
 | |
| const fs = require("fs");
 | |
| const BinaryMiddleware = require("../lib/serialization/BinaryMiddleware");
 | |
| const FileMiddleware = require("../lib/serialization/FileMiddleware");
 | |
| const Serializer = require("../lib/serialization/Serializer");
 | |
| const SerializerMiddleware = require("../lib/serialization/SerializerMiddleware");
 | |
| 
 | |
| /** @typedef {{ size: number, lazySize: number }} SizeInfo */
 | |
| 
 | |
| const binaryMiddleware = new BinaryMiddleware();
 | |
| 
 | |
| const serializer = new Serializer([binaryMiddleware, new FileMiddleware(fs)]);
 | |
| 
 | |
| const rawSerializer = new Serializer([new FileMiddleware(fs)]);
 | |
| 
 | |
| /** @type {Array<SizeInfo | undefined>} */
 | |
| const lazySizes = [];
 | |
| 
 | |
| /**
 | |
|  * @param {Array<any>} data data
 | |
|  * @returns {Promise<SizeInfo>} size info
 | |
|  */
 | |
| const captureSize = async data => {
 | |
| 	let size = 0;
 | |
| 	let lazySize = 0;
 | |
| 	for (const b of data) {
 | |
| 		if (Buffer.isBuffer(b)) {
 | |
| 			size += b.length;
 | |
| 		} else if (typeof b === "function") {
 | |
| 			const i = lazySizes.length;
 | |
| 			lazySizes.push(undefined);
 | |
| 			const r = await captureSize(await b());
 | |
| 			lazySize += r.size + r.lazySize;
 | |
| 			lazySizes[i] = r;
 | |
| 		}
 | |
| 	}
 | |
| 	return { size, lazySize };
 | |
| };
 | |
| 
 | |
| const ESCAPE = null;
 | |
| const ESCAPE_ESCAPE_VALUE = null;
 | |
| const ESCAPE_END_OBJECT = true;
 | |
| const ESCAPE_UNDEFINED = false;
 | |
| 
 | |
| /**
 | |
|  * @param {Array<any>} data data
 | |
|  * @param {string} indent indent
 | |
|  * @returns {Promise<void>} promise
 | |
|  */
 | |
| const printData = async (data, indent) => {
 | |
| 	if (!Array.isArray(data)) throw new Error("Not an array");
 | |
| 	if (Buffer.isBuffer(data[0])) {
 | |
| 		for (const b of data) {
 | |
| 			if (typeof b === "function") {
 | |
| 				const innerData = await b();
 | |
| 				const info = /** @type {SizeInfo} */ (lazySizes.shift());
 | |
| 				const sizeInfo = `${(info.size / 1048576).toFixed(2)} MiB + ${(
 | |
| 					info.lazySize / 1048576
 | |
| 				).toFixed(2)} lazy MiB`;
 | |
| 				console.log(`${indent}= lazy ${sizeInfo} {`);
 | |
| 				await printData(innerData, `${indent}  `);
 | |
| 				console.log(`${indent}}`);
 | |
| 			} else {
 | |
| 				console.log(`${indent}= ${b.toString("hex")}`);
 | |
| 			}
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 	const referencedValues = new Map();
 | |
| 	const referencedValuesCounters = new Map();
 | |
| 	const referencedTypes = new Map();
 | |
| 	let currentReference = 0;
 | |
| 	let currentTypeReference = 0;
 | |
| 	let i = 0;
 | |
| 	const read = () => data[i++];
 | |
| 	/**
 | |
| 	 * @param {string} content content
 | |
| 	 */
 | |
| 	const printLine = content => {
 | |
| 		console.log(`${indent}${content}`);
 | |
| 	};
 | |
| 	printLine(`Version: ${read()}`);
 | |
| 	while (i < data.length) {
 | |
| 		const item = read();
 | |
| 		if (item === ESCAPE) {
 | |
| 			const nextItem = read();
 | |
| 			if (nextItem === ESCAPE_ESCAPE_VALUE) {
 | |
| 				printLine("null");
 | |
| 			} else if (nextItem === ESCAPE_UNDEFINED) {
 | |
| 				printLine("undefined");
 | |
| 			} else if (nextItem === ESCAPE_END_OBJECT) {
 | |
| 				indent = indent.slice(0, -2);
 | |
| 				printLine(`} = #${currentReference++}`);
 | |
| 			} else if (typeof nextItem === "number" && nextItem < 0) {
 | |
| 				const ref = currentReference + nextItem;
 | |
| 				const value = referencedValues.get(ref);
 | |
| 				referencedValuesCounters.set(
 | |
| 					ref,
 | |
| 					(referencedValuesCounters.get(ref) || 0) + 1
 | |
| 				);
 | |
| 				if (value) {
 | |
| 					printLine(
 | |
| 						`Reference ${nextItem} => ${JSON.stringify(value)} #${ref}`
 | |
| 					);
 | |
| 				} else {
 | |
| 					printLine(`Reference ${nextItem} => #${ref}`);
 | |
| 				}
 | |
| 			} else {
 | |
| 				const request = nextItem;
 | |
| 				if (typeof request === "number") {
 | |
| 					const ref = currentTypeReference - request;
 | |
| 					printLine(
 | |
| 						`Object (Reference ${request} => ${referencedTypes.get(
 | |
| 							ref
 | |
| 						)} @${ref}) {`
 | |
| 					);
 | |
| 				} else {
 | |
| 					const name = read();
 | |
| 					referencedTypes.set(currentTypeReference, `${request} / ${name}`);
 | |
| 					printLine(
 | |
| 						`Object (${request} / ${name} @${currentTypeReference++}) {`
 | |
| 					);
 | |
| 				}
 | |
| 				indent += "  ";
 | |
| 			}
 | |
| 		} else if (typeof item === "string") {
 | |
| 			if (item !== "") {
 | |
| 				referencedValues.set(currentReference, item);
 | |
| 				printLine(`${JSON.stringify(item)} = #${currentReference++}`);
 | |
| 			} else {
 | |
| 				printLine('""');
 | |
| 			}
 | |
| 		} else if (Buffer.isBuffer(item)) {
 | |
| 			printLine(`buffer ${item.toString("hex")} = #${currentReference++}`);
 | |
| 		} else if (typeof item === "function") {
 | |
| 			const innerData = await item();
 | |
| 			if (!SerializerMiddleware.isLazy(item, binaryMiddleware)) {
 | |
| 				const info = /** @type {SizeInfo} */ (lazySizes.shift());
 | |
| 				const sizeInfo = `${(info.size / 1048576).toFixed(2)} MiB + ${(
 | |
| 					info.lazySize / 1048576
 | |
| 				).toFixed(2)} lazy MiB`;
 | |
| 				printLine(`lazy-file ${sizeInfo} {`);
 | |
| 			} else {
 | |
| 				printLine("lazy-inline {");
 | |
| 			}
 | |
| 			await printData(innerData, `${indent}  `);
 | |
| 			printLine("}");
 | |
| 		} else {
 | |
| 			printLine(String(item));
 | |
| 		}
 | |
| 	}
 | |
| 	const refCounters = Array.from(referencedValuesCounters);
 | |
| 	refCounters.sort(([a, A], [b, B]) => B - A);
 | |
| 	printLine("SUMMARY: top references:");
 | |
| 	for (const [ref, count] of refCounters.slice(10)) {
 | |
| 		const value = referencedValues.get(ref);
 | |
| 		if (value) {
 | |
| 			printLine(`- #${ref} x ${count} = ${JSON.stringify(value)}`);
 | |
| 		} else {
 | |
| 			printLine(`- #${ref} x ${count}`);
 | |
| 		}
 | |
| 	}
 | |
| };
 | |
| 
 | |
| const filename = process.argv[2];
 | |
| 
 | |
| (async () => {
 | |
| 	const structure = await rawSerializer.deserialize(null, {
 | |
| 		filename: path.resolve(filename),
 | |
| 		extension: ".pack"
 | |
| 	});
 | |
| 	const info = await captureSize(structure);
 | |
| 	const sizeInfo = `${(info.size / 1048576).toFixed(2)} MiB + ${(
 | |
| 		info.lazySize / 1048576
 | |
| 	).toFixed(2)} lazy MiB`;
 | |
| 	console.log(`${filename} ${sizeInfo}:`);
 | |
| 
 | |
| 	const data = await serializer.deserialize(null, {
 | |
| 		filename: path.resolve(filename),
 | |
| 		extension: ".pack"
 | |
| 	});
 | |
| 	await printData(data, "");
 | |
| })();
 |