extension-develop 3.15.0-next.1 → 3.15.1

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 (28) hide show
  1. package/dist/221.cjs +4 -2
  2. package/dist/{512.cjs → 442.cjs} +258 -119
  3. package/dist/extension-js-devtools/chrome/background/service_worker.js +2 -2
  4. package/dist/extension-js-devtools/chrome/content_scripts/content-0.js +2 -2
  5. package/dist/extension-js-devtools/chrome/manifest.json +0 -1
  6. package/dist/extension-js-devtools/chrome/scripts/logger-client.js +1 -0
  7. package/dist/extension-js-devtools/chromium/background/service_worker.js +2 -2
  8. package/dist/extension-js-devtools/chromium/content_scripts/content-0.js +2 -2
  9. package/dist/extension-js-devtools/chromium/manifest.json +0 -1
  10. package/dist/extension-js-devtools/chromium/scripts/logger-client.js +1 -0
  11. package/dist/extension-js-devtools/edge/background/service_worker.js +2 -2
  12. package/dist/extension-js-devtools/edge/content_scripts/content-0.js +2 -2
  13. package/dist/extension-js-devtools/edge/manifest.json +0 -1
  14. package/dist/extension-js-devtools/edge/scripts/logger-client.js +1 -0
  15. package/dist/extension-js-devtools/firefox/background/scripts.js +2 -2
  16. package/dist/extension-js-devtools/firefox/content_scripts/content-0.js +2 -2
  17. package/dist/extension-js-devtools/firefox/manifest.json +1 -1
  18. package/dist/extension-js-devtools/firefox/scripts/logger-client.js +1 -0
  19. package/dist/minimum-script-file.cjs +4 -3
  20. package/dist/minimum-script-file.js +4 -3
  21. package/dist/module.cjs +81 -34
  22. package/dist/preact-refresh-shim.cjs +25 -0
  23. package/dist/preview.cjs +25 -3
  24. package/package.json +2 -2
  25. package/dist/extension-js-devtools/chrome/content_scripts/styles.305cf4cf.css +0 -2
  26. package/dist/extension-js-devtools/chromium/content_scripts/styles.305cf4cf.css +0 -2
  27. package/dist/extension-js-devtools/edge/content_scripts/styles.305cf4cf.css +0 -2
  28. package/dist/extension-js-devtools/firefox/content_scripts/styles.305cf4cf.css +0 -2
package/dist/221.cjs CHANGED
@@ -464,7 +464,9 @@ exports.modules = {
464
464
  compress: false,
465
465
  devMiddleware: {
466
466
  writeToDisk: shouldWriteAssetToDisk,
467
- stats: false
467
+ stats: {
468
+ all: false
469
+ }
468
470
  },
469
471
  watchFiles: {
470
472
  paths: [
@@ -488,7 +490,7 @@ exports.modules = {
488
490
  },
489
491
  port,
490
492
  hot: true,
491
- liveReload: false
493
+ liveReload: true
492
494
  };
493
495
  const devServer = new dev_server_.RspackDevServer(serverConfig, compiler);
494
496
  const START_TIMEOUT_MS = parseInt(String(process.env.EXTENSION_START_TIMEOUT_MS || '30000'), 10);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  exports.ids = [
3
- 512
3
+ 442
4
4
  ];
5
5
  exports.modules = {
6
6
  "./dev-server/compiler-hooks.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
@@ -1451,6 +1451,7 @@ exports.modules = {
1451
1451
  bannerPrinted: false,
1452
1452
  pendingCompilationLine: ''
1453
1453
  };
1454
+ const BANNER_PRINTED_EVENT = 'extensionjs:banner-printed';
1454
1455
  function markBannerPrinted() {
1455
1456
  sharedState.bannerPrinted = true;
1456
1457
  if (sharedState.pendingCompilationLine) {
@@ -1458,6 +1459,15 @@ exports.modules = {
1458
1459
  sharedState.pendingCompilationLine = '';
1459
1460
  }
1460
1461
  }
1462
+ let listenerInstalled = false;
1463
+ function ensureBannerListener() {
1464
+ if (listenerInstalled) return;
1465
+ listenerInstalled = true;
1466
+ process.on(BANNER_PRINTED_EVENT, ()=>{
1467
+ markBannerPrinted();
1468
+ });
1469
+ }
1470
+ ensureBannerListener();
1461
1471
  function isBannerPrinted() {
1462
1472
  if (sharedState.bannerPrinted) return true;
1463
1473
  if ('true' === process.env.EXTENSION_CLI_BANNER_PRINTED) {
@@ -2199,14 +2209,14 @@ exports.modules = {
2199
2209
  {
2200
2210
  test: /\.css$/,
2201
2211
  exclude: /\.module\.css$/,
2202
- type: 'asset',
2212
+ type: 'asset/inline',
2203
2213
  loader: null
2204
2214
  },
2205
2215
  ...useSass ? [
2206
2216
  {
2207
2217
  test: /\.(sass|scss)$/,
2208
2218
  exclude: /\.module\.(sass|scss)$/,
2209
- type: 'asset',
2219
+ type: 'asset/inline',
2210
2220
  loader: 'sass-loader'
2211
2221
  },
2212
2222
  {
@@ -2219,7 +2229,7 @@ exports.modules = {
2219
2229
  {
2220
2230
  test: /\.less$/,
2221
2231
  exclude: /\.module\.less$/,
2222
- type: 'asset',
2232
+ type: 'asset/inline',
2223
2233
  loader: 'less-loader'
2224
2234
  },
2225
2235
  {
@@ -2229,32 +2239,22 @@ exports.modules = {
2229
2239
  }
2230
2240
  ] : []
2231
2241
  ];
2232
- const rules = await Promise.all(fileTypes.map(async ({ test, exclude, type = 'asset', loader })=>{
2233
- const baseConfig = {
2242
+ const rules = await Promise.all(fileTypes.map(async ({ test, exclude, type, loader })=>{
2243
+ const use = loader ? await commonStyleLoaders(projectPath, {
2244
+ mode: mode,
2245
+ loader: resolvePreprocessorLoader(loader, projectPath),
2246
+ loaderOptions: 'sass-loader' === loader ? createSassLoaderOptions(projectPath, mode) : {
2247
+ sourceMap: true
2248
+ }
2249
+ }) : await commonStyleLoaders(projectPath, {
2250
+ mode: mode
2251
+ });
2252
+ return {
2234
2253
  test,
2235
2254
  exclude,
2236
2255
  type,
2237
- issuer: isContentScript
2238
- };
2239
- if ('asset' === type) baseConfig.generator = {
2240
- filename: "content_scripts/[name].[contenthash:8].css"
2241
- };
2242
- if (!loader) return {
2243
- ...baseConfig,
2244
- use: await commonStyleLoaders(projectPath, {
2245
- mode: mode
2246
- })
2247
- };
2248
- const loaderOptions = 'sass-loader' === loader ? createSassLoaderOptions(projectPath, mode) : {
2249
- sourceMap: true
2250
- };
2251
- return {
2252
- ...baseConfig,
2253
- use: await commonStyleLoaders(projectPath, {
2254
- mode: mode,
2255
- loader: resolvePreprocessorLoader(loader, projectPath),
2256
- loaderOptions
2257
- })
2256
+ issuer: isContentScript,
2257
+ use
2258
2258
  };
2259
2259
  }));
2260
2260
  return rules;
@@ -2305,28 +2305,21 @@ exports.modules = {
2305
2305
  ] : []
2306
2306
  ];
2307
2307
  const rules = await Promise.all(fileTypes.map(async ({ test, exclude, type, loader })=>{
2308
- const baseConfig = {
2308
+ const use = loader ? await commonStyleLoaders(projectPath, {
2309
+ mode: mode,
2310
+ loader: css_in_html_loader_resolvePreprocessorLoader(loader, projectPath),
2311
+ loaderOptions: 'sass-loader' === loader ? createSassLoaderOptions(projectPath, mode) : {
2312
+ sourceMap: true
2313
+ }
2314
+ }) : await commonStyleLoaders(projectPath, {
2315
+ mode: mode
2316
+ });
2317
+ return {
2309
2318
  test,
2310
2319
  exclude,
2311
2320
  type,
2312
- issuer: isNotContentScript
2313
- };
2314
- if (!loader) return {
2315
- ...baseConfig,
2316
- use: await commonStyleLoaders(projectPath, {
2317
- mode: mode
2318
- })
2319
- };
2320
- const loaderOptions = 'sass-loader' === loader ? createSassLoaderOptions(projectPath, mode) : {
2321
- sourceMap: true
2322
- };
2323
- return {
2324
- ...baseConfig,
2325
- use: await commonStyleLoaders(projectPath, {
2326
- mode: mode,
2327
- loader: css_in_html_loader_resolvePreprocessorLoader(loader, projectPath),
2328
- loaderOptions
2329
- })
2321
+ issuer: isNotContentScript,
2322
+ use
2330
2323
  };
2331
2324
  }));
2332
2325
  return rules;
@@ -2380,8 +2373,8 @@ exports.modules = {
2380
2373
  const usingLess = (0, has_dependency.w)(projectPath, 'less');
2381
2374
  const maybeInstallStylelint = await maybeUseStylelint(projectPath);
2382
2375
  plugins.push(...maybeInstallStylelint);
2383
- const maybeInstallSass = await maybeUseSass(projectPath);
2384
- const maybeInstallLess = await maybeUseLess(projectPath, manifestPath);
2376
+ await maybeUseSass(projectPath);
2377
+ await maybeUseLess(projectPath, manifestPath);
2385
2378
  const loaders = [
2386
2379
  ...await cssInContentScriptLoader(projectPath, manifestPath, mode, {
2387
2380
  useSass: usingSass,
@@ -2392,24 +2385,6 @@ exports.modules = {
2392
2385
  useLess: usingLess
2393
2386
  })
2394
2387
  ];
2395
- if (maybeInstallSass.length) loaders.push({
2396
- test: /\.(sass|scss)$/,
2397
- exclude: /\.module\.(sass|scss)$/,
2398
- type: 'asset/resource',
2399
- generator: {
2400
- filename: "content_scripts/[name].[contenthash:8].css"
2401
- },
2402
- issuer: (issuer)=>isContentScriptEntry(issuer, manifestPath, projectPath)
2403
- });
2404
- if (maybeInstallLess.length) loaders.push({
2405
- test: /\.less$/,
2406
- exclude: /\.module\.less$/,
2407
- type: 'asset/resource',
2408
- generator: {
2409
- filename: "content_scripts/[name].[contenthash:8].css"
2410
- },
2411
- issuer: (issuer)=>isContentScriptEntry(issuer, manifestPath, projectPath)
2412
- });
2413
2388
  compiler.options.output.cssFilename = '[name].css';
2414
2389
  compiler.options.output.cssChunkFilename = '[name].css';
2415
2390
  compiler.options.plugins = [
@@ -2648,9 +2623,6 @@ exports.modules = {
2648
2623
  dependencyId: '@rspack/plugin-preact-refresh',
2649
2624
  moduleAdapter: (mod)=>mod && mod.default || mod
2650
2625
  });
2651
- const preactPlugins = [
2652
- new PreactRefreshPlugin({})
2653
- ];
2654
2626
  const requireFromProject = (0, external_module_.createRequire)(external_path_.join(projectPath, 'package.json'));
2655
2627
  const resolveFromProject = (id)=>{
2656
2628
  try {
@@ -2659,11 +2631,19 @@ exports.modules = {
2659
2631
  return;
2660
2632
  }
2661
2633
  };
2634
+ const preactPkgJson = resolveFromProject('preact/package.json');
2635
+ const preactDir = preactPkgJson ? external_path_.dirname(preactPkgJson) : void 0;
2662
2636
  const preactCompat = resolveFromProject('preact/compat');
2663
2637
  const preactTestUtils = resolveFromProject('preact/test-utils');
2664
2638
  const preactJsxRuntime = resolveFromProject('preact/jsx-runtime');
2665
2639
  const preactJsxDevRuntime = resolveFromProject('preact/jsx-dev-runtime');
2640
+ const preactPlugins = [
2641
+ new PreactRefreshPlugin(preactDir ? {
2642
+ preactPath: preactDir
2643
+ } : {})
2644
+ ];
2666
2645
  const alias = {};
2646
+ if (preactDir) alias.preact = preactDir;
2667
2647
  if (preactCompat) {
2668
2648
  alias.react = preactCompat;
2669
2649
  alias['react-dom'] = preactCompat;
@@ -2820,7 +2800,7 @@ exports.modules = {
2820
2800
  const defaultPlugins = [
2821
2801
  new VueLoaderPlugin(),
2822
2802
  new core_.DefinePlugin({
2823
- __VUE_OPTIONS_API__: JSON.stringify(true),
2803
+ __VUE_OPTIONS_API__: JSON.stringify(!isProd),
2824
2804
  __VUE_PROD_DEVTOOLS__: JSON.stringify(!isProd),
2825
2805
  __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: JSON.stringify(!isProd)
2826
2806
  })
@@ -3415,13 +3395,20 @@ exports.modules = {
3415
3395
  if (!outputPath) return;
3416
3396
  const csDir = external_path_.join(outputPath, "content_scripts");
3417
3397
  if (!external_fs_.existsSync(csDir)) return;
3418
- const hashedRe = /^content-\d+\.[a-f0-9]+\.(js|css)(\.map)?$/i;
3398
+ const emittedNames = new Set();
3399
+ const assets = 'function' == typeof compilation.getAssets ? compilation.getAssets() : [];
3400
+ for (const asset of assets){
3401
+ const name = asset?.name || '';
3402
+ if (name.startsWith("content_scripts/")) emittedNames.add(name);
3403
+ }
3404
+ const hashedRe = /^[A-Za-z0-9._-]+\.[a-f0-9]{6,}\.(js|css)(\.map)?$/i;
3419
3405
  try {
3420
3406
  for (const name of external_fs_.readdirSync(csDir)){
3421
3407
  if (!hashedRe.test(name)) continue;
3422
3408
  const rel = `content_scripts/${name}`;
3423
- if (!currentNames.has(rel)) {
3424
- if (!currentNames.has(rel.replace(/\.map$/, ''))) try {
3409
+ const relNoMap = rel.replace(/\.map$/, '');
3410
+ if (!(currentNames.has(rel) || currentNames.has(relNoMap))) {
3411
+ if (!(emittedNames.has(rel) || emittedNames.has(relNoMap))) try {
3425
3412
  external_fs_.unlinkSync(external_path_.join(csDir, name));
3426
3413
  } catch {}
3427
3414
  }
@@ -3899,7 +3886,19 @@ exports.modules = {
3899
3886
  }
3900
3887
  }
3901
3888
  const assetKeys = Object.keys(compilation.assets || {});
3902
- const cssUnderContentScripts = assetKeys.filter((k)=>k.startsWith("content_scripts/")).filter((k)=>k.endsWith('.css')).sort();
3889
+ const emittedCssUnderContentScripts = assetKeys.filter((k)=>k.startsWith("content_scripts/")).filter((k)=>k.endsWith('.css'));
3890
+ const onDiskCssUnderContentScripts = [];
3891
+ const outputPath = compilation.options.output?.path;
3892
+ if (outputPath) try {
3893
+ const csDir = external_path_.join(outputPath, "content_scripts");
3894
+ if (external_fs_.existsSync(csDir)) {
3895
+ for (const name of external_fs_.readdirSync(csDir))if (name.endsWith('.css')) onDiskCssUnderContentScripts.push(`content_scripts/${name}`);
3896
+ }
3897
+ } catch {}
3898
+ const cssUnderContentScripts = Array.from(new Set([
3899
+ ...emittedCssUnderContentScripts,
3900
+ ...onDiskCssUnderContentScripts
3901
+ ])).sort();
3903
3902
  if (Array.isArray(canonicalManifest.content_scripts)) for (const contentScript of canonicalManifest.content_scripts){
3904
3903
  const jsFiles = Array.isArray(contentScript.js) ? contentScript.js : [];
3905
3904
  const canonicalCss = jsFiles.map(toCanonicalContentScriptCss).filter((resource)=>Boolean(resource && cssUnderContentScripts.includes(resource)));
@@ -5322,6 +5321,7 @@ exports.modules = {
5322
5321
  ];
5323
5322
  if ('development' === compiler.options.mode) {
5324
5323
  if (devServerHmrImports.length > 0) fileAssets.unshift(...devServerHmrImports);
5324
+ fileAssets.unshift((0, develop_context.G5)('preact-refresh-shim'));
5325
5325
  const hmrScript = (0, develop_context.G5)("minimum-script-file");
5326
5326
  fileAssets.push(hmrScript);
5327
5327
  }
@@ -7534,8 +7534,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7534
7534
  manifestPath: this.manifestPath,
7535
7535
  includeList: this.includeList || {}
7536
7536
  }).apply(compiler);
7537
- const wrapperDisabled = 'production' === compiler.options.mode || 'true' === process.env.EXTENSION_NO_RELOAD;
7538
- if (!wrapperDisabled) new AddContentScriptWrapper({
7537
+ new AddContentScriptWrapper({
7539
7538
  manifestPath: this.manifestPath,
7540
7539
  browser: this.browser
7541
7540
  }).apply(compiler);
@@ -7600,6 +7599,9 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7600
7599
  function localesValidationDetected(issue) {
7601
7600
  return `Locales validation detected: ${issue}`;
7602
7601
  }
7602
+ function localesMustBeAtProjectRoot(foundAt, expectedAt) {
7603
+ return `_locales/ is canonically placed at the project root (sibling of package.json, public/, dist/) — mirroring public/ and how Chrome reads locales from the extension root in dist. Found in the legacy next-to-manifest location; the build will use it, but consider moving it for consistency with public/ and to silence this warning.\n\n found: ${foundAt}\n preferred: ${expectedAt}`;
7604
+ }
7603
7605
  function pushCompilationError(compiler, compilation, name, message, file) {
7604
7606
  const ErrorConstructor = compiler?.rspack?.WebpackError || Error;
7605
7607
  const error = new ErrorConstructor(message);
@@ -7608,14 +7610,60 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7608
7610
  if (!compilation.errors) compilation.errors = [];
7609
7611
  compilation.errors.push(error);
7610
7612
  }
7613
+ function isUsableDir(p) {
7614
+ try {
7615
+ return external_fs_.existsSync(p) && external_fs_.statSync(p).isDirectory();
7616
+ } catch {
7617
+ return false;
7618
+ }
7619
+ }
7620
+ function resolveLocalesFolder(manifestPath, projectRoot) {
7621
+ if (projectRoot) {
7622
+ const fromRoot = external_path_.join(projectRoot, '_locales');
7623
+ if (isUsableDir(fromRoot)) return fromRoot;
7624
+ }
7625
+ const fromManifest = external_path_.join(external_path_.dirname(manifestPath), '_locales');
7626
+ if (isUsableDir(fromManifest)) return fromManifest;
7627
+ }
7628
+ function listLocaleFiles(folder) {
7629
+ const out = [];
7630
+ for (const locale of external_fs_.readdirSync(folder)){
7631
+ const localeDir = external_path_.join(folder, locale);
7632
+ try {
7633
+ if (!external_fs_.statSync(localeDir).isDirectory()) continue;
7634
+ } catch {
7635
+ continue;
7636
+ }
7637
+ for (const entry of external_fs_.readdirSync(localeDir))out.push(external_path_.join(localeDir, entry));
7638
+ }
7639
+ return out;
7640
+ }
7641
+ function getLocales(manifestPath, projectRoot) {
7642
+ const localesFolder = resolveLocalesFolder(manifestPath, projectRoot);
7643
+ if (!localesFolder) return [];
7644
+ return listLocaleFiles(localesFolder);
7645
+ }
7611
7646
  function validateLocales(compiler, compilation, manifestPath) {
7647
+ const projectRoot = compiler.options.context || void 0;
7612
7648
  try {
7613
- const manifestDir = external_path_.dirname(manifestPath);
7614
7649
  const manifestRaw = external_fs_.readFileSync(manifestPath, 'utf8');
7615
7650
  const manifest = JSON.parse(manifestRaw);
7616
7651
  const defaultLocale = manifest?.default_locale;
7617
- const localesRoot = external_path_.join(manifestDir, '_locales');
7618
- const hasLocalesRoot = external_fs_.existsSync(localesRoot);
7652
+ const resolvedLocalesRoot = resolveLocalesFolder(manifestPath, projectRoot);
7653
+ const localesRoot = resolvedLocalesRoot || external_path_.join(external_path_.dirname(manifestPath), '_locales');
7654
+ const hasLocalesRoot = Boolean(resolvedLocalesRoot);
7655
+ if (projectRoot && resolvedLocalesRoot) {
7656
+ const manifestDir = external_path_.dirname(manifestPath);
7657
+ const sameAsRoot = external_path_.resolve(manifestDir) === external_path_.resolve(projectRoot);
7658
+ const usedManifestDirFallback = !sameAsRoot && external_path_.resolve(resolvedLocalesRoot) === external_path_.resolve(external_path_.join(manifestDir, '_locales'));
7659
+ if (usedManifestDirFallback) {
7660
+ const ErrorConstructor = compiler?.rspack?.WebpackError || Error;
7661
+ const warning = new ErrorConstructor(localesMustBeAtProjectRoot(resolvedLocalesRoot, external_path_.join(projectRoot, '_locales')));
7662
+ warning.name = 'LocalesLayoutWarning';
7663
+ if (!compilation.warnings) compilation.warnings = [];
7664
+ compilation.warnings.push(warning);
7665
+ }
7666
+ }
7619
7667
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(localesIncludeSummary(true, hasLocalesRoot, 'string' == typeof defaultLocale ? defaultLocale : void 0));
7620
7668
  if ('string' == typeof defaultLocale && defaultLocale.trim()) {
7621
7669
  if (!hasLocalesRoot) {
@@ -7675,9 +7723,8 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7675
7723
  }
7676
7724
  } catch {}
7677
7725
  try {
7678
- const manifestDir = external_path_.dirname(manifestPath);
7679
- const localesRoot = external_path_.join(manifestDir, '_locales');
7680
- if (external_fs_.existsSync(localesRoot)) {
7726
+ const localesRoot = resolveLocalesFolder(manifestPath, projectRoot);
7727
+ if (localesRoot && external_fs_.existsSync(localesRoot)) {
7681
7728
  const localeDirs = external_fs_.readdirSync(localesRoot).map((d)=>external_path_.join(localesRoot, d)).filter((p)=>external_fs_.statSync(p).isDirectory());
7682
7729
  for (const localeDir of localeDirs){
7683
7730
  const msgPath = external_path_.join(localeDir, 'messages.json');
@@ -7694,19 +7741,12 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7694
7741
  } catch {}
7695
7742
  return true;
7696
7743
  }
7697
- function getLocales(manifestPath) {
7698
- const localesFolder = external_path_.join(external_path_.dirname(manifestPath), '_locales');
7699
- const localeFiles = [];
7700
- if (external_fs_.existsSync(localesFolder)) for (const locale of external_fs_.readdirSync(localesFolder)){
7701
- const localeDir = external_path_.join(localesFolder, locale);
7702
- if (localeDir && external_fs_.statSync(localeDir).isDirectory()) for (const localeEntity of external_fs_.readdirSync(localeDir))localeFiles.push(external_path_.join(external_path_.dirname(manifestPath), '_locales', locale, localeEntity));
7703
- }
7704
- return localeFiles;
7705
- }
7706
7744
  function processLocaleAssets(compiler, compilation, manifestPath) {
7707
7745
  if (compilation.errors.length > 0) return;
7708
- const localesFields = getLocales(manifestPath);
7709
- const discoveredList = getLocales(manifestPath) || [];
7746
+ const projectRoot = compiler.options.context || void 0;
7747
+ const localesFields = getLocales(manifestPath, projectRoot);
7748
+ const discoveredList = getLocales(manifestPath, projectRoot) || [];
7749
+ const resolvedLocalesRoot = resolveLocalesFolder(manifestPath, projectRoot);
7710
7750
  let emittedCount = 0;
7711
7751
  let missingCount = 0;
7712
7752
  for (const field of Object.entries(localesFields || [])){
@@ -7726,8 +7766,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7726
7766
  }
7727
7767
  const source = external_fs_.readFileSync(thisResource);
7728
7768
  const rawSource = new core_.sources.RawSource(source);
7729
- const manifestDir = external_path_.dirname(manifestPath);
7730
- const localesRoot = external_path_.join(manifestDir, '_locales');
7769
+ const localesRoot = resolvedLocalesRoot || external_path_.join(external_path_.dirname(manifestPath), '_locales');
7731
7770
  const relativeToLocales = external_path_.relative(localesRoot, thisResource);
7732
7771
  const normalizedRel = relativeToLocales.split(external_path_.sep).join('/');
7733
7772
  const filename = `_locales/${normalizedRel}`;
@@ -7737,22 +7776,14 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7737
7776
  }
7738
7777
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(localesEmitSummary(emittedCount, missingCount, discoveredList.length));
7739
7778
  }
7740
- function trackLocaleDependencies(compilation, manifestPath) {
7779
+ function trackLocaleDependencies(compilation, manifestPath, projectRoot) {
7741
7780
  if (compilation.errors?.length) return;
7742
- const localesFields = getLocales(manifestPath);
7781
+ const localesFields = getLocales(manifestPath, projectRoot) || [];
7743
7782
  let added = 0;
7744
- for (const field of Object.entries(localesFields || [])){
7745
- const [, resource] = field;
7746
- if (resource) {
7747
- const fileDependencies = new Set(compilation.fileDependencies);
7748
- const fileResources = localesFields || [];
7749
- for (const thisResource of fileResources)if (external_fs_.existsSync(thisResource) && '.json' === external_path_.extname(thisResource)) {
7750
- if (!fileDependencies.has(thisResource)) {
7751
- fileDependencies.add(thisResource);
7752
- compilation.fileDependencies.add(thisResource);
7753
- added++;
7754
- }
7755
- }
7783
+ for (const thisResource of localesFields)if (external_fs_.existsSync(thisResource) && '.json' === external_path_.extname(thisResource)) {
7784
+ if (!compilation.fileDependencies.has(thisResource)) {
7785
+ compilation.fileDependencies.add(thisResource);
7786
+ added++;
7756
7787
  }
7757
7788
  }
7758
7789
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(localesDepsTracked(added));
@@ -7788,13 +7819,9 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7788
7819
  processLocaleAssets(compiler, compilation, this.manifestPath);
7789
7820
  });
7790
7821
  });
7791
- compiler.hooks.thisCompilation.tap('locales:module', (compilation)=>{
7792
- compilation.hooks.processAssets.tap({
7793
- name: 'locales:module',
7794
- stage: core_.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
7795
- }, ()=>{
7796
- trackLocaleDependencies(compilation, this.manifestPath);
7797
- });
7822
+ compiler.hooks.afterCompile.tap('locales:module', (compilation)=>{
7823
+ const projectRoot = compiler.options.context || void 0;
7824
+ trackLocaleDependencies(compilation, this.manifestPath, projectRoot);
7798
7825
  });
7799
7826
  }
7800
7827
  constructor(options){
@@ -8524,7 +8551,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8524
8551
  else if (val) scripts.push(val);
8525
8552
  const html = fields.html || {};
8526
8553
  const iconsRaw = fields.icons;
8527
- const icons = iconsRaw ? Array.isArray(iconsRaw) ? iconsRaw : Object.values(iconsRaw) : [];
8554
+ const icons = iconsRaw ? Array.isArray(iconsRaw) ? iconsRaw : flattenValues(iconsRaw) : [];
8528
8555
  const jsonMap = fields.json || {};
8529
8556
  const json = [];
8530
8557
  for (const [key, val] of Object.entries(jsonMap))if (isCriticalJsonFeatureKey(key)) {
@@ -8871,6 +8898,117 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8871
8898
  }
8872
8899
  }
8873
8900
  plugin_wasm_define_property(WasmPlugin, "name", 'plugin-wasm');
8901
+ const PAGE_DIRS = [
8902
+ 'pages',
8903
+ 'sidebar',
8904
+ 'popup',
8905
+ 'options',
8906
+ 'options_ui',
8907
+ 'devtools',
8908
+ 'newtab',
8909
+ 'sandbox',
8910
+ 'action',
8911
+ 'browser_action',
8912
+ 'page_action'
8913
+ ];
8914
+ const isCodeAsset = (name)=>/\.(js|css|wasm)$/i.test(name);
8915
+ const categorize_isSourceMap = (name)=>/\.map$/i.test(name);
8916
+ const isHotUpdate = (name)=>/(^|\/)hot\//.test(name);
8917
+ function categorizeAsset(rawName) {
8918
+ const name = String(rawName || '').replace(/\\/g, '/');
8919
+ if (!name) return 'ignored';
8920
+ if (!isCodeAsset(name)) return 'ignored';
8921
+ if (categorize_isSourceMap(name)) return 'ignored';
8922
+ if (isHotUpdate(name)) return 'ignored';
8923
+ if (/(^|\/)content_scripts\//.test(name)) return "content-script";
8924
+ if (/(^|\/)background\//.test(name) || /(^|\/)service[-_]?worker\.(js|css|wasm)$/i.test(name)) return 'service-worker';
8925
+ for (const dir of PAGE_DIRS)if (new RegExp(`(^|\\/)${dir}\\/`).test(name)) return 'page';
8926
+ return 'ignored';
8927
+ }
8928
+ const BUDGET_BYTES = {
8929
+ "content-script": 262144,
8930
+ 'service-worker': 204800,
8931
+ page: 512000,
8932
+ ignored: 1 / 0
8933
+ };
8934
+ function fmtKiB(bytes) {
8935
+ const kib = bytes / 1024;
8936
+ if (kib >= 1024) return `${(kib / 1024).toFixed(2)} MiB`;
8937
+ return `${kib.toFixed(1)} KiB`;
8938
+ }
8939
+ function perfBudgetWarning(assets) {
8940
+ const header = `${1 === assets.length ? 'asset exceeds' : 'assets exceed'} the extension performance budget. Browser extensions inject content scripts on every navigation and wake service workers from cold, so we apply tighter budgets than the rspack default.`;
8941
+ const lines = assets.map((a)=>{
8942
+ const over = (a.size / a.budget * 100 - 100).toFixed(0);
8943
+ return ` ${a.name}\n size: ${fmtKiB(a.size)}\n budget: ${fmtKiB(a.budget)} (over by ${over}%)\n role: ${categoryRole(a.category)}`;
8944
+ });
8945
+ const remediation = "Recommended: lazy-load with dynamic import(), code-split per route, or replace large SDKs with thin fetch wrappers. See https://rspack.rs/guide/optimization/code-splitting";
8946
+ return `${header}\n\n${lines.join('\n')}\n\n${remediation}`;
8947
+ }
8948
+ function categoryRole(c) {
8949
+ switch(c){
8950
+ case "content-script":
8951
+ return "content script — injected on every page navigation";
8952
+ case 'service-worker':
8953
+ return 'service worker / background — wakes from cold each session';
8954
+ case 'page':
8955
+ return 'UI page — opened on demand';
8956
+ default:
8957
+ return 'asset';
8958
+ }
8959
+ }
8960
+ function plugin_perf_budgets_define_property(obj, key, value) {
8961
+ if (key in obj) Object.defineProperty(obj, key, {
8962
+ value: value,
8963
+ enumerable: true,
8964
+ configurable: true,
8965
+ writable: true
8966
+ });
8967
+ else obj[key] = value;
8968
+ return obj;
8969
+ }
8970
+ class PerfBudgetsPlugin {
8971
+ apply(compiler) {
8972
+ const enabled = 'boolean' == typeof this.options.enabled ? this.options.enabled : 'production' === compiler.options.mode;
8973
+ if (!enabled) return;
8974
+ const budgets = {
8975
+ ...BUDGET_BYTES,
8976
+ ...this.options.budgets || {}
8977
+ };
8978
+ compiler.hooks.afterCompile.tap(PerfBudgetsPlugin.name, (compilation)=>{
8979
+ if (compilation.errors?.length) return;
8980
+ const oversized = [];
8981
+ const assets = compilation.assets || {};
8982
+ for (const [name, source] of Object.entries(assets)){
8983
+ const size = source?.size?.() ?? 0;
8984
+ if (!size) continue;
8985
+ const category = categorizeAsset(name);
8986
+ if ('ignored' === category) continue;
8987
+ const budget = budgets[category];
8988
+ if (isFinite(budget)) {
8989
+ if (!(size <= budget)) oversized.push({
8990
+ name,
8991
+ size,
8992
+ budget,
8993
+ category
8994
+ });
8995
+ }
8996
+ }
8997
+ if (0 === oversized.length) return;
8998
+ oversized.sort((a, b)=>b.size - a.size);
8999
+ const ErrorConstructor = compiler?.rspack?.WebpackError || Error;
9000
+ const warning = new ErrorConstructor(perfBudgetWarning(oversized));
9001
+ warning.name = 'PerfBudgetWarning';
9002
+ if (!compilation.warnings) compilation.warnings = [];
9003
+ compilation.warnings.push(warning);
9004
+ });
9005
+ }
9006
+ constructor(options = {}){
9007
+ plugin_perf_budgets_define_property(this, "options", void 0);
9008
+ this.options = options;
9009
+ }
9010
+ }
9011
+ plugin_perf_budgets_define_property(PerfBudgetsPlugin, "name", 'plugin-perf-budgets');
8874
9012
  function webpackConfig(projectStructure, devOptions) {
8875
9013
  const { manifestPath } = projectStructure;
8876
9014
  const { packageJsonDir } = (0, lib_paths.fu)(projectStructure);
@@ -8927,7 +9065,8 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8927
9065
  }),
8928
9066
  new SpecialFoldersPlugin({
8929
9067
  manifestPath
8930
- })
9068
+ }),
9069
+ new PerfBudgetsPlugin()
8931
9070
  ];
8932
9071
  if (devOptions.noBrowser) plugins.push(new plugin_playwright.Tb({
8933
9072
  packageJsonDir,
@@ -9066,7 +9205,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9066
9205
  console: (0, branding.P)('Extension.js')
9067
9206
  },
9068
9207
  performance: {
9069
- hints: 'production' === devOptions.mode ? 'warning' : false
9208
+ hints: false
9070
9209
  },
9071
9210
  optimization: {
9072
9211
  minimize: 'production' === devOptions.mode,