Skip to content

Commit 9d754f5

Browse files
committed
Refactor manifest conversion for Firefox packaging
Replaced inline PowerShell/Node.js manifest conversion logic in build scripts with a dedicated Node.js script (convert-manifest-firefox.js) for improved reliability and maintainability. Updated build.bat and build.sh to use the new script for Firefox extension packaging.
1 parent 27ea3e5 commit 9d754f5

File tree

5 files changed

+66
-45
lines changed

5 files changed

+66
-45
lines changed

build/build.bat

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,14 @@ mkdir dist
2323

2424
REM Chrome/Edge packaging
2525
echo [PACK] Building Chrome/Edge version...
26-
REM Use tar to create zip with forward slashes to avoid Firefox AMO "Invalid file name" error
2726
tar -a -cf "dist\pixtab-%VERSION%-chrome.zip" manifest.json LICENSE index.html options.html style.css _locales icons src
2827

2928
REM Firefox packaging (temporarily modify manifest)
3029
echo [PACK] Building Firefox version...
3130
copy manifest.json manifest.backup.json >nul
3231

33-
REM Use PowerShell to parse and update JSON (more robust)
34-
REM Firefox does not support service_worker, convert to scripts array format
35-
powershell -Command "$m = Get-Content manifest.json -Raw | ConvertFrom-Json; if ($m.background -and $m.background.service_worker) { $sw = $m.background.service_worker; $type = $m.background.type; $m.background = New-Object PSObject; $m.background | Add-Member scripts @($sw); if ($type) { $m.background | Add-Member type $type } }; if ($m.action -and $m.action.default_icon -is [System.Collections.Hashtable]) { $icon = $m.action.default_icon.'48' -or $m.action.default_icon.'32' -or $m.action.default_icon.'16' -or $m.action.default_icon.'128'; if (-not $icon) { $icon = 'icons/icon-48.png' }; $m.action.default_icon = $icon }; if (-not $m.browser_specific_settings) { $m.browser_specific_settings = New-Object PSObject }; if (-not $m.browser_specific_settings.gecko) { $m.browser_specific_settings | Add-Member gecko (New-Object PSObject) }; $m.browser_specific_settings.gecko.strict_min_version = '113.0'; $m.browser_specific_settings | Add-Member gecko_android (New-Object PSObject -Property @{ strict_min_version = '113.0' }) -Force; $m | ConvertTo-Json -Depth 10 | Set-Content manifest.json"
36-
powershell -Command "$m = Get-Content manifest.json -Raw | ConvertFrom-Json; if ($m.background -and $m.background.service_worker) { $sw = $m.background.service_worker; $type = $m.background.type; $m.background = New-Object PSObject; $m.background | Add-Member -NotePropertyName scripts -NotePropertyValue @($sw); if ($type) { $m.background | Add-Member -NotePropertyName type -NotePropertyValue $type } }; if ($m.action -and $m.action.default_icon -is [System.Collections.Hashtable]) { $icon = $null; foreach ($k in @('48','32','16','128')) { if ($m.action.default_icon.ContainsKey($k) -and $m.action.default_icon.$k) { $icon = $m.action.default_icon.$k; break } }; if (-not $icon) { $icon = 'icons/icon-48.png' }; $m.action.default_icon = $icon }; if (-not $m.browser_specific_settings) { $m.browser_specific_settings = New-Object PSObject }; if (-not $m.browser_specific_settings.gecko) { $m.browser_specific_settings | Add-Member -NotePropertyName gecko -NotePropertyValue (New-Object PSObject) }; $m.browser_specific_settings.gecko.strict_min_version = '113.0'; if (-not $m.browser_specific_settings.gecko_android) { $m.browser_specific_settings | Add-Member -NotePropertyName gecko_android -NotePropertyValue (New-Object PSObject -Property @{ strict_min_version = '113.0' }) } else { $m.browser_specific_settings.gecko_android.strict_min_version = '113.0' }; if (-not $m.browser_specific_settings.gecko.data_collection_permissions) { $m.browser_specific_settings.gecko | Add-Member -NotePropertyName data_collection_permissions -NotePropertyValue (New-Object PSObject -Property @{ collects = $false; required = @('none'); optional = @() }) }; $m | ConvertTo-Json -Depth 10 | Set-Content manifest.json"
32+
REM Use external Node.js script for manifest conversion (more reliable)
33+
node "%~dp0convert-manifest-firefox.js"
3734

3835
tar -a -cf "dist\pixtab-%VERSION%-firefox.zip" manifest.json LICENSE index.html options.html style.css _locales icons src
3936

build/build.sh

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,37 @@
11
#!/bin/bash
2-
# PixTab 一键打包脚本 (macOS/Linux)
2+
# PixTab Build Script (macOS/Linux)
3+
# Generates Chrome/Edge and Firefox extension packages
34
set -e
45

5-
cd "$(dirname "$0")/.."
6+
SCRIPT_DIR="$(dirname "$0")"
7+
cd "$SCRIPT_DIR/.."
68

7-
echo "🔨 开始打包 PixTab..."
9+
echo "🔨 [BUILD] Starting PixTab packaging..."
810

9-
# 读取版本号
11+
# Read version from manifest.json
1012
VERSION=$(node -e "console.log(require('./manifest.json').version)")
11-
echo "📋 版本号: $VERSION"
13+
echo "📋 [INFO] Version: $VERSION"
1214

1315
rm -rf dist
1416
mkdir -p dist
1517

16-
# 打包 Chrome/Edge 版本
17-
echo "📦 打包 Chrome/Edge 版本..."
18+
# Chrome/Edge packaging
19+
echo "📦 [PACK] Building Chrome/Edge version..."
1820
zip -r "dist/pixtab-${VERSION}-chrome.zip" manifest.json LICENSE index.html options.html style.css _locales icons src -x "*.git*" -x "*.DS_Store"
1921

20-
# 打包 Firefox 版本(临时修改 manifest
21-
echo "📦 打包 Firefox 版本..."
22+
# Firefox packaging (temporarily modify manifest)
23+
echo "📦 [PACK] Building Firefox version..."
2224
cp manifest.json manifest.backup.json
2325

24-
# 用 Node.js 处理 manifest 字段,兼容 Firefox
25-
# Firefox 不支持 service_worker,需要转换为 scripts 数组格式
26-
node -e "
27-
const fs = require('fs');
28-
const manifestPath = 'manifest.json';
29-
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
30-
// Firefox 需要 scripts 数组而不是 service_worker
31-
if (manifest.background && manifest.background.service_worker) {
32-
const sw = manifest.background.service_worker;
33-
const type = manifest.background.type;
34-
manifest.background = { scripts: [sw] };
35-
if (type) manifest.background.type = type;
36-
}
37-
if (manifest.action && manifest.action.default_icon && typeof manifest.action.default_icon === 'object') {
38-
const sizes = ['48', '32', '16', '128'];
39-
let selected = null;
40-
for (const s of sizes) { if (manifest.action.default_icon[s]) { selected = manifest.action.default_icon[s]; break; } }
41-
if (!selected) selected = 'icons/icon-48.png';
42-
manifest.action.default_icon = selected;
43-
}
44-
if (!manifest.browser_specific_settings) manifest.browser_specific_settings = {};
45-
if (!manifest.browser_specific_settings.gecko) manifest.browser_specific_settings.gecko = {};
46-
manifest.browser_specific_settings.gecko.strict_min_version = '113.0';
47-
if (!manifest.browser_specific_settings.gecko_android) manifest.browser_specific_settings.gecko_android = {};
48-
manifest.browser_specific_settings.gecko_android.strict_min_version = '113.0';
49-
manifest.browser_specific_settings.gecko.data_collection_permissions = manifest.browser_specific_settings.gecko.data_collection_permissions || { collects: false, required: ['none'], optional: [] };
50-
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
51-
"
26+
# Use external Node.js script for manifest conversion (more reliable)
27+
node "$SCRIPT_DIR/convert-manifest-firefox.js"
5228

5329
zip -r "dist/pixtab-${VERSION}-firefox.xpi" manifest.json LICENSE index.html options.html style.css _locales icons src -x "*.git*" -x "*.DS_Store"
5430

31+
# Restore original manifest
5532
mv manifest.backup.json manifest.json
5633

5734
echo ""
58-
echo "打包完成!"
59-
echo " - dist/pixtab-${VERSION}-chrome.zip"
60-
echo " - dist/pixtab-${VERSION}-firefox.xpi"
35+
echo "[DONE] Packaging complete!"
36+
echo " - dist/pixtab-${VERSION}-chrome.zip -> Chrome Web Store / Edge Add-ons"
37+
echo " - dist/pixtab-${VERSION}-firefox.xpi -> Firefox AMO"

build/convert-manifest-firefox.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Convert manifest.json for Firefox compatibility
3+
* Firefox does not support service_worker in background, needs scripts array
4+
*/
5+
const fs = require('fs');
6+
const path = require('path');
7+
8+
const manifestPath = path.join(process.cwd(), 'manifest.json');
9+
const m = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
10+
11+
// Firefox needs scripts array instead of service_worker
12+
if (m.background && m.background.service_worker) {
13+
const sw = m.background.service_worker;
14+
const type = m.background.type;
15+
m.background = { scripts: [sw] };
16+
if (type) m.background.type = type;
17+
}
18+
19+
// Firefox prefers single icon string for action.default_icon
20+
if (m.action && m.action.default_icon && typeof m.action.default_icon === 'object') {
21+
const sizes = ['48', '32', '16', '128'];
22+
let selected = null;
23+
for (const s of sizes) {
24+
if (m.action.default_icon[s]) {
25+
selected = m.action.default_icon[s];
26+
break;
27+
}
28+
}
29+
if (!selected) selected = 'icons/icon-48.png';
30+
m.action.default_icon = selected;
31+
}
32+
33+
// Ensure browser_specific_settings for Firefox
34+
if (!m.browser_specific_settings) m.browser_specific_settings = {};
35+
if (!m.browser_specific_settings.gecko) m.browser_specific_settings.gecko = {};
36+
m.browser_specific_settings.gecko.strict_min_version = '113.0';
37+
38+
if (!m.browser_specific_settings.gecko_android) m.browser_specific_settings.gecko_android = {};
39+
m.browser_specific_settings.gecko_android.strict_min_version = '113.0';
40+
41+
// Data collection permissions for Firefox
42+
m.browser_specific_settings.gecko.data_collection_permissions =
43+
m.browser_specific_settings.gecko.data_collection_permissions ||
44+
{ collects: false, required: ['none'], optional: [] };
45+
46+
fs.writeFileSync(manifestPath, JSON.stringify(m, null, 2));
47+
console.log('[OK] Manifest converted for Firefox');

dist/pixtab-1.3-chrome.zip

0 Bytes
Binary file not shown.

dist/pixtab-1.3-firefox.xpi

-78 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)