ISMIS Helper: cross-browser build, CI, PDF fixes, Chrome download fix
build-extension / build (push) Successful in 37s
build-extension / build (push) Successful in 37s
Squash merge of feat/ismis-helper into prod.
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
'use strict';
|
||||
// Zero-dependency build script: packages the extension for Firefox and Chrome.
|
||||
// Usage: node scripts/build.js [firefox|chrome|all] [--version X.Y.Z]
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const DIST = path.join(ROOT, 'dist');
|
||||
const FF_GECKO_ID = process.env.FF_GECKO_ID || 'ismis-helper@adrianbonpin';
|
||||
|
||||
// Order matters for the single-file Chrome service worker:
|
||||
// fontkit -> pdf-lib -> pdf.js -> background.js
|
||||
const CHROME_BG_PARTS = [
|
||||
'libs/fontkit.min.js',
|
||||
'libs/pdf-lib.min.js',
|
||||
'pdf.js',
|
||||
'background.js',
|
||||
];
|
||||
|
||||
// Everything to copy from ROOT into a target, relative paths.
|
||||
function collectFiles(srcDir, out = [], prefix = '') {
|
||||
for (const entry of fs.readdirSync(srcDir)) {
|
||||
const abs = path.join(srcDir, entry);
|
||||
const rel = prefix ? prefix + '/' + entry : entry;
|
||||
if (entry === '.git' || entry === 'node_modules' || entry === 'dist' ||
|
||||
entry === 'docs' || entry === 'scripts' || entry === 'test' ||
|
||||
entry === 'manifest.json' || entry.startsWith('.')) {
|
||||
continue;
|
||||
}
|
||||
if (fs.statSync(abs).isDirectory()) collectFiles(abs, out, rel);
|
||||
else out.push(rel);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function copyDir(relList, destDir) {
|
||||
for (const rel of relList) {
|
||||
const src = path.join(ROOT, rel);
|
||||
const dst = path.join(destDir, rel);
|
||||
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
||||
fs.copyFileSync(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
function readManifest() {
|
||||
return JSON.parse(fs.readFileSync(path.join(ROOT, 'manifest.json'), 'utf8'));
|
||||
}
|
||||
|
||||
// ---- STORED zip writer (no compression, valid for both browsers) ----
|
||||
function crc32(buf) {
|
||||
let table = [];
|
||||
for (let n = 0; n < 256; n++) {
|
||||
let c = n;
|
||||
for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
||||
table[n] = c >>> 0;
|
||||
}
|
||||
let crc = 0xffffffff;
|
||||
for (let i = 0; i < buf.length; i++) crc = table[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
|
||||
return (crc ^ 0xffffffff) >>> 0;
|
||||
}
|
||||
|
||||
function writeStoredZip(files, baseDir, zipPath) {
|
||||
const chunks = [];
|
||||
const central = [];
|
||||
let offset = 0;
|
||||
for (const rel of files) {
|
||||
const data = fs.readFileSync(path.join(baseDir, rel));
|
||||
const name = Buffer.from(rel, 'utf8');
|
||||
const crc = crc32(data);
|
||||
const lh = Buffer.alloc(30);
|
||||
lh.writeUInt32LE(0x04034b50, 0);
|
||||
lh.writeUInt16LE(20, 4);
|
||||
lh.writeUInt16LE(0, 6);
|
||||
lh.writeUInt16LE(0, 8); // method: stored
|
||||
lh.writeUInt16LE(0, 10);
|
||||
lh.writeUInt16LE(0, 12);
|
||||
lh.writeUInt32LE(crc, 14);
|
||||
lh.writeUInt32LE(data.length, 18);
|
||||
lh.writeUInt32LE(data.length, 22);
|
||||
lh.writeUInt16LE(name.length, 26);
|
||||
lh.writeUInt16LE(0, 28);
|
||||
chunks.push(lh, name, data);
|
||||
const ch = Buffer.alloc(46);
|
||||
ch.writeUInt32LE(0x02014b50, 0);
|
||||
ch.writeUInt16LE(20, 4);
|
||||
ch.writeUInt16LE(20, 6);
|
||||
ch.writeUInt16LE(0, 8);
|
||||
ch.writeUInt16LE(0, 10);
|
||||
ch.writeUInt16LE(0, 12);
|
||||
ch.writeUInt32LE(crc, 16);
|
||||
ch.writeUInt32LE(data.length, 20);
|
||||
ch.writeUInt32LE(data.length, 24);
|
||||
ch.writeUInt16LE(name.length, 28);
|
||||
ch.writeUInt16LE(0, 30);
|
||||
ch.writeUInt16LE(0, 32);
|
||||
ch.writeUInt16LE(0, 34);
|
||||
ch.writeUInt16LE(0, 36);
|
||||
ch.writeUInt32LE(0, 38);
|
||||
ch.writeUInt32LE(offset, 42);
|
||||
central.push(ch, name);
|
||||
offset += lh.length + name.length + data.length;
|
||||
}
|
||||
const cdStart = offset;
|
||||
let cdSize = 0;
|
||||
central.forEach((b) => { cdSize += b.length; });
|
||||
const eocd = Buffer.alloc(22);
|
||||
eocd.writeUInt32LE(0x06054b50, 0);
|
||||
eocd.writeUInt16LE(files.length, 8);
|
||||
eocd.writeUInt16LE(files.length, 10);
|
||||
eocd.writeUInt32LE(cdSize, 12);
|
||||
eocd.writeUInt32LE(cdStart, 16);
|
||||
eocd.writeUInt16LE(0, 20);
|
||||
const all = Buffer.concat([...chunks, ...central, eocd]);
|
||||
fs.writeFileSync(zipPath, all);
|
||||
}
|
||||
|
||||
function buildTarget(target, version) {
|
||||
const dir = path.join(DIST, target);
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
|
||||
const relList = collectFiles(ROOT);
|
||||
copyDir(relList, dir);
|
||||
|
||||
if (target === 'firefox') {
|
||||
const m = readManifest();
|
||||
if (version) m.version = version;
|
||||
m.browser_specific_settings = { gecko: { id: FF_GECKO_ID } };
|
||||
fs.writeFileSync(path.join(dir, 'manifest.json'), JSON.stringify(m, null, 2) + '\n');
|
||||
} else { // chrome
|
||||
const m = readManifest();
|
||||
if (version) m.version = version;
|
||||
delete m.background;
|
||||
m.background = { service_worker: 'background.chrome.js' };
|
||||
delete m.browser_specific_settings;
|
||||
fs.writeFileSync(path.join(dir, 'manifest.json'), JSON.stringify(m, null, 2) + '\n');
|
||||
const worker = CHROME_BG_PARTS
|
||||
.map((p) => fs.readFileSync(path.join(ROOT, p), 'utf8'))
|
||||
.join('\n;\n');
|
||||
fs.writeFileSync(path.join(dir, 'background.chrome.js'), worker);
|
||||
}
|
||||
|
||||
const suffix = version ? '-' + version : '';
|
||||
const zipName = path.join(DIST, `ismis-helper-${target}${suffix}.zip`);
|
||||
writeStoredZip(collectFiles(dir), dir, zipName);
|
||||
console.log(`built ${target}: ${zipName}`);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const args = process.argv.slice(2);
|
||||
const rawTargets = args.filter((a) => !a.startsWith('--'));
|
||||
const vi = args.indexOf('--version');
|
||||
let version = null;
|
||||
if (vi !== -1 && args[vi + 1]) version = String(args[vi + 1]).replace(/^v/, '');
|
||||
const requested = rawTargets.length ? rawTargets : ['all'];
|
||||
const targets = requested.includes('all')
|
||||
? ['firefox', 'chrome']
|
||||
: requested.filter((t) => t === 'firefox' || t === 'chrome');
|
||||
if (!targets.length) {
|
||||
console.error('Usage: node scripts/build.js [firefox|chrome|all] [--version X.Y.Z]');
|
||||
process.exit(1);
|
||||
}
|
||||
for (const t of targets) buildTarget(t, version);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user