wxt 0.18.7 → 0.18.9

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/dist/cli.js CHANGED
@@ -917,10 +917,13 @@ try {
917
917
  // Use "pre" so the new script is added before vite bundles all the scripts
918
918
  order: "pre",
919
919
  handler(html, _ctx) {
920
+ const src = config.command === "serve" ? `http://${config.dev.server?.hostname}:${config.dev.server?.port}/@id/${virtualHtmlModuleId}` : virtualHtmlModuleId;
920
921
  const { document } = parseHTML2(html);
922
+ const existing = document.querySelector(`script[src='${src}']`);
923
+ if (existing) return;
921
924
  const script = document.createElement("script");
922
925
  script.type = "module";
923
- script.src = config.command === "serve" ? `http://${config.dev.server?.hostname}:${config.dev.server?.port}/@id/${virtualHtmlModuleId}` : virtualHtmlModuleId;
926
+ script.src = src;
924
927
  if (document.head == null) {
925
928
  const newHead = document.createElement("head");
926
929
  document.documentElement.prepend(newHead);
@@ -971,6 +974,9 @@ ${noImports}`;
971
974
  }
972
975
 
973
976
  // src/core/builders/vite/index.ts
977
+ import { ViteNodeServer } from "vite-node/server";
978
+ import { ViteNodeRunner } from "vite-node/client";
979
+ import { installSourcemapsSupport } from "vite-node/source-map";
974
980
  async function createViteBuilder(wxtConfig, hooks, server) {
975
981
  const vite = await import("vite");
976
982
  const getBaseConfig = async () => {
@@ -1118,21 +1124,64 @@ async function createViteBuilder(wxtConfig, hooks, server) {
1118
1124
  return {
1119
1125
  name: "Vite",
1120
1126
  version: vite.version,
1121
- async importEntrypoint(url) {
1122
- const baseConfig = await getBaseConfig();
1123
- const envConfig = {
1124
- plugins: [
1125
- webextensionPolyfillMock(wxtConfig),
1126
- removeEntrypointMainFunction(wxtConfig, url)
1127
- ]
1128
- };
1129
- const config = vite.mergeConfig(baseConfig, envConfig);
1130
- const server2 = await vite.createServer(config);
1131
- await server2.listen();
1132
- const runtime = await vite.createViteRuntime(server2, { hmr: false });
1133
- const module = await runtime.executeUrl(url);
1134
- await server2.close();
1135
- return module.default;
1127
+ async importEntrypoint(path11) {
1128
+ switch (wxtConfig.experimental.entrypointImporter) {
1129
+ default:
1130
+ case "jiti": {
1131
+ return await importEntrypointFile(path11);
1132
+ }
1133
+ case "vite-runtime": {
1134
+ const baseConfig = await getBaseConfig();
1135
+ const envConfig = {
1136
+ plugins: [
1137
+ webextensionPolyfillMock(wxtConfig),
1138
+ removeEntrypointMainFunction(wxtConfig, path11)
1139
+ ]
1140
+ };
1141
+ const config = vite.mergeConfig(baseConfig, envConfig);
1142
+ const server2 = await vite.createServer(config);
1143
+ await server2.listen();
1144
+ const runtime = await vite.createViteRuntime(server2, { hmr: false });
1145
+ const module = await runtime.executeUrl(path11);
1146
+ await server2.close();
1147
+ return module.default;
1148
+ }
1149
+ case "vite-node": {
1150
+ const baseConfig = await getBaseConfig();
1151
+ baseConfig.optimizeDeps ??= {};
1152
+ baseConfig.optimizeDeps.noDiscovery = true;
1153
+ baseConfig.optimizeDeps.include = [];
1154
+ const envConfig = {
1155
+ plugins: [
1156
+ webextensionPolyfillMock(wxtConfig),
1157
+ removeEntrypointMainFunction(wxtConfig, path11)
1158
+ ]
1159
+ };
1160
+ const config = vite.mergeConfig(baseConfig, envConfig);
1161
+ const server2 = await vite.createServer(config);
1162
+ await server2.pluginContainer.buildStart({});
1163
+ const node = new ViteNodeServer(server2);
1164
+ installSourcemapsSupport({
1165
+ getSourceMap: (source) => node.getSourceMap(source)
1166
+ });
1167
+ const runner = new ViteNodeRunner({
1168
+ root: server2.config.root,
1169
+ base: server2.config.base,
1170
+ // when having the server and runner in a different context,
1171
+ // you will need to handle the communication between them
1172
+ // and pass to this function
1173
+ fetchModule(id) {
1174
+ return node.fetchModule(id);
1175
+ },
1176
+ resolveId(id, importer) {
1177
+ return node.resolveId(id, importer);
1178
+ }
1179
+ });
1180
+ const res = await runner.executeFile(path11);
1181
+ await server2.close();
1182
+ return res.default;
1183
+ }
1184
+ }
1136
1185
  },
1137
1186
  async build(group) {
1138
1187
  let entryConfig;
@@ -1321,11 +1370,25 @@ function detectDevChanges(changedFiles, currentOutput) {
1321
1370
  (changedFile) => findEffectedSteps(changedFile, currentOutput)
1322
1371
  )
1323
1372
  );
1324
- if (changedSteps.size === 0) return { type: "no-change" };
1373
+ if (changedSteps.size === 0) {
1374
+ const hasPublicChange = some(
1375
+ changedFiles,
1376
+ (file) => file.startsWith(wxt.config.publicDir)
1377
+ );
1378
+ if (hasPublicChange) {
1379
+ return {
1380
+ type: "extension-reload",
1381
+ rebuildGroups: [],
1382
+ cachedOutput: currentOutput
1383
+ };
1384
+ } else {
1385
+ return { type: "no-change" };
1386
+ }
1387
+ }
1325
1388
  const unchangedOutput = {
1326
1389
  manifest: currentOutput.manifest,
1327
1390
  steps: [],
1328
- publicAssets: []
1391
+ publicAssets: [...currentOutput.publicAssets]
1329
1392
  };
1330
1393
  const changedOutput = {
1331
1394
  manifest: currentOutput.manifest,
@@ -1339,13 +1402,6 @@ function detectDevChanges(changedFiles, currentOutput) {
1339
1402
  unchangedOutput.steps.push(step);
1340
1403
  }
1341
1404
  }
1342
- for (const asset of currentOutput.publicAssets) {
1343
- if (changedSteps.has(asset)) {
1344
- changedOutput.publicAssets.push(asset);
1345
- } else {
1346
- unchangedOutput.publicAssets.push(asset);
1347
- }
1348
- }
1349
1405
  const isOnlyHtmlChanges = changedFiles.length > 0 && every(changedFiles, (file) => file.endsWith(".html"));
1350
1406
  if (isOnlyHtmlChanges) {
1351
1407
  return {
@@ -1386,122 +1442,27 @@ function findEffectedSteps(changedFile, currentOutput) {
1386
1442
  const effectedChunk = step.chunks.find((chunk) => isChunkEffected(chunk));
1387
1443
  if (effectedChunk) changes.push(step);
1388
1444
  }
1389
- const effectedAsset = currentOutput.publicAssets.find(
1390
- (chunk) => isChunkEffected(chunk)
1391
- );
1392
- if (effectedAsset) changes.push(effectedAsset);
1393
1445
  return changes;
1394
1446
  }
1395
1447
 
1396
1448
  // src/core/utils/building/find-entrypoints.ts
1397
- import { relative as relative4, resolve as resolve8 } from "path";
1398
- import fs6 from "fs-extra";
1449
+ import { relative as relative3, resolve as resolve7 } from "path";
1450
+ import fs5 from "fs-extra";
1399
1451
  import { minimatch } from "minimatch";
1400
1452
  import { parseHTML as parseHTML3 } from "linkedom";
1401
1453
  import JSON5 from "json5";
1402
1454
  import glob2 from "fast-glob";
1403
1455
  import pc2 from "picocolors";
1404
-
1405
- // src/core/utils/building/import-entrypoint.ts
1406
- import createJITI from "jiti";
1407
- import { createUnimport as createUnimport2 } from "unimport";
1408
- import fs5 from "fs-extra";
1409
- import { relative as relative3, resolve as resolve7 } from "node:path";
1410
- import { transformSync } from "esbuild";
1411
- import { fileURLToPath } from "node:url";
1412
- async function importEntrypointFile(path11) {
1413
- wxt.logger.debug("Loading file metadata:", path11);
1414
- const normalPath = normalizePath(path11);
1415
- const unimport2 = createUnimport2({
1416
- ...wxt.config.imports,
1417
- // Only allow specific imports, not all from the project
1418
- dirs: []
1419
- });
1420
- await unimport2.init();
1421
- const text = await fs5.readFile(path11, "utf-8");
1422
- const textNoImports = removeProjectImportStatements(text);
1423
- const { code } = await unimport2.injectImports(textNoImports);
1424
- wxt.logger.debug(
1425
- ["Text:", text, "No imports:", textNoImports, "Code:", code].join("\n")
1426
- );
1427
- const jiti = createJITI(
1428
- typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url),
1429
- {
1430
- cache: false,
1431
- debug: wxt.config.debug,
1432
- esmResolve: true,
1433
- alias: {
1434
- "webextension-polyfill": resolve7(
1435
- wxt.config.wxtModuleDir,
1436
- "dist/virtual/mock-browser.js"
1437
- )
1438
- },
1439
- // Continue using node to load TS files even if `bun run --bun` is detected. Jiti does not
1440
- // respect the custom transform function when using it's native bun option.
1441
- experimentalBun: false,
1442
- // List of extensions to transform with esbuild
1443
- extensions: [
1444
- ".ts",
1445
- ".cts",
1446
- ".mts",
1447
- ".tsx",
1448
- ".js",
1449
- ".cjs",
1450
- ".mjs",
1451
- ".jsx"
1452
- ],
1453
- transform(opts) {
1454
- const isEntrypoint = opts.filename === normalPath;
1455
- return transformSync(
1456
- // Use modified source code for entrypoints
1457
- isEntrypoint ? code : opts.source,
1458
- getEsbuildOptions(opts)
1459
- );
1460
- }
1461
- }
1462
- );
1463
- try {
1464
- const res = await jiti(path11);
1465
- return res.default;
1466
- } catch (err) {
1467
- const filePath = relative3(wxt.config.root, path11);
1468
- if (err instanceof ReferenceError) {
1469
- const variableName = err.message.replace(" is not defined", "");
1470
- throw Error(
1471
- `${filePath}: Cannot use imported variable "${variableName}" outside the main function. See https://wxt.dev/guide/go-further/entrypoint-side-effects.html`,
1472
- { cause: err }
1473
- );
1474
- } else {
1475
- wxt.logger.error(err);
1476
- throw Error(`Failed to load entrypoint: ${filePath}`, { cause: err });
1477
- }
1478
- }
1479
- }
1480
- function getEsbuildOptions(opts) {
1481
- const isJsx = opts.filename?.endsWith("x");
1482
- return {
1483
- format: "cjs",
1484
- loader: isJsx ? "tsx" : "ts",
1485
- ...isJsx ? {
1486
- // `h` and `Fragment` are undefined, but that's OK because JSX is never evaluated while
1487
- // grabbing the entrypoint's options.
1488
- jsxFactory: "h",
1489
- jsxFragment: "Fragment"
1490
- } : void 0
1491
- };
1492
- }
1493
-
1494
- // src/core/utils/building/find-entrypoints.ts
1495
1456
  async function findEntrypoints() {
1496
- await fs6.mkdir(wxt.config.wxtDir, { recursive: true });
1497
- await fs6.writeJson(resolve8(wxt.config.wxtDir, "tsconfig.json"), {});
1457
+ await fs5.mkdir(wxt.config.wxtDir, { recursive: true });
1458
+ await fs5.writeJson(resolve7(wxt.config.wxtDir, "tsconfig.json"), {});
1498
1459
  const relativePaths = await glob2(Object.keys(PATH_GLOB_TO_TYPE_MAP), {
1499
1460
  cwd: wxt.config.entrypointsDir
1500
1461
  });
1501
1462
  relativePaths.sort();
1502
1463
  const pathGlobs = Object.keys(PATH_GLOB_TO_TYPE_MAP);
1503
1464
  const entrypointInfos = relativePaths.reduce((results, relativePath) => {
1504
- const inputPath = resolve8(wxt.config.entrypointsDir, relativePath);
1465
+ const inputPath = resolve7(wxt.config.entrypointsDir, relativePath);
1505
1466
  const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
1506
1467
  const matchingGlob = pathGlobs.find(
1507
1468
  (glob7) => minimatch(relativePath, glob7)
@@ -1543,7 +1504,7 @@ async function findEntrypoints() {
1543
1504
  return {
1544
1505
  ...info,
1545
1506
  type,
1546
- outputDir: resolve8(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
1507
+ outputDir: resolve7(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
1547
1508
  options: {
1548
1509
  include: void 0,
1549
1510
  exclude: void 0
@@ -1617,7 +1578,7 @@ function preventDuplicateEntrypointNames(files) {
1617
1578
  if (absolutePaths.length > 1) {
1618
1579
  lines.push(`- ${name}`);
1619
1580
  absolutePaths.forEach((absolutePath) => {
1620
- lines.push(` - ${relative4(wxt.config.root, absolutePath)}`);
1581
+ lines.push(` - ${relative3(wxt.config.root, absolutePath)}`);
1621
1582
  });
1622
1583
  }
1623
1584
  return lines;
@@ -1705,7 +1666,7 @@ async function getUnlistedScriptEntrypoint({
1705
1666
  name,
1706
1667
  skipped
1707
1668
  }) {
1708
- const defaultExport = await importEntrypoint(inputPath);
1669
+ const defaultExport = await wxt.builder.importEntrypoint(inputPath);
1709
1670
  if (defaultExport == null) {
1710
1671
  throw Error(
1711
1672
  `${name}: Default export not found, did you forget to call "export default defineUnlistedScript(...)"?`
@@ -1728,7 +1689,7 @@ async function getBackgroundEntrypoint({
1728
1689
  }) {
1729
1690
  let options = {};
1730
1691
  if (inputPath !== VIRTUAL_NOOP_BACKGROUND_MODULE_ID) {
1731
- const defaultExport = await importEntrypoint(inputPath);
1692
+ const defaultExport = await wxt.builder.importEntrypoint(inputPath);
1732
1693
  if (defaultExport == null) {
1733
1694
  throw Error(
1734
1695
  `${name}: Default export not found, did you forget to call "export default defineBackground(...)"?`
@@ -1754,7 +1715,13 @@ async function getContentScriptEntrypoint({
1754
1715
  name,
1755
1716
  skipped
1756
1717
  }) {
1757
- const { main: _, ...options } = await importEntrypoint(inputPath);
1718
+ const defaultExport = await wxt.builder.importEntrypoint(inputPath);
1719
+ if (defaultExport == null) {
1720
+ throw Error(
1721
+ `${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
1722
+ );
1723
+ }
1724
+ const { main: _, ...options } = defaultExport;
1758
1725
  if (options == null) {
1759
1726
  throw Error(
1760
1727
  `${name}: Default export not found, did you forget to call "export default defineContentScript(...)"?`
@@ -1764,7 +1731,7 @@ async function getContentScriptEntrypoint({
1764
1731
  type: "content-script",
1765
1732
  name,
1766
1733
  inputPath,
1767
- outputDir: resolve8(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
1734
+ outputDir: resolve7(wxt.config.outDir, CONTENT_SCRIPT_OUT_DIR),
1768
1735
  options: resolvePerBrowserOptions(options, wxt.config.browser),
1769
1736
  skipped
1770
1737
  };
@@ -1797,7 +1764,7 @@ async function getSidepanelEntrypoint(info) {
1797
1764
  };
1798
1765
  }
1799
1766
  async function getHtmlEntrypointOptions(info, keyMap, queries, parsers) {
1800
- const content = await fs6.readFile(info.inputPath, "utf-8");
1767
+ const content = await fs5.readFile(info.inputPath, "utf-8");
1801
1768
  const { document } = parseHTML3(content);
1802
1769
  const options = {};
1803
1770
  const defaultQuery = (manifestKey) => document.querySelector(`meta[name='manifest.${manifestKey}']`)?.getAttribute("content");
@@ -1857,14 +1824,11 @@ var PATH_GLOB_TO_TYPE_MAP = {
1857
1824
  [`*/index.${CSS_EXTENSIONS_PATTERN}`]: "unlisted-style"
1858
1825
  };
1859
1826
  var CONTENT_SCRIPT_OUT_DIR = "content-scripts";
1860
- function importEntrypoint(path11) {
1861
- return wxt.config.experimental.viteRuntime ? wxt.builder.importEntrypoint(path11) : importEntrypointFile(path11);
1862
- }
1863
1827
 
1864
1828
  // src/core/utils/building/generate-wxt-dir.ts
1865
- import { createUnimport as createUnimport3 } from "unimport";
1866
- import fs7 from "fs-extra";
1867
- import { relative as relative5, resolve as resolve9 } from "path";
1829
+ import { createUnimport as createUnimport2 } from "unimport";
1830
+ import fs6 from "fs-extra";
1831
+ import { relative as relative4, resolve as resolve8 } from "path";
1868
1832
  import path5 from "node:path";
1869
1833
 
1870
1834
  // src/core/utils/i18n.ts
@@ -1906,10 +1870,10 @@ function parseI18nMessages(messagesJson) {
1906
1870
 
1907
1871
  // src/core/utils/building/generate-wxt-dir.ts
1908
1872
  async function generateTypesDir(entrypoints) {
1909
- await fs7.ensureDir(wxt.config.typesDir);
1873
+ await fs6.ensureDir(wxt.config.typesDir);
1910
1874
  const references = [];
1911
1875
  if (wxt.config.imports !== false) {
1912
- const unimport2 = createUnimport3(wxt.config.imports);
1876
+ const unimport2 = createUnimport2(wxt.config.imports);
1913
1877
  references.push(await writeImportsDeclarationFile(unimport2));
1914
1878
  if (wxt.config.imports.eslintrc.enabled) {
1915
1879
  await writeImportsEslintFile(unimport2, wxt.config.imports);
@@ -1922,7 +1886,7 @@ async function generateTypesDir(entrypoints) {
1922
1886
  await writeTsConfigFile(mainReference);
1923
1887
  }
1924
1888
  async function writeImportsDeclarationFile(unimport2) {
1925
- const filePath = resolve9(wxt.config.typesDir, "imports.d.ts");
1889
+ const filePath = resolve8(wxt.config.typesDir, "imports.d.ts");
1926
1890
  await unimport2.scanImportsFromDir(void 0, { cwd: wxt.config.srcDir });
1927
1891
  await writeFileIfDifferent(
1928
1892
  filePath,
@@ -1938,10 +1902,10 @@ async function writeImportsEslintFile(unimport2, options) {
1938
1902
  (await unimport2.getImports()).map((i) => i.as ?? i.name).filter(Boolean).sort().forEach((name) => {
1939
1903
  eslintrc.globals[name] = options.eslintrc.globalsPropValue;
1940
1904
  });
1941
- await fs7.writeJson(options.eslintrc.filePath, eslintrc, { spaces: 2 });
1905
+ await fs6.writeJson(options.eslintrc.filePath, eslintrc, { spaces: 2 });
1942
1906
  }
1943
1907
  async function writePathsDeclarationFile(entrypoints) {
1944
- const filePath = resolve9(wxt.config.typesDir, "paths.d.ts");
1908
+ const filePath = resolve8(wxt.config.typesDir, "paths.d.ts");
1945
1909
  const unions = entrypoints.map(
1946
1910
  (entry) => getEntrypointBundlePath(
1947
1911
  entry,
@@ -1969,7 +1933,7 @@ declare module "wxt/browser" {
1969
1933
  return filePath;
1970
1934
  }
1971
1935
  async function writeI18nDeclarationFile() {
1972
- const filePath = resolve9(wxt.config.typesDir, "i18n.d.ts");
1936
+ const filePath = resolve8(wxt.config.typesDir, "i18n.d.ts");
1973
1937
  const defaultLocale = wxt.config.manifest.default_locale;
1974
1938
  const template = `// Generated by wxt
1975
1939
  import "wxt/browser";
@@ -1998,7 +1962,7 @@ declare module "wxt/browser" {
1998
1962
  defaultLocale,
1999
1963
  "messages.json"
2000
1964
  );
2001
- const content = JSON.parse(await fs7.readFile(defaultLocalePath, "utf-8"));
1965
+ const content = JSON.parse(await fs6.readFile(defaultLocalePath, "utf-8"));
2002
1966
  messages = parseI18nMessages(content);
2003
1967
  } else {
2004
1968
  messages = parseI18nMessages({});
@@ -2022,7 +1986,7 @@ declare module "wxt/browser" {
2022
1986
  return filePath;
2023
1987
  }
2024
1988
  async function writeGlobalsDeclarationFile() {
2025
- const filePath = resolve9(wxt.config.typesDir, "globals.d.ts");
1989
+ const filePath = resolve8(wxt.config.typesDir, "globals.d.ts");
2026
1990
  const globals2 = [...getGlobals(wxt.config), ...getEntrypointGlobals("")];
2027
1991
  await writeFileIfDifferent(
2028
1992
  filePath,
@@ -2041,14 +2005,14 @@ async function writeGlobalsDeclarationFile() {
2041
2005
  }
2042
2006
  async function writeMainDeclarationFile(references) {
2043
2007
  const dir = wxt.config.wxtDir;
2044
- const filePath = resolve9(dir, "wxt.d.ts");
2008
+ const filePath = resolve8(dir, "wxt.d.ts");
2045
2009
  await writeFileIfDifferent(
2046
2010
  filePath,
2047
2011
  [
2048
2012
  "// Generated by wxt",
2049
2013
  `/// <reference types="wxt/vite-builder-env" />`,
2050
2014
  ...references.map(
2051
- (ref) => `/// <reference types="./${normalizePath(relative5(dir, ref))}" />`
2015
+ (ref) => `/// <reference types="./${normalizePath(relative4(dir, ref))}" />`
2052
2016
  ),
2053
2017
  // Add references to modules installed from NPM to the TS project so
2054
2018
  // their type augmentation can update InlineConfig correctly. Local
@@ -2063,7 +2027,7 @@ async function writeMainDeclarationFile(references) {
2063
2027
  }
2064
2028
  async function writeTsConfigFile(mainReference) {
2065
2029
  const dir = wxt.config.wxtDir;
2066
- const getTsconfigPath = (path11) => normalizePath(relative5(dir, path11));
2030
+ const getTsconfigPath = (path11) => normalizePath(relative4(dir, path11));
2067
2031
  const paths = Object.entries(wxt.config.alias).flatMap(([alias, absolutePath]) => {
2068
2032
  const aliasPath = getTsconfigPath(absolutePath);
2069
2033
  return [
@@ -2072,7 +2036,7 @@ async function writeTsConfigFile(mainReference) {
2072
2036
  ];
2073
2037
  }).join(",\n");
2074
2038
  await writeFileIfDifferent(
2075
- resolve9(dir, "tsconfig.json"),
2039
+ resolve8(dir, "tsconfig.json"),
2076
2040
  `{
2077
2041
  "compilerOptions": {
2078
2042
  "target": "ESNext",
@@ -2102,10 +2066,10 @@ import { loadConfig } from "c12";
2102
2066
  import path6 from "node:path";
2103
2067
 
2104
2068
  // src/core/utils/cache.ts
2105
- import fs8, { ensureDir as ensureDir3 } from "fs-extra";
2106
- import { dirname as dirname4, resolve as resolve10 } from "path";
2069
+ import fs7, { ensureDir as ensureDir3 } from "fs-extra";
2070
+ import { dirname as dirname4, resolve as resolve9 } from "path";
2107
2071
  function createFsCache(wxtDir) {
2108
- const getPath = (key) => resolve10(wxtDir, "cache", encodeURIComponent(key));
2072
+ const getPath = (key) => resolve9(wxtDir, "cache", encodeURIComponent(key));
2109
2073
  return {
2110
2074
  async set(key, value) {
2111
2075
  const path11 = getPath(key);
@@ -2115,7 +2079,7 @@ function createFsCache(wxtDir) {
2115
2079
  async get(key) {
2116
2080
  const path11 = getPath(key);
2117
2081
  try {
2118
- return await fs8.readFile(path11, "utf-8");
2082
+ return await fs7.readFile(path11, "utf-8");
2119
2083
  } catch {
2120
2084
  return void 0;
2121
2085
  }
@@ -2127,12 +2091,12 @@ function createFsCache(wxtDir) {
2127
2091
  import defu from "defu";
2128
2092
 
2129
2093
  // src/core/utils/package.ts
2130
- import { resolve as resolve11 } from "node:path";
2131
- import fs9 from "fs-extra";
2094
+ import { resolve as resolve10 } from "node:path";
2095
+ import fs8 from "fs-extra";
2132
2096
  async function getPackageJson() {
2133
- const file = resolve11(wxt.config.root, "package.json");
2097
+ const file = resolve10(wxt.config.root, "package.json");
2134
2098
  try {
2135
- return await fs9.readJson(file);
2099
+ return await fs8.readJson(file);
2136
2100
  } catch (err) {
2137
2101
  wxt.logger.debug(
2138
2102
  `Failed to read package.json at: ${file}. Returning undefined.`
@@ -2148,7 +2112,7 @@ function isModuleInstalled(name) {
2148
2112
  }
2149
2113
 
2150
2114
  // src/core/utils/building/resolve-config.ts
2151
- import fs10 from "fs-extra";
2115
+ import fs9 from "fs-extra";
2152
2116
  import glob3 from "fast-glob";
2153
2117
  async function resolveConfig(inlineConfig, command) {
2154
2118
  let userConfig = {};
@@ -2264,7 +2228,7 @@ async function resolveConfig(inlineConfig, command) {
2264
2228
  alias,
2265
2229
  experimental: defu(mergedConfig.experimental, {
2266
2230
  includeBrowserPolyfill: true,
2267
- viteRuntime: false
2231
+ entrypointImporter: "jiti"
2268
2232
  }),
2269
2233
  dev: {
2270
2234
  server: devServerConfig,
@@ -2386,7 +2350,7 @@ async function resolveWxtModuleDir() {
2386
2350
  return path6.resolve(requireResolve("wxt"), "../..");
2387
2351
  }
2388
2352
  async function isDirMissing(dir) {
2389
- return !await fs10.exists(dir);
2353
+ return !await fs9.exists(dir);
2390
2354
  }
2391
2355
  function logMissingDir(logger, name, expected) {
2392
2356
  logger.warn(
@@ -2498,6 +2462,95 @@ var ENTRY_TYPE_TO_GROUP_MAP = {
2498
2462
  "content-script-style": "individual"
2499
2463
  };
2500
2464
 
2465
+ // src/core/utils/building/import-entrypoint.ts
2466
+ import createJITI from "jiti";
2467
+ import { createUnimport as createUnimport3 } from "unimport";
2468
+ import fs10 from "fs-extra";
2469
+ import { relative as relative5, resolve as resolve11 } from "node:path";
2470
+ import { transformSync } from "esbuild";
2471
+ import { fileURLToPath } from "node:url";
2472
+ async function importEntrypointFile(path11) {
2473
+ wxt.logger.debug("Loading file metadata:", path11);
2474
+ const normalPath = normalizePath(path11);
2475
+ const unimport2 = createUnimport3({
2476
+ ...wxt.config.imports,
2477
+ // Only allow specific imports, not all from the project
2478
+ dirs: []
2479
+ });
2480
+ await unimport2.init();
2481
+ const text = await fs10.readFile(path11, "utf-8");
2482
+ const textNoImports = removeProjectImportStatements(text);
2483
+ const { code } = await unimport2.injectImports(textNoImports);
2484
+ wxt.logger.debug(
2485
+ ["Text:", text, "No imports:", textNoImports, "Code:", code].join("\n")
2486
+ );
2487
+ const jiti = createJITI(
2488
+ typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url),
2489
+ {
2490
+ cache: false,
2491
+ debug: wxt.config.debug,
2492
+ esmResolve: true,
2493
+ alias: {
2494
+ "webextension-polyfill": resolve11(
2495
+ wxt.config.wxtModuleDir,
2496
+ "dist/virtual/mock-browser.js"
2497
+ )
2498
+ },
2499
+ // Continue using node to load TS files even if `bun run --bun` is detected. Jiti does not
2500
+ // respect the custom transform function when using it's native bun option.
2501
+ experimentalBun: false,
2502
+ // List of extensions to transform with esbuild
2503
+ extensions: [
2504
+ ".ts",
2505
+ ".cts",
2506
+ ".mts",
2507
+ ".tsx",
2508
+ ".js",
2509
+ ".cjs",
2510
+ ".mjs",
2511
+ ".jsx"
2512
+ ],
2513
+ transform(opts) {
2514
+ const isEntrypoint = opts.filename === normalPath;
2515
+ return transformSync(
2516
+ // Use modified source code for entrypoints
2517
+ isEntrypoint ? code : opts.source,
2518
+ getEsbuildOptions(opts)
2519
+ );
2520
+ }
2521
+ }
2522
+ );
2523
+ try {
2524
+ const res = await jiti(path11);
2525
+ return res.default;
2526
+ } catch (err) {
2527
+ const filePath = relative5(wxt.config.root, path11);
2528
+ if (err instanceof ReferenceError) {
2529
+ const variableName = err.message.replace(" is not defined", "");
2530
+ throw Error(
2531
+ `${filePath}: Cannot use imported variable "${variableName}" outside the main function. See https://wxt.dev/guide/go-further/entrypoint-side-effects.html`,
2532
+ { cause: err }
2533
+ );
2534
+ } else {
2535
+ wxt.logger.error(err);
2536
+ throw Error(`Failed to load entrypoint: ${filePath}`, { cause: err });
2537
+ }
2538
+ }
2539
+ }
2540
+ function getEsbuildOptions(opts) {
2541
+ const isJsx = opts.filename?.endsWith("x");
2542
+ return {
2543
+ format: "cjs",
2544
+ loader: isJsx ? "tsx" : "ts",
2545
+ ...isJsx ? {
2546
+ // `h` and `Fragment` are undefined, but that's OK because JSX is never evaluated while
2547
+ // grabbing the entrypoint's options.
2548
+ jsxFactory: "h",
2549
+ jsxFragment: "Fragment"
2550
+ } : void 0
2551
+ };
2552
+ }
2553
+
2501
2554
  // src/core/utils/building/internal-build.ts
2502
2555
  import pc5 from "picocolors";
2503
2556
  import fs13 from "fs-extra";
@@ -2609,7 +2662,7 @@ function getChunkSortWeight(filename) {
2609
2662
  import pc4 from "picocolors";
2610
2663
 
2611
2664
  // package.json
2612
- var version = "0.18.6";
2665
+ var version = "0.18.8";
2613
2666
 
2614
2667
  // src/core/utils/log/printHeader.ts
2615
2668
  function printHeader() {
@@ -3690,6 +3743,7 @@ function createFileReloader(server) {
3690
3743
  return async (event, path11) => {
3691
3744
  await wxt.reloadConfig();
3692
3745
  if (path11.startsWith(wxt.config.outBaseDir)) return;
3746
+ if (path11.startsWith(wxt.config.wxtDir)) return;
3693
3747
  changeQueue.push([event, path11]);
3694
3748
  await fileChangedMutex.runExclusive(async () => {
3695
3749
  if (server.currentOutput == null) return;
@@ -434,14 +434,17 @@ interface InlineConfig {
434
434
  */
435
435
  includeBrowserPolyfill?: boolean;
436
436
  /**
437
- * When set to `true`, use the Vite Runtime API to load entrypoint options instead of the default, `jiti`.
437
+ * Method used to import entrypoint files during the build process to extract their options.
438
438
  *
439
- * Lets you use imported variables and leverage your Vite config to add support for non-standard APIs/syntax.
439
+ * - "jiti": Simplest and fastest, but doesn't allow using any imported variables outside the entrypoint's main function
440
+ * - "vite-runtime" (unstable): Uses Vite 5.3's new runtime API to import the entrypoints. Automatically includes vite config based on your wxt.config.ts file
441
+ * - "vite-node" (unstable): Uses `vite-node` to import the entrypoints. Automatically includes vite config based on your wxt.config.ts file
440
442
  *
441
- * @experimental Early access to try out the feature before it becomes the default.
442
- * @default false
443
+ * @see {@link https://wxt.dev/guide/go-further/entrypoint-side-effects.html|Entrypoint Side-effect Docs}
444
+ *
445
+ * @default "jiti"
443
446
  */
444
- viteRuntime?: boolean;
447
+ entrypointImporter?: 'jiti' | 'vite-runtime' | 'vite-node';
445
448
  };
446
449
  /**
447
450
  * Config effecting dev mode only.
@@ -1179,7 +1182,7 @@ interface ResolvedConfig {
1179
1182
  alias: Record<string, string>;
1180
1183
  experimental: {
1181
1184
  includeBrowserPolyfill: boolean;
1182
- viteRuntime: boolean;
1185
+ entrypointImporter: 'jiti' | 'vite-runtime' | 'vite-node';
1183
1186
  };
1184
1187
  dev: {
1185
1188
  /** Only defined during dev command */