create-addfox-app 0.1.1-beta.10 → 0.1.1-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +85 -75
  3. package/package.json +2 -1
  4. package/templates/README.md +3 -0
  5. package/templates/template-preact-js/addfox.config.js +27 -0
  6. package/templates/template-preact-js/app/background/index.js +8 -0
  7. package/templates/template-preact-js/app/content/index.js +1 -0
  8. package/templates/template-preact-js/app/options/App.jsx +5 -0
  9. package/templates/template-preact-js/app/options/index.jsx +5 -0
  10. package/templates/template-preact-js/app/popup/App.jsx +23 -0
  11. package/templates/template-preact-js/app/popup/index.jsx +5 -0
  12. package/templates/template-preact-js/app/sidepanel/App.jsx +5 -0
  13. package/templates/template-preact-js/app/sidepanel/index.jsx +5 -0
  14. package/templates/template-preact-js/package.json +19 -0
  15. package/templates/template-preact-js/public/icons/icon_128.png +0 -0
  16. package/templates/template-preact-js/public/welcome.html +19 -0
  17. package/templates/template-preact-ts/addfox.config.ts +27 -0
  18. package/templates/template-preact-ts/app/background/index.ts +8 -0
  19. package/templates/template-preact-ts/app/content/index.ts +1 -0
  20. package/templates/template-preact-ts/app/options/App.tsx +5 -0
  21. package/templates/template-preact-ts/app/options/index.tsx +5 -0
  22. package/templates/template-preact-ts/app/popup/App.tsx +23 -0
  23. package/templates/template-preact-ts/app/popup/index.tsx +5 -0
  24. package/templates/template-preact-ts/app/sidepanel/App.tsx +5 -0
  25. package/templates/template-preact-ts/app/sidepanel/index.tsx +5 -0
  26. package/templates/template-preact-ts/package.json +21 -0
  27. package/templates/template-preact-ts/public/icons/icon_128.png +0 -0
  28. package/templates/template-preact-ts/public/welcome.html +19 -0
  29. package/templates/template-preact-ts/tsconfig.json +19 -0
  30. package/templates/template-react-js/addfox.config.js +27 -0
  31. package/templates/template-react-js/app/background/index.js +8 -0
  32. package/templates/template-react-js/app/content/index.js +1 -0
  33. package/templates/template-react-js/app/options/App.jsx +3 -0
  34. package/templates/template-react-js/app/options/index.jsx +5 -0
  35. package/templates/template-react-js/app/popup/App.jsx +21 -0
  36. package/templates/template-react-js/app/popup/index.jsx +5 -0
  37. package/templates/template-react-js/app/sidepanel/App.jsx +3 -0
  38. package/templates/template-react-js/app/sidepanel/index.jsx +5 -0
  39. package/templates/template-react-js/package.json +20 -0
  40. package/templates/template-react-js/public/icons/icon_128.png +0 -0
  41. package/templates/template-react-js/public/welcome.html +19 -0
  42. package/templates/template-react-ts/addfox.config.ts +27 -0
  43. package/templates/template-react-ts/app/background/index.ts +8 -0
  44. package/templates/template-react-ts/app/content/index.ts +1 -0
  45. package/templates/template-react-ts/app/options/App.tsx +3 -0
  46. package/templates/template-react-ts/app/options/index.tsx +5 -0
  47. package/templates/template-react-ts/app/popup/App.tsx +21 -0
  48. package/templates/template-react-ts/app/popup/index.tsx +5 -0
  49. package/templates/template-react-ts/app/sidepanel/App.tsx +3 -0
  50. package/templates/template-react-ts/app/sidepanel/index.tsx +5 -0
  51. package/templates/template-react-ts/package.json +24 -0
  52. package/templates/template-react-ts/public/icons/icon_128.png +0 -0
  53. package/templates/template-react-ts/public/welcome.html +19 -0
  54. package/templates/template-react-ts/tsconfig.json +19 -0
  55. package/templates/template-solid-js/addfox.config.js +28 -0
  56. package/templates/template-solid-js/app/background/index.js +8 -0
  57. package/templates/template-solid-js/app/content/index.js +1 -0
  58. package/templates/template-solid-js/app/options/App.jsx +3 -0
  59. package/templates/template-solid-js/app/options/index.jsx +5 -0
  60. package/templates/template-solid-js/app/popup/App.jsx +26 -0
  61. package/templates/template-solid-js/app/popup/index.jsx +5 -0
  62. package/templates/template-solid-js/app/sidepanel/App.jsx +3 -0
  63. package/templates/template-solid-js/app/sidepanel/index.jsx +5 -0
  64. package/templates/template-solid-js/package.json +20 -0
  65. package/templates/template-solid-js/public/icons/icon_128.png +0 -0
  66. package/templates/template-solid-js/public/welcome.html +19 -0
  67. package/templates/template-solid-ts/addfox.config.ts +28 -0
  68. package/templates/template-solid-ts/app/background/index.ts +8 -0
  69. package/templates/template-solid-ts/app/content/index.ts +1 -0
  70. package/templates/template-solid-ts/app/options/App.tsx +3 -0
  71. package/templates/template-solid-ts/app/options/index.tsx +5 -0
  72. package/templates/template-solid-ts/app/popup/App.tsx +26 -0
  73. package/templates/template-solid-ts/app/popup/index.tsx +5 -0
  74. package/templates/template-solid-ts/app/sidepanel/App.tsx +3 -0
  75. package/templates/template-solid-ts/app/sidepanel/index.tsx +5 -0
  76. package/templates/template-solid-ts/package.json +22 -0
  77. package/templates/template-solid-ts/public/icons/icon_128.png +0 -0
  78. package/templates/template-solid-ts/public/welcome.html +19 -0
  79. package/templates/template-solid-ts/tsconfig.json +19 -0
  80. package/templates/template-svelte-js/addfox.config.js +27 -0
  81. package/templates/template-svelte-js/app/background/index.js +8 -0
  82. package/templates/template-svelte-js/app/content/index.js +1 -0
  83. package/templates/template-svelte-js/app/options/App.svelte +4 -0
  84. package/templates/template-svelte-js/app/options/index.js +4 -0
  85. package/templates/template-svelte-js/app/popup/App.svelte +24 -0
  86. package/templates/template-svelte-js/app/popup/index.js +4 -0
  87. package/templates/template-svelte-js/app/sidepanel/App.svelte +4 -0
  88. package/templates/template-svelte-js/app/sidepanel/index.js +4 -0
  89. package/templates/template-svelte-js/package.json +19 -0
  90. package/templates/template-svelte-js/public/icons/icon_128.png +0 -0
  91. package/templates/template-svelte-js/public/welcome.html +19 -0
  92. package/templates/template-svelte-ts/addfox.config.ts +27 -0
  93. package/templates/template-svelte-ts/app/background/index.ts +8 -0
  94. package/templates/template-svelte-ts/app/content/index.ts +1 -0
  95. package/templates/template-svelte-ts/app/options/App.svelte +4 -0
  96. package/templates/template-svelte-ts/app/options/index.ts +4 -0
  97. package/templates/template-svelte-ts/app/popup/App.svelte +24 -0
  98. package/templates/template-svelte-ts/app/popup/index.ts +4 -0
  99. package/templates/template-svelte-ts/app/sidepanel/App.svelte +4 -0
  100. package/templates/template-svelte-ts/app/sidepanel/index.ts +4 -0
  101. package/templates/template-svelte-ts/package.json +21 -0
  102. package/templates/template-svelte-ts/public/icons/icon_128.png +0 -0
  103. package/templates/template-svelte-ts/public/welcome.html +19 -0
  104. package/templates/template-svelte-ts/tsconfig.json +19 -0
  105. package/templates/template-vanilla-js/addfox.config.js +25 -0
  106. package/templates/template-vanilla-js/app/background/index.js +8 -0
  107. package/templates/template-vanilla-js/app/content/index.js +1 -0
  108. package/templates/template-vanilla-js/app/options/index.js +2 -0
  109. package/templates/template-vanilla-js/app/popup/index.js +37 -0
  110. package/templates/template-vanilla-js/app/sidepanel/index.js +2 -0
  111. package/templates/template-vanilla-js/package.json +15 -0
  112. package/templates/template-vanilla-js/public/icons/icon_128.png +0 -0
  113. package/templates/template-vanilla-js/public/welcome.html +19 -0
  114. package/templates/template-vanilla-ts/addfox.config.ts +25 -0
  115. package/templates/template-vanilla-ts/app/background/index.ts +8 -0
  116. package/templates/template-vanilla-ts/app/content/index.ts +1 -0
  117. package/templates/template-vanilla-ts/app/options/index.ts +2 -0
  118. package/templates/template-vanilla-ts/app/popup/index.ts +37 -0
  119. package/templates/template-vanilla-ts/app/sidepanel/index.ts +2 -0
  120. package/templates/template-vanilla-ts/package.json +17 -0
  121. package/templates/template-vanilla-ts/public/icons/icon_128.png +0 -0
  122. package/templates/template-vanilla-ts/public/welcome.html +19 -0
  123. package/templates/template-vanilla-ts/tsconfig.json +17 -0
  124. package/templates/template-vue-js/addfox.config.js +27 -0
  125. package/templates/template-vue-js/app/background/index.js +8 -0
  126. package/templates/template-vue-js/app/content/index.js +1 -0
  127. package/templates/template-vue-js/app/options/App.vue +6 -0
  128. package/templates/template-vue-js/app/options/index.js +5 -0
  129. package/templates/template-vue-js/app/popup/App.vue +28 -0
  130. package/templates/template-vue-js/app/popup/index.js +5 -0
  131. package/templates/template-vue-js/app/sidepanel/App.vue +6 -0
  132. package/templates/template-vue-js/app/sidepanel/index.js +5 -0
  133. package/templates/template-vue-js/package.json +20 -0
  134. package/templates/template-vue-js/public/icons/icon_128.png +0 -0
  135. package/templates/template-vue-js/public/welcome.html +19 -0
  136. package/templates/template-vue-ts/addfox.config.ts +27 -0
  137. package/templates/template-vue-ts/app/background/index.ts +8 -0
  138. package/templates/template-vue-ts/app/content/index.ts +1 -0
  139. package/templates/template-vue-ts/app/options/App.vue +6 -0
  140. package/templates/template-vue-ts/app/options/index.ts +5 -0
  141. package/templates/template-vue-ts/app/popup/App.vue +26 -0
  142. package/templates/template-vue-ts/app/popup/index.ts +5 -0
  143. package/templates/template-vue-ts/app/sidepanel/App.vue +6 -0
  144. package/templates/template-vue-ts/app/sidepanel/index.ts +5 -0
  145. package/templates/template-vue-ts/package.json +23 -0
  146. package/templates/template-vue-ts/public/icons/icon_128.png +0 -0
  147. package/templates/template-vue-ts/public/welcome.html +19 -0
  148. package/templates/template-vue-ts/tsconfig.json +19 -0
package/README.md CHANGED
@@ -15,4 +15,4 @@ Interactive scaffolder: generates a addfox-based extension project from options
15
15
 
16
16
  ## Templates
17
17
 
18
- Scaffold templates live at **repo root** in **`templates/`** (e.g. `template-vanilla-ts`, `template-react-ts`). The CLI downloads the chosen template from the GitHub repo tarball, so the repo must have `templates/` at root and committed. The npm package does not bundle templates; it fetches from GitHub at scaffold time.
18
+ Scaffold templates ship inside this package under **`templates/`** (e.g. `template-vanilla-ts`, `template-react-ts`). They are included in the published npm tarball; the CLI copies the chosen folder into your new project (no remote download). The template’s **`addfox.config`** (including `manifest`) is **preserved**; the CLI only **merges** Rsbuild Less/Sass plugins when those style engines are selected. If no config file exists, a full fallback config is generated.
package/dist/cli.js CHANGED
@@ -8,17 +8,16 @@ import prompts from "prompts";
8
8
  import { blue, cyan, dim, gray, green, lightBlue, magenta, red, trueColor, yellow } from "kolorist";
9
9
  import minimist from "minimist";
10
10
  import { cp, mkdir } from "node:fs/promises";
11
- import { gunzipSync } from "node:zlib";
12
11
  import { detectPackageManager, getExecCommand, getInstallCommand, getRunCommand } from "@addfox/pkg-manager";
13
- const GITHUB_REPO = "addfox/addfox";
14
12
  const TEMPLATE_BASE = "templates";
15
- function getRepoRoot() {
16
- const fromDist = external_node_path_resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
17
- return fromDist;
13
+ function getPackageRoot() {
14
+ return external_node_path_resolve(dirname(fileURLToPath(import.meta.url)), "..");
15
+ }
16
+ function getBundledTemplatesDir() {
17
+ return join(getPackageRoot(), TEMPLATE_BASE);
18
18
  }
19
19
  function hasLocalTemplate(templateName) {
20
- const repoRoot = getRepoRoot();
21
- return existsSync(join(repoRoot, TEMPLATE_BASE, templateName));
20
+ return existsSync(join(getBundledTemplatesDir(), templateName));
22
21
  }
23
22
  const SKIP_TEMPLATE_PATH_PARTS = new Set([
24
23
  "node_modules",
@@ -30,10 +29,9 @@ function shouldCopyLocalTemplatePath(src) {
30
29
  for (const part of normalized)if (SKIP_TEMPLATE_PATH_PARTS.has(part)) return false;
31
30
  return true;
32
31
  }
33
- async function tryLocalTemplates(templateName, destDir) {
34
- const repoRoot = getRepoRoot();
35
- const templatePath = join(repoRoot, TEMPLATE_BASE, templateName);
36
- if (!existsSync(templatePath)) return false;
32
+ async function copyBundledTemplate(templateName, destDir) {
33
+ const templatePath = join(getBundledTemplatesDir(), templateName);
34
+ if (!existsSync(templatePath)) throw new Error(`Bundled template "${templateName}" not found under create-addfox-app. Reinstall the package.`);
37
35
  await mkdir(destDir, {
38
36
  recursive: true
39
37
  });
@@ -41,58 +39,6 @@ async function tryLocalTemplates(templateName, destDir) {
41
39
  recursive: true,
42
40
  filter: (src)=>shouldCopyLocalTemplatePath(src)
43
41
  });
44
- return true;
45
- }
46
- function parseTarHeader(buf) {
47
- if (buf.every((b)=>0 === b)) return null;
48
- const rawName = buf.subarray(0, 100).toString("utf8").replace(/\0+$/, "");
49
- const sizeStr = buf.subarray(124, 136).toString("utf8").replace(/\0+$/, "").trim();
50
- const type = String.fromCharCode(buf[156]);
51
- const prefix = buf.subarray(345, 500).toString("utf8").replace(/\0+$/, "");
52
- return {
53
- name: prefix ? `${prefix}/${rawName}` : rawName,
54
- size: parseInt(sizeStr, 8) || 0,
55
- type
56
- };
57
- }
58
- function extractMatchingFiles(tarBuffer, templatePrefix, destDir) {
59
- let offset = 0;
60
- while(offset + 512 <= tarBuffer.length){
61
- const header = parseTarHeader(tarBuffer.subarray(offset, offset + 512));
62
- offset += 512;
63
- if (!header) break;
64
- const dataBlocks = 512 * Math.ceil(header.size / 512);
65
- const idx = header.name.indexOf(templatePrefix);
66
- if (-1 !== idx) {
67
- const relativePath = header.name.substring(idx + templatePrefix.length).replace(/^\//, "");
68
- if (relativePath) {
69
- const destPath = join(destDir, relativePath);
70
- const isDir = "5" === header.type || relativePath.endsWith("/");
71
- if (isDir) mkdirSync(destPath, {
72
- recursive: true
73
- });
74
- else if ("0" === header.type || "\0" === header.type) {
75
- mkdirSync(dirname(destPath), {
76
- recursive: true
77
- });
78
- writeFileSync(destPath, tarBuffer.subarray(offset, offset + header.size));
79
- }
80
- }
81
- }
82
- offset += dataBlocks;
83
- }
84
- }
85
- async function downloadTemplate(templateName, destDir, branch = "main") {
86
- const url = `https://codeload.github.com/${GITHUB_REPO}/tar.gz/${branch}`;
87
- const templatePrefix = `${TEMPLATE_BASE}/${templateName}/`;
88
- const response = await fetch(url);
89
- if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
90
- const compressed = Buffer.from(await response.arrayBuffer());
91
- const tarBuffer = gunzipSync(compressed);
92
- mkdirSync(destDir, {
93
- recursive: true
94
- });
95
- extractMatchingFiles(tarBuffer, templatePrefix, destDir);
96
42
  }
97
43
  const FRAMES = [
98
44
  "⠋",
@@ -295,7 +241,7 @@ function getStylePlugin(engine) {
295
241
  };
296
242
  return null;
297
243
  }
298
- const MINIMAL_MANIFEST = ' name: "My Extension",\n version: "1.0.0",\n manifest_version: 3,\n description: "Browser extension built with addfox",\n permissions: ["storage", "activeTab"],';
244
+ const MINIMAL_MANIFEST = ' name: "My Extension",\n version: "1.0.0",\n manifest_version: 3,\n description: "Browser extension built with addfox",\n permissions: ["activeTab"],\n icons: {\n "16": "icons/icon_128.png",\n "48": "icons/icon_128.png",\n "128": "icons/icon_128.png",\n },\n action: {\n default_icon: {\n "16": "icons/icon_128.png",\n "48": "icons/icon_128.png",\n "128": "icons/icon_128.png",\n },\n },';
299
245
  function generateAddfoxConfig(framework, _language, styleEngine) {
300
246
  const importLines = [];
301
247
  const fwImport = getFrameworkPluginImport(framework);
@@ -323,6 +269,67 @@ function generateAddfoxConfig(framework, _language, styleEngine) {
323
269
  ];
324
270
  return parts.filter(Boolean).join("\n");
325
271
  }
272
+ const MANIFEST_LINE = " manifest: { chromium: manifest, firefox: { ...manifest } },";
273
+ function findMatchingArrayClose(source, openBracketIdx) {
274
+ if ("[" !== source[openBracketIdx]) return -1;
275
+ let depth = 0;
276
+ for(let i = openBracketIdx; i < source.length; i++){
277
+ const c = source[i];
278
+ if ("[" === c) depth++;
279
+ else if ("]" === c) {
280
+ depth--;
281
+ if (0 === depth) return i;
282
+ }
283
+ }
284
+ return -1;
285
+ }
286
+ function hasImportFromModule(source, modulePath) {
287
+ return source.includes(`from "${modulePath}"`) || source.includes(`from '${modulePath}'`) || source.includes(`from \`${modulePath}\``);
288
+ }
289
+ function insertImportAfterLastImport(source, importLine) {
290
+ const trimmed = importLine.trim();
291
+ const moduleMatch = /from\s+["']([^"']+)["']/.exec(trimmed);
292
+ if (moduleMatch && hasImportFromModule(source, moduleMatch[1])) return source;
293
+ const lines = source.split("\n");
294
+ let lastImportIdx = -1;
295
+ for(let i = 0; i < lines.length; i++)if (lines[i].trim().startsWith("import ")) lastImportIdx = i;
296
+ if (-1 === lastImportIdx) return `${importLine}\n${source}`;
297
+ const next = [
298
+ ...lines
299
+ ];
300
+ next.splice(lastImportIdx + 1, 0, importLine);
301
+ return next.join("\n");
302
+ }
303
+ function pluginCallPresent(inner, call) {
304
+ const fn = call.replace(/\(\)$/, "");
305
+ return inner.includes(`${fn}(`);
306
+ }
307
+ function mergeCallsIntoPluginsArray(source, calls) {
308
+ const pluginsIdx = source.indexOf("plugins:");
309
+ if (-1 === pluginsIdx) return addPluginsBlockAfterManifest(source, calls);
310
+ const bracketStart = source.indexOf("[", pluginsIdx);
311
+ if (-1 === bracketStart) return source;
312
+ const bracketEnd = findMatchingArrayClose(source, bracketStart);
313
+ if (-1 === bracketEnd) return source;
314
+ let inner = source.slice(bracketStart + 1, bracketEnd).trim();
315
+ for (const c of calls)if (!pluginCallPresent(inner, c)) inner = inner ? `${inner}, ${c}` : c;
316
+ return source.slice(0, bracketStart + 1) + inner + source.slice(bracketEnd);
317
+ }
318
+ function addPluginsBlockAfterManifest(source, calls) {
319
+ const idx = source.indexOf(MANIFEST_LINE);
320
+ if (-1 === idx) return source;
321
+ const insertPos = idx + MANIFEST_LINE.length;
322
+ return `${source.slice(0, insertPos)}\n plugins: [${calls.join(", ")}],${source.slice(insertPos)}`;
323
+ }
324
+ function mergeScaffoldIntoAddfoxConfig(source, styleEngine) {
325
+ const st = getStylePlugin(styleEngine);
326
+ if (!st) return source;
327
+ let out = insertImportAfterLastImport(source, st.importLine);
328
+ out = mergeCallsIntoPluginsArray(out, [
329
+ st.call
330
+ ]);
331
+ return out;
332
+ }
326
333
  const UTF8_BOM = "\uFEFF";
327
334
  function stripUtf8Bom(text) {
328
335
  return text.startsWith(UTF8_BOM) ? text.slice(UTF8_BOM.length) : text;
@@ -941,21 +948,20 @@ async function main() {
941
948
  if (!testSelection) process.exit(0);
942
949
  const pm = options.packageManager;
943
950
  const templateName = getTemplateName(options.framework, options.language);
944
- const useLocalTemplate = hasLocalTemplate(templateName);
945
- const templateLabel = useLocalTemplate ? "Copying local template..." : "Downloading template...";
946
- const LOCAL_TEMPLATE_SPINNER_MIN_MS = 800;
951
+ const templateReady = hasLocalTemplate(templateName);
952
+ const templateLabel = "Copying template...";
953
+ const TEMPLATE_SPINNER_MIN_MS = 800;
947
954
  try {
948
955
  await runWithTemplateSpinner(templateLabel, async ()=>{
949
- await new Promise((resolve)=>{
950
- setImmediate(resolve);
956
+ await new Promise((resolveSpinner)=>{
957
+ setImmediate(resolveSpinner);
951
958
  });
952
- if (await tryLocalTemplates(templateName, root)) return;
953
- await downloadTemplate(templateName, root);
954
- }, useLocalTemplate ? {
955
- minVisibleMs: LOCAL_TEMPLATE_SPINNER_MIN_MS
959
+ await copyBundledTemplate(templateName, root);
960
+ }, templateReady ? {
961
+ minVisibleMs: TEMPLATE_SPINNER_MIN_MS
956
962
  } : void 0);
957
963
  } catch (err) {
958
- console.error(red(`\n Failed to download template: ${err.message}\n`));
964
+ console.error(red(`\n Failed to copy template: ${err.message}\n`));
959
965
  process.exit(1);
960
966
  }
961
967
  const useAllEntries = options.entries.includes("__all__");
@@ -966,7 +972,11 @@ async function main() {
966
972
  if (!useAllEntries && effectiveEntries.length > 0) filterAppEntries(root, effectiveEntries);
967
973
  const configExt = "ts" === options.language ? "ts" : "js";
968
974
  const configPath = external_node_path_resolve(root, `addfox.config.${configExt}`);
969
- const configContent = generateAddfoxConfig(options.framework, options.language, options.styleEngine);
975
+ let configContent;
976
+ if (existsSync(configPath)) {
977
+ const existing = readFileSync(configPath, "utf-8");
978
+ configContent = existing.trim().length > 0 && existing.includes("defineConfig") ? mergeScaffoldIntoAddfoxConfig(existing, options.styleEngine) : generateAddfoxConfig(options.framework, options.language, options.styleEngine);
979
+ } else configContent = generateAddfoxConfig(options.framework, options.language, options.styleEngine);
970
980
  writeFileSync(configPath, configContent, "utf-8");
971
981
  updatePackageName(root, targetDir);
972
982
  applyStyleEngine(root, options.framework, options.language, options.styleEngine);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-addfox-app",
3
- "version": "0.1.1-beta.10",
3
+ "version": "0.1.1-beta.11",
4
4
  "description": "Interactive scaffolder for addfox extension projects",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,6 +9,7 @@
9
9
  },
10
10
  "files": [
11
11
  "dist",
12
+ "templates",
12
13
  "LICENSE"
13
14
  ],
14
15
  "dependencies": {
@@ -0,0 +1,3 @@
1
+ # Scaffold templates
2
+
3
+ Templates used by **create-addfox-app**. Each subdirectory (e.g. `template-vanilla-ts`, `template-react-ts`) is a full project skeleton. They live under this package and ship with the published npm tarball; the CLI copies the chosen folder into the new project directory.
@@ -0,0 +1,27 @@
1
+ import { defineConfig } from "addfox";
2
+ import { pluginPreact } from "@rsbuild/plugin-preact";
3
+
4
+ const manifest = {
5
+ name: "My Extension",
6
+ version: "1.0.0",
7
+ manifest_version: 3,
8
+ description: "Browser extension built with addfox",
9
+ permissions: ["activeTab"],
10
+ icons: {
11
+ "16": "icons/icon_128.png",
12
+ "48": "icons/icon_128.png",
13
+ "128": "icons/icon_128.png",
14
+ },
15
+ action: {
16
+ default_icon: {
17
+ "16": "icons/icon_128.png",
18
+ "48": "icons/icon_128.png",
19
+ "128": "icons/icon_128.png",
20
+ },
21
+ },
22
+ };
23
+
24
+ export default defineConfig({
25
+ manifest: { chromium: manifest, firefox: { ...manifest } },
26
+ plugins: [pluginPreact()],
27
+ });
@@ -0,0 +1,8 @@
1
+ function openWelcomePage() {
2
+ chrome.tabs.create({ url: chrome.runtime.getURL("welcome.html") });
3
+ }
4
+
5
+ chrome.runtime.onInstalled.addListener((details) => {
6
+ if (details.reason === "install" || details.reason === "update") openWelcomePage();
7
+ console.log("Extension installed");
8
+ });
@@ -0,0 +1 @@
1
+ console.log("Content script loaded");
@@ -0,0 +1,5 @@
1
+ import { h } from "preact";
2
+
3
+ export default function App() {
4
+ return <div>Hello from Preact</div>;
5
+ }
@@ -0,0 +1,5 @@
1
+ import { render, h } from "preact";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) render(h(App, null), root);
@@ -0,0 +1,23 @@
1
+ import { h } from "preact";
2
+
3
+ export default function App() {
4
+ const popupStyle = {
5
+ width: 320,
6
+ minHeight: 200,
7
+ padding: 16,
8
+ boxSizing: "border-box",
9
+ display: "flex",
10
+ flexDirection: "column",
11
+ alignItems: "center",
12
+ justifyContent: "center",
13
+ gap: 12,
14
+ fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
15
+ };
16
+
17
+ return (
18
+ <div style={popupStyle}>
19
+ <img src="/icons/icon_128.png" alt="" width={64} height={64} />
20
+ <div style={{ fontSize: 18, fontWeight: 600 }}>AddFox Preact</div>
21
+ </div>
22
+ );
23
+ }
@@ -0,0 +1,5 @@
1
+ import { render, h } from "preact";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) render(h(App, null), root);
@@ -0,0 +1,5 @@
1
+ import { h } from "preact";
2
+
3
+ export default function App() {
4
+ return <div>Hello from Preact</div>;
5
+ }
@@ -0,0 +1,5 @@
1
+ import { render, h } from "preact";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) render(h(App, null), root);
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "my-extension",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "addfox dev",
8
+ "build": "addfox build"
9
+ },
10
+ "dependencies": {
11
+ "addfox": "^0.1.1-beta.7",
12
+ "@rsbuild/core": "^1.7.3",
13
+ "@addfox/utils": "^0.1.1-beta.5",
14
+ "preact": "^10.29.0"
15
+ },
16
+ "devDependencies": {
17
+ "@rsbuild/plugin-preact": "^1.7.2"
18
+ }
19
+ }
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Welcome - Addfox + Preact</title>
7
+ <style>
8
+ body { font-family: system-ui, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; margin: 0; background: #fafafa; color: #1a1a1a; }
9
+ h1 { font-size: 1.75rem; font-weight: 700; margin: 0 0 0.5rem; }
10
+ p { font-size: 1rem; color: #666; margin: 0; }
11
+ .welcome-icon { width: 96px; height: 96px; margin-bottom: 1rem; object-fit: contain; border-radius: 12px; }
12
+ </style>
13
+ </head>
14
+ <body>
15
+ <img class="welcome-icon" src="/icons/icon_128.png" alt="" width="96" height="96" />
16
+ <h1>Addfox + Preact</h1>
17
+ <p>Your extension is ready. Happy building!</p>
18
+ </body>
19
+ </html>
@@ -0,0 +1,27 @@
1
+ import { defineConfig } from "addfox";
2
+ import { pluginPreact } from "@rsbuild/plugin-preact";
3
+
4
+ const manifest = {
5
+ name: "My Extension",
6
+ version: "1.0.0",
7
+ manifest_version: 3,
8
+ description: "Browser extension built with addfox",
9
+ permissions: ["activeTab"],
10
+ icons: {
11
+ "16": "icons/icon_128.png",
12
+ "48": "icons/icon_128.png",
13
+ "128": "icons/icon_128.png",
14
+ },
15
+ action: {
16
+ default_icon: {
17
+ "16": "icons/icon_128.png",
18
+ "48": "icons/icon_128.png",
19
+ "128": "icons/icon_128.png",
20
+ },
21
+ },
22
+ };
23
+
24
+ export default defineConfig({
25
+ manifest: { chromium: manifest, firefox: { ...manifest } },
26
+ plugins: [pluginPreact()],
27
+ });
@@ -0,0 +1,8 @@
1
+ function openWelcomePage() {
2
+ chrome.tabs.create({ url: chrome.runtime.getURL("welcome.html") });
3
+ }
4
+
5
+ chrome.runtime.onInstalled.addListener((details) => {
6
+ if (details.reason === "install" || details.reason === "update") openWelcomePage();
7
+ console.log("Extension installed");
8
+ });
@@ -0,0 +1 @@
1
+ console.log("Content script loaded");
@@ -0,0 +1,5 @@
1
+ import { h } from "preact";
2
+
3
+ export default function App() {
4
+ return <div>Hello from Preact</div>;
5
+ }
@@ -0,0 +1,5 @@
1
+ import { createRoot } from "react-dom/client";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) createRoot(root).render(<App />);
@@ -0,0 +1,23 @@
1
+ import { h } from "preact";
2
+
3
+ export default function App() {
4
+ const popupStyle = {
5
+ width: 320,
6
+ minHeight: 200,
7
+ padding: 16,
8
+ boxSizing: "border-box" as const,
9
+ display: "flex",
10
+ flexDirection: "column" as const,
11
+ alignItems: "center",
12
+ justifyContent: "center",
13
+ gap: 12,
14
+ fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
15
+ };
16
+
17
+ return (
18
+ <div style={popupStyle}>
19
+ <img src="/icons/icon_128.png" alt="" width={64} height={64} />
20
+ <div style={{ fontSize: 18, fontWeight: 600 }}>AddFox Preact</div>
21
+ </div>
22
+ );
23
+ }
@@ -0,0 +1,5 @@
1
+ import { createRoot } from "react-dom/client";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) createRoot(root).render(<App />);
@@ -0,0 +1,5 @@
1
+ import { h } from "preact";
2
+
3
+ export default function App() {
4
+ return <div>Hello from Preact</div>;
5
+ }
@@ -0,0 +1,5 @@
1
+ import { createRoot } from "react-dom/client";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) createRoot(root).render(<App />);
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "my-extension",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "addfox dev",
8
+ "build": "addfox build"
9
+ },
10
+ "dependencies": {
11
+ "addfox": "^0.1.1-beta.7",
12
+ "@rsbuild/core": "^1.7.3",
13
+ "@addfox/utils": "^0.1.1-beta.5",
14
+ "preact": "^10.29.0"
15
+ },
16
+ "devDependencies": {
17
+ "@rsbuild/plugin-preact": "^1.7.2",
18
+ "typescript": "^5.9.3",
19
+ "@types/chrome": "^0.1.38"
20
+ }
21
+ }
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Welcome - Addfox + Preact</title>
7
+ <style>
8
+ body { font-family: system-ui, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; margin: 0; background: #fafafa; color: #1a1a1a; }
9
+ h1 { font-size: 1.75rem; font-weight: 700; margin: 0 0 0.5rem; }
10
+ p { font-size: 1rem; color: #666; margin: 0; }
11
+ .welcome-icon { width: 96px; height: 96px; margin-bottom: 1rem; object-fit: contain; border-radius: 12px; }
12
+ </style>
13
+ </head>
14
+ <body>
15
+ <img class="welcome-icon" src="/icons/icon_128.png" alt="" width="96" height="96" />
16
+ <h1>Addfox + Preact</h1>
17
+ <p>Your extension is ready. Happy building!</p>
18
+ </body>
19
+ </html>
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "jsx": "react-jsx",
8
+ "resolveJsonModule": true,
9
+ "isolatedModules": true,
10
+ "noEmit": true,
11
+ "skipLibCheck": true,
12
+ "types": [
13
+ "chrome"
14
+ ]
15
+ },
16
+ "include": [
17
+ "app"
18
+ ]
19
+ }
@@ -0,0 +1,27 @@
1
+ import { defineConfig } from "addfox";
2
+ import { pluginReact } from "@rsbuild/plugin-react";
3
+
4
+ const manifest = {
5
+ name: "My Extension",
6
+ version: "1.0.0",
7
+ manifest_version: 3,
8
+ description: "Browser extension built with addfox",
9
+ permissions: ["activeTab"],
10
+ icons: {
11
+ "16": "icons/icon_128.png",
12
+ "48": "icons/icon_128.png",
13
+ "128": "icons/icon_128.png",
14
+ },
15
+ action: {
16
+ default_icon: {
17
+ "16": "icons/icon_128.png",
18
+ "48": "icons/icon_128.png",
19
+ "128": "icons/icon_128.png",
20
+ },
21
+ },
22
+ };
23
+
24
+ export default defineConfig({
25
+ manifest: { chromium: manifest, firefox: { ...manifest } },
26
+ plugins: [pluginReact()],
27
+ });
@@ -0,0 +1,8 @@
1
+ function openWelcomePage() {
2
+ chrome.tabs.create({ url: chrome.runtime.getURL("welcome.html") });
3
+ }
4
+
5
+ chrome.runtime.onInstalled.addListener((details) => {
6
+ if (details.reason === "install" || details.reason === "update") openWelcomePage();
7
+ console.log("Extension installed");
8
+ });
@@ -0,0 +1 @@
1
+ console.log("Content script loaded");
@@ -0,0 +1,3 @@
1
+ export default function App() {
2
+ return <div>Hello from React</div>;
3
+ }
@@ -0,0 +1,5 @@
1
+ import { createRoot } from "react-dom/client";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) createRoot(root).render(<App />);
@@ -0,0 +1,21 @@
1
+ export default function App() {
2
+ const popupStyle = {
3
+ width: 320,
4
+ minHeight: 200,
5
+ padding: 16,
6
+ boxSizing: "border-box",
7
+ display: "flex",
8
+ flexDirection: "column",
9
+ alignItems: "center",
10
+ justifyContent: "center",
11
+ gap: 12,
12
+ fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
13
+ };
14
+
15
+ return (
16
+ <div style={popupStyle}>
17
+ <img src="/icons/icon_128.png" alt="" width={64} height={64} />
18
+ <div style={{ fontSize: 18, fontWeight: 600 }}>AddFox React</div>
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,5 @@
1
+ import { createRoot } from "react-dom/client";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) createRoot(root).render(<App />);
@@ -0,0 +1,3 @@
1
+ export default function App() {
2
+ return <div>Hello from React</div>;
3
+ }
@@ -0,0 +1,5 @@
1
+ import { createRoot } from "react-dom/client";
2
+ import App from "./App";
3
+
4
+ const root = document.getElementById("root");
5
+ if (root) createRoot(root).render(<App />);