Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"asar": true,
"asarUnpack": "**/*.node",
"afterPack": "scripts/afterPackHoock.js",
"afterSign": "scripts/afterSign.js",
"nsis": {
"perMachine": false,
"oneClick": true,
Expand Down
76 changes: 75 additions & 1 deletion scripts/afterPackHoock.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,76 @@
const path = require('path');
const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses');
const fs = require('fs');
const {
saveMetaData,
getTotalSize,
formatSize,
getFolderSizes,
} = require('./helpers/script/script-helper');
const {
compareAndPrint,
} = require('../scripts/helpers/terminal/terminal-helper');

const buildDir = './dist/win-unpacked';
const folderMetadataFile = './dist/bundle-analytics/folder-size-metadata.json';
const currentFolderMetaDataFile =
'./dist/bundle-analytics/folder-size-metadata.json';

const folderComparison = () => {
console.log(
'====================Build Size Changes By Folders====================\n',
);

const folderSizes = getFolderSizes(buildDir);
let previousBuildSizeTotal = 0;
let previousFolderSizes = {};
if (fs.existsSync(folderMetadataFile)) {
previousFolderSizes = JSON.parse(fs.readFileSync(folderMetadataFile));
previousBuildSizeTotal = Object.values(previousFolderSizes).reduce(
(prev, next) => prev + next,
0,
);
console.log('Comparing with previous metadata...\n');
compareAndPrint(folderSizes, previousFolderSizes, 0.01);

return previousBuildSizeTotal;
} else {
console.log('No previous metadata found. Creating one...');
}
saveMetaData(folderSizes, currentFolderMetaDataFile);
};

const analyzeBundle = (context, totalPreviousBuildSize) => {
console.log('\n====================Bundle overall====================\n');
const appDir = context.appOutDir;
console.log(`📦 Analyzing size of unpacked Electron app at: ${appDir}\n`);

const entries = fs.readdirSync(appDir);
let total = 0;

for (const entry of entries) {
// nosemgrep
const fullPath = path.join(appDir, entry);
const size = fs.statSync(fullPath).isDirectory()
? getTotalSize(fullPath, entry)
: fs.statSync(fullPath).size;

total += size;
console.log(`${formatSize(size).padEnd(10)} ${entry}`);
}

console.log(`\n🧮 Total pre-package size: ${formatSize(total)}\n`);
console.log(
`\n🧮 Overall Size Different: ${
total - totalPreviousBuildSize > 0 ? 'INCREASED by' : 'DECREASED by'
} ${formatSize(Math.abs(total - totalPreviousBuildSize))}\n`,
);
};

module.exports = async function afterPack(context) {
const {
appOutDir,
packager: { appInfo, platform },
packager: { appInfo },
} = context;
const ext = {
darwin: '.app',
Expand All @@ -18,4 +84,12 @@ module.exports = async function afterPack(context) {
version: FuseVersion.V1,
[FuseV1Options.EnableNodeCliInspectArguments]: false,
});

if (context.electronPlatformName === 'win32') {
// Run comparison for folder changes
const totalPreviousBuildSize = folderComparison();

// Run comparison for bundle changes
totalPreviousBuildSize && analyzeBundle(context, totalPreviousBuildSize);
}
};
57 changes: 57 additions & 0 deletions scripts/afterSign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const { getRawHeader } = require('@electron/asar');
const path = require('path');
const fs = require('fs');
const { saveMetaData } = require('./helpers/script/script-helper');
const {
compareAndPrint,
} = require('../scripts/helpers/terminal/terminal-helper');

const folderSnapshotFile = './dist/asar-size-metadata.json';
const currentFolderMetaDataFile =
'./dist/bundle-analytics/asar-size-metadata.json';

function getTotalSize(record) {
if ('size' in record) {
// FileRecord
return record.size;
} else {
// DirectoryRecord
return Object.values(record.files).reduce(
(sum, metadata) => sum + getTotalSize(metadata),
0,
);
}
}

async function getFileSizes(archivePath) {
const headerBuffer = await getRawHeader(archivePath);
const files = {};

for (const [fileName, fileMeta] of Object.entries(
headerBuffer.header.files,
)) {
files[fileName] = getTotalSize(fileMeta);
}

let previousFolderSizes = {};

if (fs.existsSync(folderSnapshotFile)) {
previousFolderSizes = JSON.parse(fs.readFileSync(folderSnapshotFile));
console.log('Comparing with previous metadata...\n');
compareAndPrint(files, previousFolderSizes, 0.01);
} else {
console.log('No previous metadata found. Creating one...');
}

saveMetaData(files, currentFolderMetaDataFile);
return files;
}

module.exports = async function afterSign(context) {
if (context.electronPlatformName === 'win32') {
const { appOutDir } = context;
// nosemgrep
const electronAsarPath = path.join(appOutDir, 'resources', 'app.asar');
await getFileSizes(electronAsarPath);
}
};
115 changes: 115 additions & 0 deletions scripts/compare.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
param(
[string]$BuildURL
)

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$buildNumber = $env:COMPARE_WIN_BUILD_VERSION
$currentAsarMetaData = "dist/bundle-analytics/asar-size-metadata.json"
$currentFolderMetaData = "dist/bundle-analytics/folder-size-metadata.json"
$output = "dist/bundle-analytics"

if ($buildNumber) {
$asarMetaData = curl "$BuildURL$buildNumber/artifact/dist/bundle-analytics/asar-size-metadata.json" | ConvertFrom-Json
$folderMetaData = curl "$BuildURL$buildNumber/artifact/dist/bundle-analytics/folder-size-metadata.json" | ConvertFrom-Json
Write-Host "Retrieving Build Metadata: $buildNumber"

# Format size - Auto shrink
function Format-Size {
param (
[double]$bytes
)

if ($bytes -ge 1GB) {
"$([math]::Round($bytes / 1GB, 2)) GB"
} elseif ($bytes -ge 1MB) {
$mb = $bytes / 1MB
if ($mb -lt 0.1) {
"$([math]::Round($bytes / 1KB, 2)) KB"
} else {
"$([math]::Round($mb, 2)) MB"
}
} elseif ($bytes -ge 1KB) {
"$([math]::Round($bytes / 1KB, 2)) KB"
} else {
"$bytes Bytes"
}
}

#Compare each meta-data
function Compare-Metadata {
param (
[PSCustomObject]$originalMetaData,
[PSCustomObject]$currentMetaData
)

# Get all unique property names from both JSON objects
$allKeys = ($originalMetaData.PSObject.Properties.Name + $currentMetaData.PSObject.Properties.Name) | Sort-Object -Unique

# Prepare a list to store comparison results
$comparison = @()

# Compare each property
foreach ($key in $allKeys) {
$originalMetaDataProperty = $originalMetaData.$key
$currentMetaDataProperty = $currentMetaData.$key

# Only compare if both values are numeric
if ($originalMetaDataProperty -is [int] -and $currentMetaDataProperty -is [int]) {
$sizeDiff = $currentMetaDataProperty - $originalMetaDataProperty
$status = if ($originalMetaDataProperty -gt $currentMetaDataProperty) {
"Decreased - [$(Format-Size -bytes $sizeDiff)]"
} elseif ($originalMetaDataProperty -lt $currentMetaDataProperty) {
"Increased - [$(Format-Size -bytes $sizeDiff)]"
} else {
"Equal"
}

$comparison += [PSCustomObject]@{
Property = $key
Original = $originalMetaDataProperty
Current = $currentMetaDataProperty
Status = $status
}
} else {
$comparison += [PSCustomObject]@{
Property = $key
Original = $originalMetaDataProperty
Current = $currentMetaDataProperty
Status = "Non-numeric or missing"
}
}
}

return [PSCustomObject]$comparison
}

#Retrieve comparison data
if ((Test-Path $currentAsarMetaData) -and (Test-Path $output)) {
Write-Host "📄 File '$currentAsarMetaData' found. Reading content..."
$currentAsarMetaDataContent = Get-Content -Path $currentAsarMetaData -Raw | ConvertFrom-Json
Write-Host "Retrieving comparison data - local asar package"
$comparisonAsar = Compare-Metadata $asarMetaData $currentAsarMetaDataContent
# Export to HTML
Write-Host "Print result"
$comparisonAsar | ConvertTo-Html -Title "Compare-asar" -Property Property, Original, Current, Status |
Out-File "$output/compare-asar.html"
} else {
Write-Host "!!!!!!File '$currentAsarMetaData' not found. Skipping JSON processing."
}

if ((Test-Path $currentFolderMetaData) -and (Test-Path $output)) {
Write-Host "📄 File '$currentFolderMetaData' found. Reading content..."
$currentFolderMetaDataContent = Get-Content -Path $currentFolderMetaData -Raw | ConvertFrom-Json
Write-Host "Retrieving comparison data - local asar package"
$comparisonFolder = Compare-Metadata $folderMetaData $currentFolderMetaDataContent
# Export to HTML
Write-Host "Print result"
$comparisonFolder | ConvertTo-Html -Title "Compare-folder" -Property Property, Original, Current, Status |
Out-File "$output/compare-folder.html"
} else {
Write-Host "!!!!!!File '$currentFolderMetaData' not found. Skipping JSON processing."
}

} else {
Write-Host "No indicator to compare, skip this"
}
15 changes: 15 additions & 0 deletions scripts/constant/unit.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* General Data Measuring Units
* Including BYTE | KB | MB | GB
*/
export declare const DataMeasurement: {
BYTE: string;
KB: string;
MB: string;
GB: string;
};

declare const _default: {
DataMeasurement: typeof DataMeasurement;
};
export default _default;
10 changes: 10 additions & 0 deletions scripts/constant/unit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const DataMeasurement = {
BYTE: 'B',
KB: 'KB',
MB: 'MB',
GB: 'GB',
};

exports.DataMeasurement = DataMeasurement;

exports.default = { DataMeasurement };
53 changes: 53 additions & 0 deletions scripts/helpers/script/script-helper.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Format current size as Bytes to readable unit accordingly as KB, MB, GB....
*
* @param byte @typeDef number - size as bytes
* @return Return {Converted Number} {Unit} as string
*/
export declare function formatSize(byte: number): string;

/**
* Convert Bytes to {unit}
*
* @param unit @typeDef DataMeasurement - which unit we should convert
* @param bytes @typeDef number - input bytes to get converted
*
* @return Return {Converted Number} based on Unit as number
*/
export declare function bytesTo(unit: string, bytes: number): number;

/**
* Recursively get total size of bundle
*
* @param dir as @string - Path to directory
*
* @return total size as number, throw error if dir is invalid
*/
export declare function getTotalSize(dir: string): number;

/**
* Save build meta data to {currentFolderSnapshotFile}
*
* @param data as @object - build meta data
* @param currentFolderSnapshotFile as @string - place to save the metadata file
*
*/
export declare function saveMetaData(data: any, dir: string): void;

/**
* Get general folder and content within sizes
*
* @param dir as @string - directory to read
*
* @returns stats as size of all files. I.E: {'file-001': 100Mb}
*/
export declare function getFolderSizes(dir: string): void;

declare const _default: {
formatSize: typeof formatSize;
bytesTo: typeof bytesTo;
getTotalSize: typeof getTotalSize;
saveMetaData: typeof saveMetaData;
getFolderSizes: typeof getFolderSizes;
};
export default _default;
Loading
Loading