From bd6c05d1b48f2b1232ed8fd74cdda134bba78bfa Mon Sep 17 00:00:00 2001 From: Adrian Bonpin Date: Mon, 28 Sep 2026 02:23:12 +0800 Subject: [PATCH] fix(build): package manifest.json and drop dev files from zips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit collectFiles() skipped manifest.json unconditionally, and the final zip is produced by calling collectFiles() on the built target dir — so both dist/*.zip shipped with no manifest.json at all and could not be installed. The per-target manifest was written into the dir correctly, then filtered back out on the way into the archive. Split the exclusion list: EXCLUDED_DIRS plus DEV_ONLY_FILES (manifest.json, AGENTS.md, README.md, package.json, package-lock.json), and only apply the latter when reading the repo root. Reading a built target keeps its generated manifest. Firefox zip: 26 files/1.84 MB (no manifest) -> 23 files/1.68 MB. Chrome zip gains its manifest.json and background.chrome.js as before. --- scripts/build.js | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/scripts/build.js b/scripts/build.js index ff3ce8d..ca28779 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -20,18 +20,31 @@ const CHROME_BG_PARTS = [ 'background.js', ]; +// Directories never copied into a build target. +const EXCLUDED_DIRS = new Set([ + '.git', 'node_modules', 'dist', 'docs', 'scripts', 'test', 'web-ext-artifacts', +]); + +// Repo-root files that are for contributors, not for the shipped extension. +// manifest.json is here because it is generated per target, not copied. +const DEV_ONLY_FILES = new Set([ + 'manifest.json', 'AGENTS.md', 'README.md', 'package.json', 'package-lock.json', +]); + // Everything to copy from ROOT into a target, relative paths. -function collectFiles(srcDir, out = [], prefix = '') { +// `excludeDev` is true when reading ROOT (skip contributor files) and false when +// reading a built target (its generated manifest.json MUST be packaged). +function collectFiles(srcDir, { dir = '', excludeDev = false, out = [] } = {}) { 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; + const rel = dir ? dir + '/' + entry : entry; + if (entry.startsWith('.') || EXCLUDED_DIRS.has(entry)) continue; + if (excludeDev && DEV_ONLY_FILES.has(entry)) continue; + if (fs.statSync(abs).isDirectory()) { + collectFiles(abs, { dir: rel, excludeDev, out }); + } else { + out.push(rel); } - if (fs.statSync(abs).isDirectory()) collectFiles(abs, out, rel); - else out.push(rel); } return out; } @@ -122,7 +135,7 @@ function buildTarget(target, version) { fs.rmSync(dir, { recursive: true, force: true }); fs.mkdirSync(dir, { recursive: true }); - const relList = collectFiles(ROOT); + const relList = collectFiles(ROOT, { excludeDev: true }); copyDir(relList, dir); if (target === 'firefox') {