extension-develop 4.0.29 → 4.0.32

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.
package/README.md CHANGED
@@ -172,7 +172,7 @@ Options accepted by each command. Values shown are typical types or enumerations
172
172
  - Supported sections:
173
173
  - config(config: Configuration): mutate the assembled Rspack config. Supports a function or a plain object. When an object is provided, it is deep‑merged on top of the assembled config.
174
174
  - commands.dev | .build | .start | .preview: per‑command options (browser, profile, binaries, flags, preferences, unified logger defaults, packaging). These defaults are applied for all respective commands.
175
- - browser.chrome | .firefox | .edge | .chromium-based | .gecko-based: start flags, excluded flags, preferences, binaries, profile reuse (persistProfile), and per-browser `extensions`.
175
+ - browser.chrome | .firefox | .edge | .safari | .chromium-based | .gecko-based | .webkit-based: start flags, excluded flags, preferences, binaries, profile reuse (persistProfile), and per-browser `extensions`.
176
176
  - extensions: load-only companion extensions (unpacked dirs) loaded alongside your extension in dev/preview/start.
177
177
  - Example: { dir: "./extensions" } loads every "./extensions/\*" folder that contains a manifest.json.
178
178
  - Precedence when composing options (one contract for every command): stock defaults → browser._ → commands._ → CLI flags.
@@ -180,11 +180,11 @@ Options accepted by each command. Values shown are typical types or enumerations
180
180
  - Example: `commands.dev.polyfill: false` turns the polyfill off for the team, and `--polyfill` turns it back on for one run.
181
181
  - Lists (`browserFlags`, `excludeBrowserFlags`): concatenate across layers in order (browser, then command, then CLI) and dedupe.
182
182
  - Objects (`preferences`): deep-merge, later layers win on key conflict.
183
- - Browser key aliases when resolving `browser.*` from `extension.config.*`:
184
- - When the runtime asks for `chromium`, `loadBrowserConfig` prefers `browser.chromium` and then falls back to `browser['chromium-based']`.
183
+ - Browser key aliases when resolving `browser.*` from `extension.config.*` (engine families adopt product blocks; named products do not adopt engine-based blocks):
185
184
  - When the runtime asks for `chromium-based`, it prefers `browser['chromium-based']` and then `browser.chromium`.
186
- - When the runtime asks for `firefox`, it prefers `browser.firefox` and then `browser['gecko-based']`.
187
185
  - When the runtime asks for `gecko-based`, it prefers `browser['gecko-based']` and then `browser.firefox`.
186
+ - When the runtime asks for `webkit-based` **or any webkit-flavored fork name** (e.g. `acme-webkit`), it prefers the exact `browser.<name>` block, then `browser['webkit-based']`, then `browser.safari`.
187
+ - Named product `safari` only uses `browser.safari` (does not adopt `webkit-based`).
188
188
  - When detected, a one‑time notice is printed to indicate config is active.
189
189
 
190
190
  ### Companion extensions (load-only)
@@ -300,7 +300,7 @@ dist/
300
300
  | plugin-css | core | - Auto‑wires CSS for HTML and content scripts<br/>- Optional SASS/LESS/PostCSS when configs exist<br/>- Integrates Stylelint when configured |
301
301
  | plugin-js-frameworks | core | - Detects React/Preact/Vue/Svelte and TypeScript<br/>- Configures SWC parsing, loaders/plugins, and safe aliases<br/>- Sets `tsconfig` resolution<br/>- Defers heavy work to `beforeRun` in production |
302
302
  | plugin-static-assets | core | - Emits images, fonts, and misc files to `assets/`<br/>- Inlines small SVGs (≤2KB), emits larger ones<br/>- Content hashing in production; stable names in development<br/>- Respects existing custom SVG rules |
303
- | plugin-compatibility | core | - Cross‑browser helpers<br/>- Normalizes browser‑specific manifest fields<br/>- Optional `webextension-polyfill` for Chromium |
303
+ | plugin-compatibility | core | - Cross‑browser helpers<br/>- Normalizes browser‑specific manifest fields<br/>- Optional `webextension-polyfill` for Chromium (skipped for Firefox/Safari) |
304
304
  | plugin-compilation | core | - Loads env and templating (`EXTENSION_PUBLIC_*`)<br/>- Optional `dist/<browser>` cleaning<br/>- Compact, de‑duplicated compilation summary |
305
305
 
306
306
  ## Notes and compatibility
@@ -12,7 +12,7 @@ import { filterKeysForThisBrowser as external_browser_extension_manifest_fields_
12
12
  import content_security_policy_parser from "content-security-policy-parser";
13
13
  import node_fs from "node:fs";
14
14
  import node_path from "node:path";
15
- import { debugExtensionsToLoad, package_namespaceObject, getDirs, asAbsolute, browserRunnerDisabled, treeWithDistFilesBrowser, packagingDistributionFiles, toPosixPath, resolveCompanionExtensionDirs, debugContextPath, PlaywrightPlugin, isWebkitBasedBrowser, spacerLine, isGeckoBasedBrowser, messages_ready, CHROMIUM_FAMILY_ALIASES, treeWithSourceAndDistFiles, computeExtensionsToLoad, noCompanionExtensionsResolved, treeWithSourceFiles, bundlerFatalError, bundlerRecompiling, noEntrypointsDetected, GECKO_FAMILY_ALIASES, packagingSourceFiles, debugBrowser, debugOutputPath, manifestInvalidJson, isChromiumBasedBrowser, getSpecialFoldersDataForCompiler } from "./101.mjs";
15
+ import { debugExtensionsToLoad, package_namespaceObject, getDirs, asAbsolute, browserRunnerDisabled, treeWithDistFilesBrowser, packagingDistributionFiles, toPosixPath, resolveCompanionExtensionDirs, debugContextPath, PlaywrightPlugin, isGeckoBasedBrowser, spacerLine, isWebkitBasedBrowser, messages_ready, CHROMIUM_FAMILY_ALIASES, treeWithSourceAndDistFiles, computeExtensionsToLoad, noCompanionExtensionsResolved, treeWithSourceFiles, bundlerFatalError, bundlerRecompiling, noEntrypointsDetected, GECKO_FAMILY_ALIASES, packagingSourceFiles, debugBrowser, debugOutputPath, manifestInvalidJson, isChromiumBasedBrowser, getSpecialFoldersDataForCompiler } from "./101.mjs";
16
16
  import { stripBom, parseJsonSafe } from "./23.mjs";
17
17
  import { isResourceUnderDirs, canonicalizeDir, toResourceKey } from "./93.mjs";
18
18
  import { prefix as messaging_prefix, isDebug } from "./349.mjs";
@@ -246,6 +246,11 @@ class PolyfillPlugin {
246
246
  }
247
247
  }
248
248
  }
249
+ function polyfillSkipReason(browser) {
250
+ if (isGeckoBasedBrowser(String(browser))) return 'Firefox bundles browser.* APIs';
251
+ if (isWebkitBasedBrowser(String(browser))) return 'Safari ships a native promise-based browser.* namespace';
252
+ return null;
253
+ }
249
254
  class CompatibilityPlugin {
250
255
  static name = 'plugin-compatibility';
251
256
  manifestPath;
@@ -257,9 +262,9 @@ class CompatibilityPlugin {
257
262
  this.polyfill = options.polyfill || false;
258
263
  }
259
264
  apply(compiler) {
260
- const isGeckoFamily = isGeckoBasedBrowser(String(this.browser));
261
- if (this.polyfill) if (isGeckoFamily) {
262
- if (isDebug()) console.log(compatibilityPolyfillSkipped('Firefox bundles browser.* APIs', this.browser));
265
+ const skipReason = polyfillSkipReason(this.browser);
266
+ if (this.polyfill) if (skipReason) {
267
+ if (isDebug()) console.log(compatibilityPolyfillSkipped(skipReason, this.browser));
263
268
  } else {
264
269
  if (isDebug()) console.log(compatibilityPolyfillEnabled(this.browser, 'webextension-polyfill'));
265
270
  new PolyfillPlugin({
@@ -1001,10 +1006,12 @@ function declarativeNetRequest(manifest) {
1001
1006
  return manifest.declarative_net_request && {
1002
1007
  declarative_net_request: {
1003
1008
  ...manifest.declarative_net_request,
1004
- rule_resources: manifest.declarative_net_request.rule_resources.map((resourceObj)=>({
1005
- ...resourceObj,
1006
- path: resourceObj.path && getFilename(`declarative_net_request/${resourceObj.id}.json`, resourceObj.path)
1007
- }))
1009
+ ...Array.isArray(manifest.declarative_net_request.rule_resources) && {
1010
+ rule_resources: manifest.declarative_net_request.rule_resources.map((resourceObj)=>({
1011
+ ...resourceObj,
1012
+ path: resourceObj.path && getFilename(`declarative_net_request/${resourceObj.id}.json`, resourceObj.path)
1013
+ }))
1014
+ }
1008
1015
  }
1009
1016
  };
1010
1017
  }
@@ -1254,6 +1261,7 @@ class EnvPlugin {
1254
1261
  if (processShim) new ProvidePlugin({
1255
1262
  process: processShim
1256
1263
  }).apply(compiler);
1264
+ const templateVars = buildTemplateVars(combinedVars, this.browser, mode);
1257
1265
  compiler.hooks.thisCompilation.tap('manifest:update-manifest', (compilation)=>{
1258
1266
  compilation.hooks.processAssets.tap({
1259
1267
  name: 'env:module',
@@ -1264,29 +1272,11 @@ class EnvPlugin {
1264
1272
  if (filename.endsWith('.json') || filename.endsWith('.html')) {
1265
1273
  let fileContent = String(compilation.assets[filename]?.source() ?? '');
1266
1274
  const resolveVar = (name)=>{
1267
- if (Object.prototype.hasOwnProperty.call(process.env, name)) {
1268
- const systemValue = process.env[name];
1269
- if ('string' == typeof systemValue) return systemValue;
1270
- }
1271
- if (Object.prototype.hasOwnProperty.call(envVars, name)) {
1272
- const explicitEnvValue = envVars[name];
1273
- if ('string' == typeof explicitEnvValue) return explicitEnvValue;
1274
- }
1275
- if (Object.prototype.hasOwnProperty.call(defaultsVars, name)) {
1276
- const defaultsValue = defaultsVars[name];
1277
- if ('string' == typeof defaultsValue) return defaultsValue;
1278
- }
1279
- const combinedValue = combinedVars[name];
1280
- return 'string' == typeof combinedValue ? combinedValue : `$${name}`;
1275
+ if (Object.prototype.hasOwnProperty.call(templateVars, name)) return templateVars[name];
1276
+ return `$${name}`;
1281
1277
  };
1282
- fileContent = fileContent.replace(/\$EXTENSION_PUBLIC_[A-Z_]+/g, (match)=>{
1283
- const envVarName = match.slice(1);
1284
- return resolveVar(envVarName);
1285
- });
1286
- fileContent = fileContent.replace(/\$EXTENSION_[A-Z_]+/g, (match)=>{
1287
- const envVarName = match.slice(1);
1288
- return resolveVar(envVarName);
1289
- });
1278
+ fileContent = fileContent.replace(/\$EXTENSION_PUBLIC_[A-Z0-9_]+/g, (match)=>resolveVar(match.slice(1)));
1279
+ fileContent = fileContent.replace(/\$EXTENSION_[A-Z0-9_]+/g, (match)=>resolveVar(match.slice(1)));
1290
1280
  compilation.updateAsset(filename, new core_sources.RawSource(fileContent));
1291
1281
  if ('manifest.json' === filename) setCurrentManifestContent(compilation, fileContent);
1292
1282
  }
@@ -1295,6 +1285,17 @@ class EnvPlugin {
1295
1285
  });
1296
1286
  }
1297
1287
  }
1288
+ function buildTemplateVars(combinedVars, browser, mode) {
1289
+ const vars = {};
1290
+ for (const [key, value] of Object.entries(combinedVars))if ('string' == typeof value && key.startsWith('EXTENSION_')) vars[key] = value;
1291
+ const browserValue = String(browser);
1292
+ const modeValue = String(mode);
1293
+ vars.EXTENSION_BROWSER = browserValue;
1294
+ vars.EXTENSION_PUBLIC_BROWSER = browserValue;
1295
+ vars.EXTENSION_MODE = modeValue;
1296
+ vars.EXTENSION_PUBLIC_MODE = modeValue;
1297
+ return vars;
1298
+ }
1298
1299
  function sanitize(input) {
1299
1300
  return input.toLowerCase().replace(/[^a-z0-9 ]/gi, '').trim().replace(/\s+/g, '-');
1300
1301
  }
@@ -8672,11 +8673,16 @@ class ThrowIfRecompileIsNeeded {
8672
8673
  this.storeInitialHtmlAssets(htmlFields);
8673
8674
  compiler.hooks.make.tapAsync('html:throw-if-recompile-is-needed', (compilation, done)=>{
8674
8675
  const files = compiler.modifiedFiles || new Set();
8675
- const changedFile = Array.from(files)[0];
8676
- if (changedFile && this.initialHtmlAssets[changedFile]) {
8677
- const isRemoteUrl = (p)=>/^(https?:)?\/\//i.test(p);
8678
- const looksLikePublicRootUrl = (p)=>p.startsWith('/') && !__rspack_external_node_fs_5ea92f0c.existsSync(p);
8679
- const updatedAssets = __rspack_external_node_fs_5ea92f0c.existsSync(changedFile) ? getAssetsFromHtml(changedFile) : void 0;
8676
+ const isRemoteUrl = (p)=>/^(https?:)?\/\//i.test(p);
8677
+ const looksLikePublicRootUrl = (p)=>p.startsWith('/') && !__rspack_external_node_fs_5ea92f0c.existsSync(p);
8678
+ for (const changedFile of files){
8679
+ if (!this.initialHtmlAssets[changedFile]) continue;
8680
+ let updatedAssets;
8681
+ try {
8682
+ updatedAssets = getAssetsFromHtml(changedFile, __rspack_external_node_fs_5ea92f0c.readFileSync(changedFile, 'utf8'));
8683
+ } catch {
8684
+ updatedAssets = void 0;
8685
+ }
8680
8686
  const updatedJsEntries = (updatedAssets?.js || []).filter((p)=>!looksLikePublicRootUrl(p) && !isRemoteUrl(p));
8681
8687
  const updatedCssEntries = (updatedAssets?.css || []).filter((p)=>!looksLikePublicRootUrl(p) && !isRemoteUrl(p));
8682
8688
  const { js, css } = this.initialHtmlAssets[changedFile];
@@ -9591,11 +9597,11 @@ function serverRestartRequiredFromManifestError(fileAdded, fileRemoved) {
9591
9597
  lines.push("Restart the dev server to pick up changes to manifest entrypoints.");
9592
9598
  return lines.join('\n');
9593
9599
  }
9594
- function legacyManifestPathWarning(legacyPath) {
9600
+ function legacyManifestPathWarning(field, legacyPath, modernPath) {
9595
9601
  const lines = [];
9596
- lines.push(`${messaging_prefix('warn')} The manifest uses a deprecated path.`);
9602
+ lines.push(`${messaging_prefix('warn')} The ${pintor.blue(field)} field uses a deprecated scaffold path.`);
9597
9603
  lines.push(`${pintor.gray('PATH')} ${pintor.underline(legacyPath)}`);
9598
- lines.push("Extension.js rewrites it to the standardized folders in the next major.");
9604
+ lines.push(`Point it at ${pintor.underline(modernPath)}, Extension.js already emits the page there.`);
9599
9605
  return lines.join('\n');
9600
9606
  }
9601
9607
  function fatalManifestShapeFixed(field, detail) {
@@ -10053,40 +10059,100 @@ class EmitManifest {
10053
10059
  });
10054
10060
  }
10055
10061
  }
10062
+ const LEGACY_MANIFEST_PATH_RULES = [
10063
+ {
10064
+ field: 'devtools_page',
10065
+ legacyPath: 'devtools_page/devtools_page.html',
10066
+ modernPath: 'devtools/index.html'
10067
+ },
10068
+ {
10069
+ field: 'options_ui.page',
10070
+ legacyPath: 'options_ui/page.html',
10071
+ modernPath: 'options/index.html'
10072
+ },
10073
+ {
10074
+ field: 'background.page',
10075
+ legacyPath: 'background/page.html',
10076
+ modernPath: 'background/index.html'
10077
+ },
10078
+ {
10079
+ field: 'browser_action.default_popup',
10080
+ legacyPath: 'browser_action/default_popup.html',
10081
+ modernPath: 'action/index.html'
10082
+ },
10083
+ {
10084
+ field: 'page_action.default_popup',
10085
+ legacyPath: 'page_action/default_popup.html',
10086
+ modernPath: 'action/index.html'
10087
+ },
10088
+ {
10089
+ field: 'side_panel.default_path',
10090
+ legacyPath: 'side_panel/default_path.html',
10091
+ modernPath: 'sidebar/index.html'
10092
+ },
10093
+ {
10094
+ field: 'sidebar_action.default_panel',
10095
+ legacyPath: 'sidebar_action/default_panel.html',
10096
+ modernPath: 'sidebar/index.html'
10097
+ }
10098
+ ];
10099
+ function normalizeLegacyPathRef(raw) {
10100
+ return String(raw || '').replace(/\\/g, '/').replace(/^\.\//, '').replace(/^\//, '');
10101
+ }
10102
+ function readField(manifest, field) {
10103
+ if (!manifest || 'object' != typeof manifest || Array.isArray(manifest)) return;
10104
+ let current = manifest;
10105
+ for (const part of field.split('.')){
10106
+ if (!current || 'object' != typeof current || Array.isArray(current) || !(part in current)) return;
10107
+ current = current[part];
10108
+ }
10109
+ return current;
10110
+ }
10111
+ function findLegacyManifestPathHits(manifest) {
10112
+ const hits = [];
10113
+ for (const rule of LEGACY_MANIFEST_PATH_RULES){
10114
+ const value = readField(manifest, rule.field);
10115
+ if ('string' == typeof value && value.trim()) {
10116
+ if (normalizeLegacyPathRef(value) === rule.legacyPath) hits.push({
10117
+ field: rule.field,
10118
+ legacyPath: rule.legacyPath,
10119
+ modernPath: rule.modernPath
10120
+ });
10121
+ }
10122
+ }
10123
+ return hits;
10124
+ }
10056
10125
  class ManifestLegacyWarnings {
10057
10126
  static name = 'manifest:legacy-warnings';
10127
+ reportedHits = new Set();
10058
10128
  apply(compiler) {
10059
- if ('production' === (compiler.options.mode || 'development')) return;
10060
- const legacy = [
10061
- 'devtools_page/devtools_page.html',
10062
- 'options_ui/page.html',
10063
- 'background/page.html',
10064
- 'browser_action/default_popup.html',
10065
- 'page_action/default_popup.html',
10066
- 'side_panel/default_path.html',
10067
- 'sidebar_action/default_panel.html'
10068
- ];
10069
10129
  compiler.hooks.thisCompilation.tap(ManifestLegacyWarnings.name, (compilation)=>{
10070
10130
  compilation.hooks.processAssets.tap({
10071
10131
  name: ManifestLegacyWarnings.name,
10072
10132
  stage: core_Compilation.PROCESS_ASSETS_STAGE_REPORT
10073
10133
  }, ()=>{
10074
- const asset = compilation.getAsset('manifest.json');
10075
- if (!asset) return;
10076
- const text = asset.source.source().toString();
10077
- let count = 0;
10078
- legacy.forEach((needle)=>{
10079
- if (text.includes(needle)) {
10080
- const message = legacyManifestPathWarning(needle);
10081
- humanLine(message);
10082
- const warn = new core_WebpackError(message);
10083
- warn.name = 'ManifestLegacyWarning';
10084
- warn.file = 'manifest.json';
10085
- compilation.warnings.push(warn);
10086
- count++;
10134
+ const original = getOriginalManifestContent(compilation);
10135
+ if (!original) return;
10136
+ const manifest = parseJsonSafe(original);
10137
+ const hits = findLegacyManifestPathHits(manifest);
10138
+ if (0 === hits.length) return;
10139
+ const isDev = 'development' === compiler.options.mode;
10140
+ let printed = 0;
10141
+ for (const hit of hits){
10142
+ const signature = `${hit.field}\0${hit.legacyPath}`;
10143
+ if (isDev) {
10144
+ if (this.reportedHits.has(signature)) continue;
10145
+ this.reportedHits.add(signature);
10087
10146
  }
10088
- });
10089
- if (isDebug()) console.log(manifestLegacyWarningsSummary(count));
10147
+ const message = legacyManifestPathWarning(hit.field, hit.legacyPath, hit.modernPath);
10148
+ humanLine(message);
10149
+ const warn = new core_WebpackError(message);
10150
+ warn.name = 'ManifestLegacyWarning';
10151
+ warn.file = 'manifest.json';
10152
+ compilation.warnings.push(warn);
10153
+ printed++;
10154
+ }
10155
+ if (isDebug()) console.log(manifestLegacyWarningsSummary(printed));
10090
10156
  });
10091
10157
  });
10092
10158
  }
@@ -11953,6 +12019,7 @@ function patchGeckoBackground(manifest, browser) {
11953
12019
  class UpdateManifest {
11954
12020
  manifestPath;
11955
12021
  browser;
12022
+ reportedFatalFixes = new Set();
11956
12023
  constructor(options){
11957
12024
  this.manifestPath = options.manifestPath;
11958
12025
  this.browser = options.browser || 'chrome';
@@ -12001,7 +12068,13 @@ class UpdateManifest {
12001
12068
  } catch {}
12002
12069
  const sanitized = sanitizeFatalManifestShapes(patchedManifest, __rspack_external_node_path_c5b9b54f.dirname(this.manifestPath));
12003
12070
  patchedManifest = sanitized.manifest;
12071
+ const isDev = 'development' === compiler.options.mode;
12004
12072
  for (const fix of sanitized.fixes){
12073
+ if (isDev) {
12074
+ const signature = `${fix.field}\0${fix.detail}`;
12075
+ if (this.reportedFatalFixes.has(signature)) continue;
12076
+ this.reportedFatalFixes.add(signature);
12077
+ }
12005
12078
  const message = fatalManifestShapeFixed(fix.field, fix.detail);
12006
12079
  humanLine(message);
12007
12080
  const warn = new core_WebpackError(message);
@@ -12261,7 +12334,7 @@ function add_public_path_runtime_module_PublicPathRuntimeModule(compiler) {
12261
12334
  'try { __extjsRuntimePath = runtime.runtime.getURL(path); } catch (_) { __extjsRuntimePath = ""; }'
12262
12335
  ]),
12263
12336
  "}",
12264
- `${RuntimeGlobals.publicPath} = typeof importScripts === 'function' || !(isBrowser || isChrome) ? path : (__extjsRuntimePath || (__extjsBase ? __extjsBase.replace(/\\/+$/, "/") + String(path).replace(/^\\/+/, "") : ""));`
12337
+ `${RuntimeGlobals.publicPath} = typeof importScripts === 'function' ? path : (__extjsRuntimePath || (__extjsBase ? __extjsBase.replace(/\\/+$/, "/") + String(path).replace(/^\\/+/, "") : path));`
12265
12338
  ]);
12266
12339
  }
12267
12340
  }
package/dist/101.mjs CHANGED
@@ -19,6 +19,46 @@ import * as __rspack_external_node_fs_5ea92f0c from "node:fs";
19
19
  import * as __rspack_external_node_os_74b4b876 from "node:os";
20
20
  import * as __rspack_external_node_path_c5b9b54f from "node:path";
21
21
  import * as __rspack_external_node_vm_bd3d9cea from "node:vm";
22
+ __rspack_external_node_path_c5b9b54f.join(process.cwd(), 'node_modules/extension-develop/dist/certs');
23
+ const CHROMIUM_BASED_BROWSERS = [
24
+ 'chrome',
25
+ 'edge',
26
+ 'brave',
27
+ 'opera',
28
+ 'vivaldi',
29
+ 'yandex'
30
+ ];
31
+ const GECKO_BASED_BROWSERS = [
32
+ 'firefox',
33
+ 'waterfox',
34
+ 'librewolf'
35
+ ];
36
+ const WEBKIT_BASED_BROWSERS = [
37
+ 'safari'
38
+ ];
39
+ const CHROMIUM_FAMILY_ALIASES = [
40
+ 'chromium',
41
+ 'chrome',
42
+ 'edge',
43
+ 'chromium-based'
44
+ ];
45
+ const GECKO_FAMILY_ALIASES = [
46
+ 'firefox',
47
+ 'gecko-based'
48
+ ];
49
+ [
50
+ ...CHROMIUM_BASED_BROWSERS,
51
+ ...GECKO_BASED_BROWSERS
52
+ ];
53
+ function isChromiumBasedBrowser(browser) {
54
+ return CHROMIUM_BASED_BROWSERS.includes(browser) || String(browser).includes('chromium');
55
+ }
56
+ function isGeckoBasedBrowser(browser) {
57
+ return GECKO_BASED_BROWSERS.includes(browser) || String(browser).includes('gecko') || String(browser).includes('firefox');
58
+ }
59
+ function isWebkitBasedBrowser(browser) {
60
+ return WEBKIT_BASED_BROWSERS.includes(browser) || String(browser).includes('webkit');
61
+ }
22
62
  function getLoggingPrefix(type) {
23
63
  return messaging_prefix(type);
24
64
  }
@@ -601,14 +641,22 @@ async function loadBrowserConfig(projectPath, browser = 'chrome') {
601
641
  const userConfig = await loadConfigFile(configPath);
602
642
  if (userConfig?.browser) {
603
643
  const browsers = userConfig.browser;
644
+ const browserName = String(browser);
604
645
  if ('chromium-based' === browser) {
605
646
  if (browsers['chromium-based']) return browsers['chromium-based'];
606
647
  if (browsers.chromium) return browsers.chromium;
607
648
  } else if ('gecko-based' === browser) {
608
649
  if (browsers['gecko-based']) return browsers['gecko-based'];
609
650
  if (browsers.firefox) return browsers.firefox;
651
+ } else if (isWebkitBasedBrowser(browserName)) {
652
+ const direct = browsers[browserName];
653
+ if (direct) return direct;
654
+ if ('safari' !== browserName) {
655
+ if (browsers['webkit-based']) return browsers['webkit-based'];
656
+ if (browsers.safari) return browsers.safari;
657
+ }
610
658
  } else {
611
- const direct = browsers[browser];
659
+ const direct = browsers[browserName];
612
660
  if (direct) return direct;
613
661
  }
614
662
  }
@@ -634,7 +682,7 @@ async function config_loader_isUsingExperimentalConfig(projectPath) {
634
682
  }
635
683
  return false;
636
684
  }
637
- var package_namespaceObject = /*#__PURE__*/ JSON.parse('{"rE":"4.0.29","El":{"@prefresh/core":"1.5.9","@prefresh/utils":"1.2.1","@rspack/core":"^2.1.1","@rspack/dev-server":"2.1.0","@rspack/plugin-preact-refresh":"2.0.1","@rspack/plugin-react-refresh":"2.0.2","@vue/compiler-sfc":"3.5.26","acorn":"^8.16.0","adm-zip":"^0.6.0","browser-extension-manifest-fields":"^2.2.9","case-sensitive-paths-webpack-plugin":"^2.4.0","content-security-policy-parser":"^0.6.0","dotenv":"^17.2.3","es-module-lexer":"^2.1.0","extension-from-store":"^0.1.1","go-git-it":"^5.1.5","ignore":"^7.0.5","less":"4.6.7","less-loader":"13.0.0","parse5-utilities":"^1.0.0","pintor":"0.3.0","postcss":"8.5.23","postcss-loader":"8.2.1","postcss-preset-env":"11.1.1","postcss-scss":"4.0.9","preact":"10.27.3","prefers-yarn":"2.0.1","react-refresh":"0.18.0","sass-loader":"17.0.0","schema-utils":"^4.3.3","svelte-loader":"3.2.4","tiny-glob":"^0.2.9","vue":"3.5.26","vue-loader":"17.4.2","webextension-polyfill":"^0.12.0","webpack-merge":"^6.0.1","webpack-target-webextension":"^2.1.3","ws":"^8.20.1"}}');
685
+ var package_namespaceObject = /*#__PURE__*/ JSON.parse('{"rE":"4.0.32","El":{"@prefresh/core":"1.5.9","@prefresh/utils":"1.2.1","@rspack/core":"^2.1.1","@rspack/dev-server":"2.1.0","@rspack/plugin-preact-refresh":"2.0.1","@rspack/plugin-react-refresh":"2.0.2","@vue/compiler-sfc":"3.5.26","acorn":"^8.16.0","adm-zip":"^0.6.0","browser-extension-manifest-fields":"^2.2.9","case-sensitive-paths-webpack-plugin":"^2.4.0","content-security-policy-parser":"^0.6.0","dotenv":"^17.2.3","es-module-lexer":"^2.1.0","extension-from-store":"^0.1.1","go-git-it":"^5.1.5","ignore":"^7.0.5","less":"4.6.7","less-loader":"13.0.0","parse5-utilities":"^1.0.0","pintor":"0.3.0","postcss":"8.5.23","postcss-loader":"8.2.1","postcss-preset-env":"11.1.1","postcss-scss":"4.0.9","preact":"10.27.3","prefers-yarn":"2.0.1","react-refresh":"0.18.0","sass-loader":"17.0.0","schema-utils":"^4.3.3","svelte-loader":"3.2.4","tiny-glob":"^0.2.9","vue":"3.5.26","vue-loader":"17.4.2","webextension-polyfill":"^0.12.0","webpack-merge":"^6.0.1","webpack-target-webextension":"^2.1.3","ws":"^8.20.1"}}');
638
686
  function asAbsolute(p) {
639
687
  return __rspack_external_node_path_c5b9b54f.isAbsolute(p) ? p : __rspack_external_node_path_c5b9b54f.resolve(p);
640
688
  }
@@ -1182,46 +1230,6 @@ function assertNoManagedDependencyConflicts(userManifestPath, projectPath) {
1182
1230
  }
1183
1231
  if (duplicates.length > 0) throw new Error(managedDependencyConflict(duplicates, userManifestPath));
1184
1232
  }
1185
- __rspack_external_node_path_c5b9b54f.join(process.cwd(), 'node_modules/extension-develop/dist/certs');
1186
- const CHROMIUM_BASED_BROWSERS = [
1187
- 'chrome',
1188
- 'edge',
1189
- 'brave',
1190
- 'opera',
1191
- 'vivaldi',
1192
- 'yandex'
1193
- ];
1194
- const GECKO_BASED_BROWSERS = [
1195
- 'firefox',
1196
- 'waterfox',
1197
- 'librewolf'
1198
- ];
1199
- const WEBKIT_BASED_BROWSERS = [
1200
- 'safari'
1201
- ];
1202
- const CHROMIUM_FAMILY_ALIASES = [
1203
- 'chromium',
1204
- 'chrome',
1205
- 'edge',
1206
- 'chromium-based'
1207
- ];
1208
- const GECKO_FAMILY_ALIASES = [
1209
- 'firefox',
1210
- 'gecko-based'
1211
- ];
1212
- [
1213
- ...CHROMIUM_BASED_BROWSERS,
1214
- ...GECKO_BASED_BROWSERS
1215
- ];
1216
- function isChromiumBasedBrowser(browser) {
1217
- return CHROMIUM_BASED_BROWSERS.includes(browser) || String(browser).includes('chromium');
1218
- }
1219
- function isGeckoBasedBrowser(browser) {
1220
- return GECKO_BASED_BROWSERS.includes(browser) || String(browser).includes('gecko') || String(browser).includes('firefox');
1221
- }
1222
- function isWebkitBasedBrowser(browser) {
1223
- return WEBKIT_BASED_BROWSERS.includes(browser) || String(browser).includes('webkit');
1224
- }
1225
1233
  function idFromHash(hash) {
1226
1234
  const hex = hash.subarray(0, 16).toString('hex');
1227
1235
  let id = '';