Skip to content

Commit d6c6a72

Browse files
committed
update extension
1 parent 655fa68 commit d6c6a72

13 files changed

Lines changed: 236 additions & 51 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
node_modules/
22
dist/
3+
dist-firefox/
34
*.zip
45
.env
56
.DS_Store

README.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Web2Vector — Chrome Extension
1+
# Web2Vector — Chrome and Firefox Extension
22

3-
A Chrome extension that exports any web page's rendered DOM to **10 output formats** using the [@node-projects/layout2vector](https://github.com/node-projects/layout2vector) library.
3+
A browser extension that exports any web page's rendered DOM to **10 output formats** using the [@node-projects/layout2vector](https://github.com/node-projects/layout2vector) library.
44

55
<p align="center">
66
<img src="src/icons/icon.svg" width="128" alt="Web2Vector icon" />
@@ -23,7 +23,7 @@ A Chrome extension that exports any web page's rendered DOM to **10 output forma
2323

2424
## Usage
2525

26-
1. Click the **Web2Vector** icon in the Chrome toolbar.
26+
1. Click the **Web2Vector** icon in the browser toolbar.
2727
2. Pick an export format from the popup menu.
2828
3. A **Save As** dialog appears — choose where to save the file.
2929

@@ -71,6 +71,12 @@ npm run build:all
7171
2. Enable **Developer mode** (top right)
7272
3. Click **Load unpacked** → select the `dist/` folder
7373

74+
### Load in Firefox
75+
76+
1. Navigate to `about:debugging#/runtime/this-firefox`
77+
2. Click **Load Temporary Add-on**
78+
3. Select the `manifest.json` file inside `dist-firefox/`
79+
7480
### Test
7581

7682
```bash
@@ -80,7 +86,9 @@ npm test
8086
### Package for Distribution
8187

8288
```bash
83-
npm run package # creates web2vector-<version>.zip
89+
npm run package # creates web2vector-chrome-<version>.zip
90+
npm run package:firefox # creates web2vector-firefox-<version>.zip
91+
npm run package:all-browsers # creates both ZIPs
8492
```
8593

8694
## Publishing to Chrome Web Store
@@ -106,7 +114,7 @@ Then create a GitHub Release to trigger the publish workflow, or use the manual
106114
## Project Structure
107115

108116
```
109-
├── manifest.json Chrome extension manifest (v3)
117+
├── manifest.json Chrome source manifest (v3)
110118
├── esbuild.config.mjs Build configuration
111119
├── src/
112120
│ ├── shared/formats.js Format definitions (shared by popup + background)
@@ -125,6 +133,7 @@ Then create a GitHub Release to trigger the publish workflow, or use the manual
125133
│ └── icon.svg Source icon
126134
├── scripts/
127135
│ ├── build-icons.mjs SVG → PNG conversion
136+
│ ├── manifest-utils.mjs Browser-specific manifest helpers
128137
│ ├── package-extension.mjs ZIP packaging
129138
│ └── upload-to-store.mjs Chrome Web Store upload
130139
├── tests/

esbuild.config.mjs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
import * as esbuild from 'esbuild';
22
import fs from 'node:fs';
33
import path from 'node:path';
4+
import { createFirefoxManifest, readChromeManifest } from './scripts/manifest-utils.mjs';
45

5-
const DIST = 'dist';
6+
const CHROME_DIST = 'dist';
7+
const FIREFOX_DIST = 'dist-firefox';
68

7-
// Ensure clean dist/
8-
fs.rmSync(DIST, { recursive: true, force: true });
9-
fs.mkdirSync(DIST, { recursive: true });
10-
fs.mkdirSync(path.join(DIST, 'icons'), { recursive: true });
9+
// Ensure clean build outputs
10+
for (const outDir of [CHROME_DIST, FIREFOX_DIST]) {
11+
fs.rmSync(outDir, { recursive: true, force: true });
12+
fs.mkdirSync(outDir, { recursive: true });
13+
fs.mkdirSync(path.join(outDir, 'icons'), { recursive: true });
14+
}
1115

1216
const commonOptions = {
1317
bundle: true,
1418
format: 'iife',
1519
platform: 'browser',
16-
target: 'chrome120',
20+
target: ['chrome120', 'firefox128'],
1721
treeShaking: true,
1822
minify: false, // keep readable for Chrome Web Store review
1923
sourcemap: false,
@@ -32,7 +36,7 @@ for (const entry of contentEntries) {
3236
await esbuild.build({
3337
...commonOptions,
3438
entryPoints: [entry],
35-
outfile: path.join(DIST, outName),
39+
outfile: path.join(CHROME_DIST, outName),
3640
});
3741
console.log(` ✔ ${outName}`);
3842
}
@@ -41,15 +45,15 @@ for (const entry of contentEntries) {
4145
await esbuild.build({
4246
...commonOptions,
4347
entryPoints: ['src/popup/popup.js'],
44-
outfile: path.join(DIST, 'popup.js'),
48+
outfile: path.join(CHROME_DIST, 'popup.js'),
4549
});
4650
console.log(' ✔ popup.js');
4751

4852
// ── Service worker ──
4953
await esbuild.build({
5054
...commonOptions,
5155
entryPoints: ['src/background/service-worker.js'],
52-
outfile: path.join(DIST, 'service-worker.js'),
56+
outfile: path.join(CHROME_DIST, 'service-worker.js'),
5357
});
5458
console.log(' ✔ service-worker.js');
5559

@@ -61,12 +65,12 @@ const statics = [
6165
];
6266

6367
for (const [src, dest] of statics) {
64-
fs.copyFileSync(src, path.join(DIST, dest));
68+
fs.copyFileSync(src, path.join(CHROME_DIST, dest));
6569
console.log(` ✔ ${dest} (copy)`);
6670
}
6771

6872
// Copy icons if they exist (generated by build:icons)
69-
const iconsDir = path.join(DIST, 'icons');
73+
const iconsDir = path.join(CHROME_DIST, 'icons');
7074
for (const size of [16, 32, 48, 128]) {
7175
const name = `icon${size}.png`;
7276
const src = path.join('src', 'icons', name);
@@ -76,4 +80,14 @@ for (const size of [16, 32, 48, 128]) {
7680
}
7781
}
7882

79-
console.log('\nBuild complete → dist/');
83+
fs.cpSync(CHROME_DIST, FIREFOX_DIST, { recursive: true });
84+
85+
const chromeManifest = readChromeManifest();
86+
const firefoxManifest = createFirefoxManifest(chromeManifest);
87+
fs.writeFileSync(
88+
path.join(FIREFOX_DIST, 'manifest.json'),
89+
`${JSON.stringify(firefoxManifest, null, 2)}\n`,
90+
);
91+
console.log(' ✔ dist-firefox/manifest.json (generated)');
92+
93+
console.log(`\nBuild complete → ${CHROME_DIST}/ and ${FIREFOX_DIST}/`);

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "web2vector-extension",
33
"version": "1.0.0",
4-
"description": "Chrome extension to export web pages to SVG, DXF, DWG, EMF, PDF, HTML, PNG, JPEG, and WebP using layout2vector",
4+
"description": "Browser extension to export web pages to SVG, DXF, DWG, EMF, PDF, HTML, PNG, JPEG, and WebP using layout2vector",
55
"private": true,
66
"type": "module",
77
"scripts": {
@@ -10,11 +10,13 @@
1010
"build:all": "npm run build:icons && npm run build",
1111
"test": "vitest run",
1212
"test:watch": "vitest",
13-
"package": "npm run build:all && node scripts/package-extension.mjs",
13+
"package": "npm run build:all && node scripts/package-extension.mjs chrome",
14+
"package:firefox": "npm run build:all && node scripts/package-extension.mjs firefox",
15+
"package:all-browsers": "npm run build:all && node scripts/package-extension.mjs chrome && node scripts/package-extension.mjs firefox",
1416
"upload": "node scripts/upload-to-store.mjs"
1517
},
1618
"dependencies": {
17-
"@node-projects/layout2vector": "^5.3.0",
19+
"@node-projects/layout2vector": "^5.4.0",
1820
"get-box-quads-polyfill": "^4.29.0"
1921
},
2022
"devDependencies": {

scripts/manifest-utils.mjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import fs from 'node:fs';
2+
3+
export function readChromeManifest(filePath = 'manifest.json') {
4+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
5+
}
6+
7+
export function createFirefoxManifest(chromeManifest) {
8+
const firefoxManifest = structuredClone(chromeManifest);
9+
firefoxManifest.background = {
10+
scripts: [chromeManifest.background.service_worker],
11+
};
12+
13+
return firefoxManifest;
14+
}

scripts/package-extension.mjs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,33 @@
11
/**
2-
* Package the built extension into a ZIP for Chrome Web Store upload.
3-
* Produces web2vector-<version>.zip in the project root.
2+
* Package the built extension into a ZIP for browser store upload.
43
*/
54
import archiver from 'archiver';
65
import fs from 'node:fs';
7-
import path from 'node:path';
86

97
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
10-
const zipName = `web2vector-${pkg.version}.zip`;
8+
const browser = process.argv[2] ?? 'chrome';
9+
const targets = {
10+
chrome: {
11+
sourceDir: 'dist',
12+
zipName: `web2vector-chrome-${pkg.version}.zip`,
13+
},
14+
firefox: {
15+
sourceDir: 'dist-firefox',
16+
zipName: `web2vector-firefox-${pkg.version}.zip`,
17+
},
18+
};
19+
20+
const target = targets[browser];
21+
22+
if (!target) {
23+
throw new Error(`Unknown package target: ${browser}`);
24+
}
25+
26+
if (!fs.existsSync(target.sourceDir)) {
27+
throw new Error(`Build output not found: ${target.sourceDir}`);
28+
}
29+
30+
const zipName = target.zipName;
1131
const output = fs.createWriteStream(zipName);
1232

1333
const archive = archiver('zip', { zlib: { level: 9 } });
@@ -19,5 +39,5 @@ archive.on('end', () => {
1939
});
2040

2141
archive.pipe(output);
22-
archive.directory('dist/', false);
42+
archive.directory(`${target.sourceDir}/`, false);
2343
await archive.finalize();

0 commit comments

Comments
 (0)