|
| 1 | +import { cpSync, rmSync, readFileSync, writeFileSync, mkdirSync, existsSync, createWriteStream } from 'node:fs' |
| 2 | +import { resolve, dirname } from 'node:path' |
| 3 | +import { fileURLToPath } from 'node:url' |
| 4 | +import { createRequire } from 'node:module' |
| 5 | +import archiver from 'archiver' |
| 6 | + |
| 7 | +const require = createRequire(import.meta.url) |
| 8 | +const esbuild = require('esbuild') |
| 9 | + |
| 10 | +const root = resolve(dirname(fileURLToPath(import.meta.url)), '..') |
| 11 | +const distDir = resolve(root, 'dist') |
| 12 | +const firefoxDir = resolve(root, 'dist-firefox') |
| 13 | + |
| 14 | +if (!existsSync(distDir)) { |
| 15 | + console.error('[package-firefox] dist/ not found, run `pnpm build` first') |
| 16 | + process.exit(1) |
| 17 | +} |
| 18 | + |
| 19 | +rmSync(firefoxDir, { recursive: true, force: true }) |
| 20 | +cpSync(distDir, firefoxDir, { recursive: true }) |
| 21 | + |
| 22 | +// --- Bundle background script as IIFE --- |
| 23 | +// CRXJS outputs background as ES modules with code-split shared chunks. |
| 24 | +// Firefox background scripts don't support ES modules, so we rebundle |
| 25 | +// the entry point into a single IIFE via esbuild. |
| 26 | + |
| 27 | +const loaderPath = resolve(firefoxDir, 'service-worker-loader.js') |
| 28 | +const loaderCode = readFileSync(loaderPath, 'utf8') |
| 29 | +const entryMatch = loaderCode.match(/import\s+'\.\/(assets\/[^']+)'/) |
| 30 | +if (!entryMatch) { |
| 31 | + console.error('[package-firefox] could not resolve service-worker-loader entry') |
| 32 | + process.exit(1) |
| 33 | +} |
| 34 | + |
| 35 | +const entryPath = resolve(firefoxDir, entryMatch[1]) |
| 36 | +const backgroundPath = resolve(firefoxDir, 'background.js') |
| 37 | + |
| 38 | +await esbuild.build({ |
| 39 | + entryPoints: [entryPath], |
| 40 | + bundle: true, |
| 41 | + format: 'iife', |
| 42 | + outfile: backgroundPath, |
| 43 | + target: 'es2022', |
| 44 | + platform: 'browser', |
| 45 | + logLevel: 'warning' |
| 46 | +}) |
| 47 | + |
| 48 | +console.log('[package-firefox] bundled background.js as IIFE') |
| 49 | + |
| 50 | +// --- Transform manifest.json --- |
| 51 | + |
| 52 | +const manifestPath = resolve(firefoxDir, 'manifest.json') |
| 53 | +const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) |
| 54 | + |
| 55 | +if (manifest.background?.service_worker) { |
| 56 | + manifest.background = { scripts: ['background.js'] } |
| 57 | +} |
| 58 | + |
| 59 | +manifest.browser_specific_settings = { |
| 60 | + gecko: { |
| 61 | + id: 'stackprism@setube.github.io', |
| 62 | + strict_min_version: '128.0' |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)) |
| 67 | +console.log('[package-firefox] manifest.json transformed') |
| 68 | + |
| 69 | +// --- Package .xpi --- |
| 70 | + |
| 71 | +const releaseDir = resolve(root, 'release') |
| 72 | +if (!existsSync(releaseDir)) mkdirSync(releaseDir) |
| 73 | + |
| 74 | +const version = manifest.version |
| 75 | +const xpiName = `stackprism-v${version}.xpi` |
| 76 | +const xpiPath = resolve(releaseDir, xpiName) |
| 77 | + |
| 78 | +await new Promise((ok, reject) => { |
| 79 | + const output = createWriteStream(xpiPath) |
| 80 | + const archive = archiver('zip', { zlib: { level: 9 } }) |
| 81 | + output.on('close', ok) |
| 82 | + archive.on('error', reject) |
| 83 | + archive.pipe(output) |
| 84 | + archive.glob('**', { cwd: firefoxDir, dot: true }) |
| 85 | + archive.finalize() |
| 86 | +}) |
| 87 | + |
| 88 | +console.log(`[package-firefox] created release/${xpiName}`) |
0 commit comments