@crxjs/vite-plugin 1.0.5 → 1.0.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @crxjs/vite-plugin
2
2
 
3
+ ## 1.0.8
4
+
5
+ ### Patch Changes
6
+
7
+ - 8a09cb9: Optimize rollup input
8
+
9
+ ## 1.0.7
10
+
11
+ ### Patch Changes
12
+
13
+ - e1604d8: Strip paths from content script resource match patterns
14
+
15
+ ## 1.0.6
16
+
17
+ ### Patch Changes
18
+
19
+ - 63d102f: Automatically ignores `build.outDir` for server HMR, so the file
20
+ writer doesn't trigger a full reload.
21
+
22
+ Fixes flaky HMR updates for content scripts; Tailwind should work fine now 🥳
23
+
24
+ - a1e2728: Fix isImporter recursion
25
+
3
26
  ## 1.0.5
4
27
 
5
28
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -132,6 +132,12 @@ function encodeManifest(manifest) {
132
132
  const json = JSON.stringify(JSON.stringify(manifest));
133
133
  return `export default ${json}`;
134
134
  }
135
+ const stubMatchPattern = (pattern) => {
136
+ const [schema, rest] = pattern.split("://");
137
+ const [origin, pathname] = rest.split("/");
138
+ const root = `${schema}://${origin}`;
139
+ return pathname ? `${root}/*` : root;
140
+ };
135
141
 
136
142
  const idBySource = /* @__PURE__ */ new Map();
137
143
  const idByUrl = /* @__PURE__ */ new Map();
@@ -185,6 +191,7 @@ const setOutputMeta = ({
185
191
  outputByOwner.set(ownerName, output);
186
192
  outputById.set(id, output);
187
193
  };
194
+ const transformResultByOwner = /* @__PURE__ */ new Map();
188
195
 
189
196
  const {
190
197
  basename,
@@ -231,17 +238,12 @@ function sourceToUrlMeta(source) {
231
238
  }
232
239
  const pluginFileWriterChunks = () => {
233
240
  let server;
234
- const ownerToTransformResultMap = /* @__PURE__ */ new Map();
235
241
  return {
236
242
  name: "crx:file-writer-chunks",
237
243
  apply: "build",
238
244
  fileWriterStart(_server) {
239
245
  server = _server;
240
246
  },
241
- watchChange(fileName) {
242
- for (const owner of ownersByFile.get(fileName) ?? /* @__PURE__ */ new Set())
243
- ownerToTransformResultMap.delete(owner);
244
- },
245
247
  async resolveId(source, importer) {
246
248
  if (this.meta.watchMode) {
247
249
  if (idBySource.has(source)) {
@@ -277,12 +279,12 @@ const pluginFileWriterChunks = () => {
277
279
  if (!serverModule)
278
280
  throw new Error(`Unable to load "${url}" from server.`);
279
281
  const { file, url: owner } = serverModule;
280
- transformResult = transformResult ?? ownerToTransformResultMap.get(owner) ?? serverModule.transformResult;
282
+ transformResult = transformResult ?? transformResultByOwner.get(owner) ?? serverModule.transformResult;
281
283
  if (!transformResult)
282
284
  transformResult = await server.transformRequest(url);
283
285
  if (!transformResult)
284
286
  throw new TypeError(`Unable to load "${url}" from server.`);
285
- ownerToTransformResultMap.set(owner, transformResult);
287
+ transformResultByOwner.set(owner, transformResult);
286
288
  if (file) {
287
289
  setFileMeta({ id, file });
288
290
  this.addWatchFile(file);
@@ -369,7 +371,7 @@ const pluginFileWriterChunks = () => {
369
371
  };
370
372
  };
371
373
 
372
- /*! *****************************************************************************
374
+ /******************************************************************************
373
375
  Copyright (c) Microsoft Corporation.
374
376
 
375
377
  Permission to use, copy, modify, and/or distribute this software for any
@@ -1481,6 +1483,12 @@ function last(arr) {
1481
1483
  function popResultSelector(args) {
1482
1484
  return isFunction(last(args)) ? args.pop() : undefined;
1483
1485
  }
1486
+ function popScheduler(args) {
1487
+ return isScheduler(last(args)) ? args.pop() : undefined;
1488
+ }
1489
+ function popNumber(args, defaultValue) {
1490
+ return typeof last(args) === 'number' ? args.pop() : defaultValue;
1491
+ }
1484
1492
 
1485
1493
  var isArrayLike = (function (x) { return x && typeof x.length === 'number' && typeof x !== 'function'; });
1486
1494
 
@@ -1697,6 +1705,126 @@ function executeSchedule(parentSubscription, scheduler, work, delay, repeat) {
1697
1705
  }
1698
1706
  }
1699
1707
 
1708
+ function observeOn(scheduler, delay) {
1709
+ if (delay === void 0) { delay = 0; }
1710
+ return operate(function (source, subscriber) {
1711
+ source.subscribe(createOperatorSubscriber(subscriber, function (value) { return executeSchedule(subscriber, scheduler, function () { return subscriber.next(value); }, delay); }, function () { return executeSchedule(subscriber, scheduler, function () { return subscriber.complete(); }, delay); }, function (err) { return executeSchedule(subscriber, scheduler, function () { return subscriber.error(err); }, delay); }));
1712
+ });
1713
+ }
1714
+
1715
+ function subscribeOn(scheduler, delay) {
1716
+ if (delay === void 0) { delay = 0; }
1717
+ return operate(function (source, subscriber) {
1718
+ subscriber.add(scheduler.schedule(function () { return source.subscribe(subscriber); }, delay));
1719
+ });
1720
+ }
1721
+
1722
+ function scheduleObservable(input, scheduler) {
1723
+ return innerFrom(input).pipe(subscribeOn(scheduler), observeOn(scheduler));
1724
+ }
1725
+
1726
+ function schedulePromise(input, scheduler) {
1727
+ return innerFrom(input).pipe(subscribeOn(scheduler), observeOn(scheduler));
1728
+ }
1729
+
1730
+ function scheduleArray(input, scheduler) {
1731
+ return new Observable(function (subscriber) {
1732
+ var i = 0;
1733
+ return scheduler.schedule(function () {
1734
+ if (i === input.length) {
1735
+ subscriber.complete();
1736
+ }
1737
+ else {
1738
+ subscriber.next(input[i++]);
1739
+ if (!subscriber.closed) {
1740
+ this.schedule();
1741
+ }
1742
+ }
1743
+ });
1744
+ });
1745
+ }
1746
+
1747
+ function scheduleIterable(input, scheduler) {
1748
+ return new Observable(function (subscriber) {
1749
+ var iterator$1;
1750
+ executeSchedule(subscriber, scheduler, function () {
1751
+ iterator$1 = input[iterator]();
1752
+ executeSchedule(subscriber, scheduler, function () {
1753
+ var _a;
1754
+ var value;
1755
+ var done;
1756
+ try {
1757
+ (_a = iterator$1.next(), value = _a.value, done = _a.done);
1758
+ }
1759
+ catch (err) {
1760
+ subscriber.error(err);
1761
+ return;
1762
+ }
1763
+ if (done) {
1764
+ subscriber.complete();
1765
+ }
1766
+ else {
1767
+ subscriber.next(value);
1768
+ }
1769
+ }, 0, true);
1770
+ });
1771
+ return function () { return isFunction(iterator$1 === null || iterator$1 === void 0 ? void 0 : iterator$1.return) && iterator$1.return(); };
1772
+ });
1773
+ }
1774
+
1775
+ function scheduleAsyncIterable(input, scheduler) {
1776
+ if (!input) {
1777
+ throw new Error('Iterable cannot be null');
1778
+ }
1779
+ return new Observable(function (subscriber) {
1780
+ executeSchedule(subscriber, scheduler, function () {
1781
+ var iterator = input[Symbol.asyncIterator]();
1782
+ executeSchedule(subscriber, scheduler, function () {
1783
+ iterator.next().then(function (result) {
1784
+ if (result.done) {
1785
+ subscriber.complete();
1786
+ }
1787
+ else {
1788
+ subscriber.next(result.value);
1789
+ }
1790
+ });
1791
+ }, 0, true);
1792
+ });
1793
+ });
1794
+ }
1795
+
1796
+ function scheduleReadableStreamLike(input, scheduler) {
1797
+ return scheduleAsyncIterable(readableStreamLikeToAsyncGenerator(input), scheduler);
1798
+ }
1799
+
1800
+ function scheduled(input, scheduler) {
1801
+ if (input != null) {
1802
+ if (isInteropObservable(input)) {
1803
+ return scheduleObservable(input, scheduler);
1804
+ }
1805
+ if (isArrayLike(input)) {
1806
+ return scheduleArray(input, scheduler);
1807
+ }
1808
+ if (isPromise(input)) {
1809
+ return schedulePromise(input, scheduler);
1810
+ }
1811
+ if (isAsyncIterable(input)) {
1812
+ return scheduleAsyncIterable(input, scheduler);
1813
+ }
1814
+ if (isIterable(input)) {
1815
+ return scheduleIterable(input, scheduler);
1816
+ }
1817
+ if (isReadableStreamLike(input)) {
1818
+ return scheduleReadableStreamLike(input, scheduler);
1819
+ }
1820
+ }
1821
+ throw createInvalidObservableTypeError(input);
1822
+ }
1823
+
1824
+ function from(input, scheduler) {
1825
+ return scheduler ? scheduled(input, scheduler) : innerFrom(input);
1826
+ }
1827
+
1700
1828
  var EmptyError = createErrorClass(function (_super) { return function EmptyErrorImpl() {
1701
1829
  _super(this);
1702
1830
  this.name = 'EmptyError';
@@ -1807,6 +1935,11 @@ function mergeMap(project, resultSelector, concurrent) {
1807
1935
  return operate(function (source, subscriber) { return mergeInternals(source, subscriber, project, concurrent); });
1808
1936
  }
1809
1937
 
1938
+ function mergeAll(concurrent) {
1939
+ if (concurrent === void 0) { concurrent = Infinity; }
1940
+ return mergeMap(identity, concurrent);
1941
+ }
1942
+
1810
1943
  function timer(dueTime, intervalOrScheduler, scheduler) {
1811
1944
  if (dueTime === void 0) { dueTime = 0; }
1812
1945
  if (scheduler === void 0) { scheduler = async; }
@@ -1839,13 +1972,22 @@ function timer(dueTime, intervalOrScheduler, scheduler) {
1839
1972
  });
1840
1973
  }
1841
1974
 
1842
- function interval(period, scheduler) {
1843
- if (period === void 0) { period = 0; }
1844
- if (scheduler === void 0) { scheduler = asyncScheduler; }
1845
- if (period < 0) {
1846
- period = 0;
1975
+ function merge() {
1976
+ var args = [];
1977
+ for (var _i = 0; _i < arguments.length; _i++) {
1978
+ args[_i] = arguments[_i];
1847
1979
  }
1848
- return timer(period, period, scheduler);
1980
+ var scheduler = popScheduler(args);
1981
+ var concurrent = popNumber(args, Infinity);
1982
+ var sources = args;
1983
+ return !sources.length
1984
+ ?
1985
+ EMPTY
1986
+ : sources.length === 1
1987
+ ?
1988
+ innerFrom(sources[0])
1989
+ :
1990
+ mergeAll(concurrent)(from(sources, scheduler));
1849
1991
  }
1850
1992
 
1851
1993
  function filter(predicate, thisArg) {
@@ -1873,6 +2015,36 @@ function buffer(closingNotifier) {
1873
2015
  });
1874
2016
  }
1875
2017
 
2018
+ function debounce(durationSelector) {
2019
+ return operate(function (source, subscriber) {
2020
+ var hasValue = false;
2021
+ var lastValue = null;
2022
+ var durationSubscriber = null;
2023
+ var emit = function () {
2024
+ durationSubscriber === null || durationSubscriber === void 0 ? void 0 : durationSubscriber.unsubscribe();
2025
+ durationSubscriber = null;
2026
+ if (hasValue) {
2027
+ hasValue = false;
2028
+ var value = lastValue;
2029
+ lastValue = null;
2030
+ subscriber.next(value);
2031
+ }
2032
+ };
2033
+ source.subscribe(createOperatorSubscriber(subscriber, function (value) {
2034
+ durationSubscriber === null || durationSubscriber === void 0 ? void 0 : durationSubscriber.unsubscribe();
2035
+ hasValue = true;
2036
+ lastValue = value;
2037
+ durationSubscriber = createOperatorSubscriber(subscriber, emit, noop);
2038
+ innerFrom(durationSelector(value)).subscribe(durationSubscriber);
2039
+ }, function () {
2040
+ emit();
2041
+ subscriber.complete();
2042
+ }, undefined, function () {
2043
+ lastValue = durationSubscriber = null;
2044
+ }));
2045
+ });
2046
+ }
2047
+
1876
2048
  function defaultIfEmpty(defaultValue) {
1877
2049
  return operate(function (source, subscriber) {
1878
2050
  var hasValue = false;
@@ -1905,10 +2077,6 @@ function take(count) {
1905
2077
  });
1906
2078
  }
1907
2079
 
1908
- function mapTo(value) {
1909
- return map(function () { return value; });
1910
- }
1911
-
1912
2080
  function throwIfEmpty(errorFactory) {
1913
2081
  if (errorFactory === void 0) { errorFactory = defaultErrorFactory; }
1914
2082
  return operate(function (source, subscriber) {
@@ -2003,7 +2171,7 @@ const filesStart$ = writerEvent$.pipe(filter((x) => {
2003
2171
  const filesStart = () => firstValueFrom(filesStart$);
2004
2172
  const filesReady$ = writerEvent$.pipe(filter((x) => {
2005
2173
  return x.type === "writeBundle";
2006
- }), switchMap((event) => interval(100).pipe(mapTo(event), first(({ bundle, options, timestamp }) => {
2174
+ }), switchMap((event) => timer(0, 100).pipe(map(() => event), first(({ bundle, options, timestamp }) => {
2007
2175
  const result = Object.keys(bundle).every((p) => {
2008
2176
  const stats = statSync(join(options.dir, p));
2009
2177
  return stats.mtimeMs > timestamp;
@@ -2152,7 +2320,6 @@ const pluginFileWriterPublic = () => {
2152
2320
  const source = await fsExtra.readFile(file);
2153
2321
  const fileName = relative(config.publicDir, file);
2154
2322
  this.emitFile({ type: "asset", fileName, source });
2155
- this.addWatchFile(file);
2156
2323
  }
2157
2324
  }
2158
2325
  }
@@ -2187,6 +2354,94 @@ const pluginFileWriterPolyfill = () => {
2187
2354
  };
2188
2355
  };
2189
2356
 
2357
+ function isUpdatePayload(p) {
2358
+ return p.type === "update";
2359
+ }
2360
+ function isFullReloadPayload(p) {
2361
+ return p.type === "full-reload";
2362
+ }
2363
+ function isPrunePayload(p) {
2364
+ return p.type === "prune";
2365
+ }
2366
+ function isCrxHMRPayload(x) {
2367
+ return x.type === "custom" && x.event.startsWith("crx:");
2368
+ }
2369
+ const hmrPayload$ = new Subject();
2370
+ const hmrPrune$ = hmrPayload$.pipe(filter(isPrunePayload));
2371
+ const hmrFullReload$ = hmrPayload$.pipe(filter(isFullReloadPayload));
2372
+ const hmrUpdate$ = hmrPayload$.pipe(filter(isUpdatePayload));
2373
+ const payload$ = merge(hmrFullReload$, hmrPrune$, hmrUpdate$);
2374
+ const rebuildSignal$ = payload$.pipe(buffer(payload$.pipe(debounce(() => filesReady$))), map((payloads) => {
2375
+ if (payloads.every(isUpdatePayload)) {
2376
+ const owners = /* @__PURE__ */ new Set();
2377
+ for (const { updates } of payloads)
2378
+ for (const { path } of updates)
2379
+ if (transformResultByOwner.has(path))
2380
+ owners.add(path);
2381
+ return { type: "partial", owners };
2382
+ }
2383
+ return { type: "full" };
2384
+ }), filter((rebuild) => rebuild.type === "partial" ? rebuild.owners.size > 0 : true));
2385
+ const crxHmrPayload$ = hmrPayload$.pipe(filter((p) => !isCrxHMRPayload(p)), buffer(filesReady$), mergeMap((pps) => {
2386
+ let fullReload;
2387
+ const payloads = [];
2388
+ for (const p of pps.slice(-50))
2389
+ if (p.type === "full-reload") {
2390
+ fullReload = p;
2391
+ } else {
2392
+ payloads.push(p);
2393
+ }
2394
+ if (fullReload)
2395
+ payloads.push(fullReload);
2396
+ return payloads;
2397
+ }), map((p) => {
2398
+ switch (p.type) {
2399
+ case "full-reload": {
2400
+ const path = p.path && outputByOwner.get(p.path);
2401
+ const fullReload = {
2402
+ type: "full-reload",
2403
+ path
2404
+ };
2405
+ return fullReload;
2406
+ }
2407
+ case "prune": {
2408
+ const paths = [];
2409
+ for (const owner of p.paths)
2410
+ if (outputByOwner.has(owner))
2411
+ paths.push(outputByOwner.get(owner));
2412
+ return { type: "prune", paths };
2413
+ }
2414
+ case "update": {
2415
+ const updates = [];
2416
+ for (const { acceptedPath, path, ...rest } of p.updates)
2417
+ if (outputByOwner.has(acceptedPath) && outputByOwner.has(path))
2418
+ updates.push({
2419
+ ...rest,
2420
+ acceptedPath: outputByOwner.get(acceptedPath),
2421
+ path: outputByOwner.get(path)
2422
+ });
2423
+ return { type: "update", updates };
2424
+ }
2425
+ default:
2426
+ return p;
2427
+ }
2428
+ }), withLatestFrom(filesReady$), filter(([p, { bundle }]) => {
2429
+ switch (p.type) {
2430
+ case "full-reload":
2431
+ return typeof p.path === "undefined" || p.path in bundle;
2432
+ case "prune":
2433
+ return p.paths.length > 0;
2434
+ case "update":
2435
+ return p.updates.length > 0;
2436
+ default:
2437
+ return true;
2438
+ }
2439
+ }), map(([p]) => ({
2440
+ type: "custom",
2441
+ event: "crx:content-script-payload",
2442
+ data: p
2443
+ })));
2444
+
2190
2445
  function sortPlugins(plugins, command) {
2191
2446
  const pre = [];
2192
2447
  const mid = [];
@@ -2283,6 +2538,18 @@ const pluginFileWriter = (crxPlugins) => (options) => {
2283
2538
  writerEvent$.next({ type: "error", error, code, frame });
2284
2539
  }
2285
2540
  });
2541
+ const rebuildSub = rebuildSignal$.subscribe((rebuild) => {
2542
+ if (rebuild.type === "partial") {
2543
+ for (const owner of rebuild.owners)
2544
+ transformResultByOwner.delete(owner);
2545
+ } else {
2546
+ transformResultByOwner.clear();
2547
+ }
2548
+ rebuildFiles();
2549
+ });
2550
+ watcher.on("close", () => {
2551
+ rebuildSub.unsubscribe();
2552
+ });
2286
2553
  });
2287
2554
  },
2288
2555
  closeBundle() {
@@ -2291,87 +2558,30 @@ const pluginFileWriter = (crxPlugins) => (options) => {
2291
2558
  };
2292
2559
  };
2293
2560
 
2294
- const debug$2 = _debug("hmr");
2295
2561
  function isImporter(file) {
2296
- const pred = (node) => {
2297
- if (node.file === file)
2562
+ const seen = /* @__PURE__ */ new Set();
2563
+ const pred = (changedNode) => {
2564
+ seen.add(changedNode);
2565
+ if (changedNode.file === file)
2298
2566
  return true;
2299
- for (const node2 of node.importers)
2300
- if (pred(node2))
2567
+ for (const parentNode of changedNode.importers) {
2568
+ const unseen = !seen.has(parentNode);
2569
+ if (unseen && pred(parentNode))
2301
2570
  return true;
2571
+ }
2572
+ return false;
2302
2573
  };
2303
2574
  return pred;
2304
2575
  }
2305
- function isCrxHMRPayload(x) {
2306
- return x.type === "custom" && x.event.startsWith("crx:");
2307
- }
2308
- const hmrPayload$ = new Subject();
2309
- const crxHmrPayload$ = hmrPayload$.pipe(filter((p) => !isCrxHMRPayload(p)), buffer(filesReady$), mergeMap((pps) => {
2310
- let fullReload;
2311
- const payloads = [];
2312
- for (const p of pps.slice(-50))
2313
- if (p.type === "full-reload") {
2314
- fullReload = p;
2315
- } else {
2316
- payloads.push(p);
2317
- }
2318
- if (fullReload)
2319
- payloads.push(fullReload);
2320
- return payloads;
2321
- }), map((p) => {
2322
- switch (p.type) {
2323
- case "full-reload": {
2324
- const path = p.path && outputByOwner.get(p.path);
2325
- const fullReload = {
2326
- type: "full-reload",
2327
- path
2328
- };
2329
- return fullReload;
2330
- }
2331
- case "prune": {
2332
- const paths = [];
2333
- for (const owner of p.paths)
2334
- if (outputByOwner.has(owner))
2335
- paths.push(outputByOwner.get(owner));
2336
- return { type: "prune", paths };
2337
- }
2338
- case "update": {
2339
- const updates = [];
2340
- for (const { acceptedPath, path, ...rest } of p.updates)
2341
- if (outputByOwner.has(acceptedPath) && outputByOwner.has(path))
2342
- updates.push({
2343
- ...rest,
2344
- acceptedPath: outputByOwner.get(acceptedPath),
2345
- path: outputByOwner.get(path)
2346
- });
2347
- return { type: "update", updates };
2348
- }
2349
- default:
2350
- return p;
2351
- }
2352
- }), withLatestFrom(filesReady$), filter(([p, { bundle }]) => {
2353
- switch (p.type) {
2354
- case "full-reload":
2355
- return typeof p.path === "undefined" || p.path in bundle;
2356
- case "prune":
2357
- return p.paths.length > 0;
2358
- case "update":
2359
- return p.updates.length > 0;
2360
- default:
2361
- return true;
2362
- }
2363
- }), map(([p]) => ({
2364
- type: "custom",
2365
- event: "crx:content-script-payload",
2366
- data: p
2367
- })));
2576
+
2577
+ const debug$2 = _debug("hmr");
2368
2578
  const crxRuntimeReload = {
2369
2579
  type: "custom",
2370
2580
  event: "crx:runtime-reload"
2371
2581
  };
2372
2582
  const pluginHMR = () => {
2373
2583
  let files;
2374
- let server;
2584
+ let decoratedSend;
2375
2585
  return [
2376
2586
  {
2377
2587
  name: "crx:hmr",
@@ -2388,38 +2598,41 @@ const pluginHMR = () => {
2388
2598
  name: "crx:hmr",
2389
2599
  apply: "serve",
2390
2600
  enforce: "pre",
2391
- config({ server: server2 = {}, ...config }) {
2392
- if (server2.hmr === false)
2601
+ config({ server = {}, ...config }) {
2602
+ if (server.hmr === false)
2393
2603
  return;
2394
- if (server2.hmr === true)
2395
- server2.hmr = {};
2396
- server2.hmr = server2.hmr ?? {};
2397
- server2.hmr.host = "localhost";
2398
- return { server: server2, ...config };
2604
+ if (server.hmr === true)
2605
+ server.hmr = {};
2606
+ server.hmr = server.hmr ?? {};
2607
+ server.hmr.host = "localhost";
2608
+ return { server, ...config };
2399
2609
  },
2400
2610
  configResolved(config) {
2401
2611
  const { watch = {} } = config.server;
2402
2612
  config.server.watch = watch;
2403
2613
  watch.ignored = watch.ignored ? [...new Set([watch.ignored].flat())] : [];
2404
- watch.ignored.push(config.build.outDir);
2614
+ const outDir = isAbsolute(config.build.outDir) ? config.build.outDir : join(config.root, config.build.outDir, "**/*");
2615
+ watch.ignored.push(outDir);
2405
2616
  },
2406
- configureServer(_server) {
2407
- server = _server;
2408
- const { send } = server.ws;
2409
- server.ws.send = (payload) => {
2410
- hmrPayload$.next(payload);
2411
- send(payload);
2412
- };
2413
- crxHmrPayload$.subscribe((payload) => {
2414
- send(payload);
2415
- });
2617
+ configureServer(server) {
2618
+ if (server.ws.send !== decoratedSend) {
2619
+ const { send } = server.ws;
2620
+ decoratedSend = (payload) => {
2621
+ hmrPayload$.next(payload);
2622
+ send(payload);
2623
+ };
2624
+ server.ws.send = decoratedSend;
2625
+ crxHmrPayload$.subscribe((payload) => {
2626
+ send(payload);
2627
+ });
2628
+ }
2416
2629
  },
2417
- handleHotUpdate({ file, modules, server: server2 }) {
2418
- const background = files.background[0] && join(server2.config.root, files.background[0]);
2630
+ handleHotUpdate({ file, modules, server }) {
2631
+ const background = files.background[0] && join(server.config.root, files.background[0]);
2419
2632
  if (background) {
2420
2633
  if (file === background || modules.some(isImporter(background))) {
2421
2634
  debug$2("sending runtime reload");
2422
- server2.ws.send(crxRuntimeReload);
2635
+ server.ws.send(crxRuntimeReload);
2423
2636
  return [];
2424
2637
  }
2425
2638
  }
@@ -2571,17 +2784,28 @@ const pluginManifest = (_manifest) => () => {
2571
2784
  async config(config2, env) {
2572
2785
  manifest = await (typeof _manifest === "function" ? _manifest(env) : _manifest);
2573
2786
  if (manifest.manifest_version !== 3)
2574
- throw new Error(`Manifest v${manifest.manifest_version} is currently unsupported, please use manifest v3`);
2787
+ throw new Error(`CRXJS does not support Manifest v${manifest.manifest_version}, please use Manifest v3`);
2575
2788
  if (env.command === "serve") {
2576
2789
  const {
2577
2790
  contentScripts: js,
2578
2791
  background: sw,
2579
2792
  html
2580
2793
  } = await manifestFiles(manifest);
2581
- let { entries = [] } = config2.optimizeDeps ?? {};
2582
- entries = [entries].flat();
2583
- const set = new Set(entries);
2584
- for (const x of [...js, ...sw, ...html])
2794
+ const { entries = [] } = config2.optimizeDeps ?? {};
2795
+ let { input = [] } = config2.build?.rollupOptions ?? {};
2796
+ if (typeof input === "string")
2797
+ input = [input];
2798
+ else
2799
+ input = Object.values(input);
2800
+ input = input.map((f) => {
2801
+ let result = f;
2802
+ if (isAbsolute(f)) {
2803
+ result = relative(config2.root ?? process.cwd(), f);
2804
+ }
2805
+ return result;
2806
+ });
2807
+ const set = new Set([entries, input].flat());
2808
+ for (const x of [js, sw, html].flat())
2585
2809
  set.add(x);
2586
2810
  return {
2587
2811
  ...config2,
@@ -3125,6 +3349,7 @@ const pluginResources = ({ contentScripts = {} }) => {
3125
3349
  resource.resources.push(...css);
3126
3350
  }
3127
3351
  if (resource.resources.length) {
3352
+ resource.matches = resource.matches.map(stubMatchPattern);
3128
3353
  manifest.web_accessible_resources.push(resource);
3129
3354
  }
3130
3355
  }
package/dist/index.mjs CHANGED
@@ -99,6 +99,12 @@ function encodeManifest(manifest) {
99
99
  const json = JSON.stringify(JSON.stringify(manifest));
100
100
  return `export default ${json}`;
101
101
  }
102
+ const stubMatchPattern = (pattern) => {
103
+ const [schema, rest] = pattern.split("://");
104
+ const [origin, pathname] = rest.split("/");
105
+ const root = `${schema}://${origin}`;
106
+ return pathname ? `${root}/*` : root;
107
+ };
102
108
 
103
109
  const idBySource = /* @__PURE__ */ new Map();
104
110
  const idByUrl = /* @__PURE__ */ new Map();
@@ -152,6 +158,7 @@ const setOutputMeta = ({
152
158
  outputByOwner.set(ownerName, output);
153
159
  outputById.set(id, output);
154
160
  };
161
+ const transformResultByOwner = /* @__PURE__ */ new Map();
155
162
 
156
163
  const {
157
164
  basename,
@@ -198,17 +205,12 @@ function sourceToUrlMeta(source) {
198
205
  }
199
206
  const pluginFileWriterChunks = () => {
200
207
  let server;
201
- const ownerToTransformResultMap = /* @__PURE__ */ new Map();
202
208
  return {
203
209
  name: "crx:file-writer-chunks",
204
210
  apply: "build",
205
211
  fileWriterStart(_server) {
206
212
  server = _server;
207
213
  },
208
- watchChange(fileName) {
209
- for (const owner of ownersByFile.get(fileName) ?? /* @__PURE__ */ new Set())
210
- ownerToTransformResultMap.delete(owner);
211
- },
212
214
  async resolveId(source, importer) {
213
215
  if (this.meta.watchMode) {
214
216
  if (idBySource.has(source)) {
@@ -244,12 +246,12 @@ const pluginFileWriterChunks = () => {
244
246
  if (!serverModule)
245
247
  throw new Error(`Unable to load "${url}" from server.`);
246
248
  const { file, url: owner } = serverModule;
247
- transformResult = transformResult ?? ownerToTransformResultMap.get(owner) ?? serverModule.transformResult;
249
+ transformResult = transformResult ?? transformResultByOwner.get(owner) ?? serverModule.transformResult;
248
250
  if (!transformResult)
249
251
  transformResult = await server.transformRequest(url);
250
252
  if (!transformResult)
251
253
  throw new TypeError(`Unable to load "${url}" from server.`);
252
- ownerToTransformResultMap.set(owner, transformResult);
254
+ transformResultByOwner.set(owner, transformResult);
253
255
  if (file) {
254
256
  setFileMeta({ id, file });
255
257
  this.addWatchFile(file);
@@ -336,7 +338,7 @@ const pluginFileWriterChunks = () => {
336
338
  };
337
339
  };
338
340
 
339
- /*! *****************************************************************************
341
+ /******************************************************************************
340
342
  Copyright (c) Microsoft Corporation.
341
343
 
342
344
  Permission to use, copy, modify, and/or distribute this software for any
@@ -1448,6 +1450,12 @@ function last(arr) {
1448
1450
  function popResultSelector(args) {
1449
1451
  return isFunction(last(args)) ? args.pop() : undefined;
1450
1452
  }
1453
+ function popScheduler(args) {
1454
+ return isScheduler(last(args)) ? args.pop() : undefined;
1455
+ }
1456
+ function popNumber(args, defaultValue) {
1457
+ return typeof last(args) === 'number' ? args.pop() : defaultValue;
1458
+ }
1451
1459
 
1452
1460
  var isArrayLike = (function (x) { return x && typeof x.length === 'number' && typeof x !== 'function'; });
1453
1461
 
@@ -1664,6 +1672,126 @@ function executeSchedule(parentSubscription, scheduler, work, delay, repeat) {
1664
1672
  }
1665
1673
  }
1666
1674
 
1675
+ function observeOn(scheduler, delay) {
1676
+ if (delay === void 0) { delay = 0; }
1677
+ return operate(function (source, subscriber) {
1678
+ source.subscribe(createOperatorSubscriber(subscriber, function (value) { return executeSchedule(subscriber, scheduler, function () { return subscriber.next(value); }, delay); }, function () { return executeSchedule(subscriber, scheduler, function () { return subscriber.complete(); }, delay); }, function (err) { return executeSchedule(subscriber, scheduler, function () { return subscriber.error(err); }, delay); }));
1679
+ });
1680
+ }
1681
+
1682
+ function subscribeOn(scheduler, delay) {
1683
+ if (delay === void 0) { delay = 0; }
1684
+ return operate(function (source, subscriber) {
1685
+ subscriber.add(scheduler.schedule(function () { return source.subscribe(subscriber); }, delay));
1686
+ });
1687
+ }
1688
+
1689
+ function scheduleObservable(input, scheduler) {
1690
+ return innerFrom(input).pipe(subscribeOn(scheduler), observeOn(scheduler));
1691
+ }
1692
+
1693
+ function schedulePromise(input, scheduler) {
1694
+ return innerFrom(input).pipe(subscribeOn(scheduler), observeOn(scheduler));
1695
+ }
1696
+
1697
+ function scheduleArray(input, scheduler) {
1698
+ return new Observable(function (subscriber) {
1699
+ var i = 0;
1700
+ return scheduler.schedule(function () {
1701
+ if (i === input.length) {
1702
+ subscriber.complete();
1703
+ }
1704
+ else {
1705
+ subscriber.next(input[i++]);
1706
+ if (!subscriber.closed) {
1707
+ this.schedule();
1708
+ }
1709
+ }
1710
+ });
1711
+ });
1712
+ }
1713
+
1714
+ function scheduleIterable(input, scheduler) {
1715
+ return new Observable(function (subscriber) {
1716
+ var iterator$1;
1717
+ executeSchedule(subscriber, scheduler, function () {
1718
+ iterator$1 = input[iterator]();
1719
+ executeSchedule(subscriber, scheduler, function () {
1720
+ var _a;
1721
+ var value;
1722
+ var done;
1723
+ try {
1724
+ (_a = iterator$1.next(), value = _a.value, done = _a.done);
1725
+ }
1726
+ catch (err) {
1727
+ subscriber.error(err);
1728
+ return;
1729
+ }
1730
+ if (done) {
1731
+ subscriber.complete();
1732
+ }
1733
+ else {
1734
+ subscriber.next(value);
1735
+ }
1736
+ }, 0, true);
1737
+ });
1738
+ return function () { return isFunction(iterator$1 === null || iterator$1 === void 0 ? void 0 : iterator$1.return) && iterator$1.return(); };
1739
+ });
1740
+ }
1741
+
1742
+ function scheduleAsyncIterable(input, scheduler) {
1743
+ if (!input) {
1744
+ throw new Error('Iterable cannot be null');
1745
+ }
1746
+ return new Observable(function (subscriber) {
1747
+ executeSchedule(subscriber, scheduler, function () {
1748
+ var iterator = input[Symbol.asyncIterator]();
1749
+ executeSchedule(subscriber, scheduler, function () {
1750
+ iterator.next().then(function (result) {
1751
+ if (result.done) {
1752
+ subscriber.complete();
1753
+ }
1754
+ else {
1755
+ subscriber.next(result.value);
1756
+ }
1757
+ });
1758
+ }, 0, true);
1759
+ });
1760
+ });
1761
+ }
1762
+
1763
+ function scheduleReadableStreamLike(input, scheduler) {
1764
+ return scheduleAsyncIterable(readableStreamLikeToAsyncGenerator(input), scheduler);
1765
+ }
1766
+
1767
+ function scheduled(input, scheduler) {
1768
+ if (input != null) {
1769
+ if (isInteropObservable(input)) {
1770
+ return scheduleObservable(input, scheduler);
1771
+ }
1772
+ if (isArrayLike(input)) {
1773
+ return scheduleArray(input, scheduler);
1774
+ }
1775
+ if (isPromise(input)) {
1776
+ return schedulePromise(input, scheduler);
1777
+ }
1778
+ if (isAsyncIterable(input)) {
1779
+ return scheduleAsyncIterable(input, scheduler);
1780
+ }
1781
+ if (isIterable(input)) {
1782
+ return scheduleIterable(input, scheduler);
1783
+ }
1784
+ if (isReadableStreamLike(input)) {
1785
+ return scheduleReadableStreamLike(input, scheduler);
1786
+ }
1787
+ }
1788
+ throw createInvalidObservableTypeError(input);
1789
+ }
1790
+
1791
+ function from(input, scheduler) {
1792
+ return scheduler ? scheduled(input, scheduler) : innerFrom(input);
1793
+ }
1794
+
1667
1795
  var EmptyError = createErrorClass(function (_super) { return function EmptyErrorImpl() {
1668
1796
  _super(this);
1669
1797
  this.name = 'EmptyError';
@@ -1774,6 +1902,11 @@ function mergeMap(project, resultSelector, concurrent) {
1774
1902
  return operate(function (source, subscriber) { return mergeInternals(source, subscriber, project, concurrent); });
1775
1903
  }
1776
1904
 
1905
+ function mergeAll(concurrent) {
1906
+ if (concurrent === void 0) { concurrent = Infinity; }
1907
+ return mergeMap(identity, concurrent);
1908
+ }
1909
+
1777
1910
  function timer(dueTime, intervalOrScheduler, scheduler) {
1778
1911
  if (dueTime === void 0) { dueTime = 0; }
1779
1912
  if (scheduler === void 0) { scheduler = async; }
@@ -1806,13 +1939,22 @@ function timer(dueTime, intervalOrScheduler, scheduler) {
1806
1939
  });
1807
1940
  }
1808
1941
 
1809
- function interval(period, scheduler) {
1810
- if (period === void 0) { period = 0; }
1811
- if (scheduler === void 0) { scheduler = asyncScheduler; }
1812
- if (period < 0) {
1813
- period = 0;
1942
+ function merge() {
1943
+ var args = [];
1944
+ for (var _i = 0; _i < arguments.length; _i++) {
1945
+ args[_i] = arguments[_i];
1814
1946
  }
1815
- return timer(period, period, scheduler);
1947
+ var scheduler = popScheduler(args);
1948
+ var concurrent = popNumber(args, Infinity);
1949
+ var sources = args;
1950
+ return !sources.length
1951
+ ?
1952
+ EMPTY
1953
+ : sources.length === 1
1954
+ ?
1955
+ innerFrom(sources[0])
1956
+ :
1957
+ mergeAll(concurrent)(from(sources, scheduler));
1816
1958
  }
1817
1959
 
1818
1960
  function filter(predicate, thisArg) {
@@ -1840,6 +1982,36 @@ function buffer(closingNotifier) {
1840
1982
  });
1841
1983
  }
1842
1984
 
1985
+ function debounce(durationSelector) {
1986
+ return operate(function (source, subscriber) {
1987
+ var hasValue = false;
1988
+ var lastValue = null;
1989
+ var durationSubscriber = null;
1990
+ var emit = function () {
1991
+ durationSubscriber === null || durationSubscriber === void 0 ? void 0 : durationSubscriber.unsubscribe();
1992
+ durationSubscriber = null;
1993
+ if (hasValue) {
1994
+ hasValue = false;
1995
+ var value = lastValue;
1996
+ lastValue = null;
1997
+ subscriber.next(value);
1998
+ }
1999
+ };
2000
+ source.subscribe(createOperatorSubscriber(subscriber, function (value) {
2001
+ durationSubscriber === null || durationSubscriber === void 0 ? void 0 : durationSubscriber.unsubscribe();
2002
+ hasValue = true;
2003
+ lastValue = value;
2004
+ durationSubscriber = createOperatorSubscriber(subscriber, emit, noop);
2005
+ innerFrom(durationSelector(value)).subscribe(durationSubscriber);
2006
+ }, function () {
2007
+ emit();
2008
+ subscriber.complete();
2009
+ }, undefined, function () {
2010
+ lastValue = durationSubscriber = null;
2011
+ }));
2012
+ });
2013
+ }
2014
+
1843
2015
  function defaultIfEmpty(defaultValue) {
1844
2016
  return operate(function (source, subscriber) {
1845
2017
  var hasValue = false;
@@ -1872,10 +2044,6 @@ function take(count) {
1872
2044
  });
1873
2045
  }
1874
2046
 
1875
- function mapTo(value) {
1876
- return map(function () { return value; });
1877
- }
1878
-
1879
2047
  function throwIfEmpty(errorFactory) {
1880
2048
  if (errorFactory === void 0) { errorFactory = defaultErrorFactory; }
1881
2049
  return operate(function (source, subscriber) {
@@ -1970,7 +2138,7 @@ const filesStart$ = writerEvent$.pipe(filter((x) => {
1970
2138
  const filesStart = () => firstValueFrom(filesStart$);
1971
2139
  const filesReady$ = writerEvent$.pipe(filter((x) => {
1972
2140
  return x.type === "writeBundle";
1973
- }), switchMap((event) => interval(100).pipe(mapTo(event), first(({ bundle, options, timestamp }) => {
2141
+ }), switchMap((event) => timer(0, 100).pipe(map(() => event), first(({ bundle, options, timestamp }) => {
1974
2142
  const result = Object.keys(bundle).every((p) => {
1975
2143
  const stats = statSync(join(options.dir, p));
1976
2144
  return stats.mtimeMs > timestamp;
@@ -2119,7 +2287,6 @@ const pluginFileWriterPublic = () => {
2119
2287
  const source = await readFile(file);
2120
2288
  const fileName = relative(config.publicDir, file);
2121
2289
  this.emitFile({ type: "asset", fileName, source });
2122
- this.addWatchFile(file);
2123
2290
  }
2124
2291
  }
2125
2292
  }
@@ -2154,6 +2321,94 @@ const pluginFileWriterPolyfill = () => {
2154
2321
  };
2155
2322
  };
2156
2323
 
2324
+ function isUpdatePayload(p) {
2325
+ return p.type === "update";
2326
+ }
2327
+ function isFullReloadPayload(p) {
2328
+ return p.type === "full-reload";
2329
+ }
2330
+ function isPrunePayload(p) {
2331
+ return p.type === "prune";
2332
+ }
2333
+ function isCrxHMRPayload(x) {
2334
+ return x.type === "custom" && x.event.startsWith("crx:");
2335
+ }
2336
+ const hmrPayload$ = new Subject();
2337
+ const hmrPrune$ = hmrPayload$.pipe(filter(isPrunePayload));
2338
+ const hmrFullReload$ = hmrPayload$.pipe(filter(isFullReloadPayload));
2339
+ const hmrUpdate$ = hmrPayload$.pipe(filter(isUpdatePayload));
2340
+ const payload$ = merge(hmrFullReload$, hmrPrune$, hmrUpdate$);
2341
+ const rebuildSignal$ = payload$.pipe(buffer(payload$.pipe(debounce(() => filesReady$))), map((payloads) => {
2342
+ if (payloads.every(isUpdatePayload)) {
2343
+ const owners = /* @__PURE__ */ new Set();
2344
+ for (const { updates } of payloads)
2345
+ for (const { path } of updates)
2346
+ if (transformResultByOwner.has(path))
2347
+ owners.add(path);
2348
+ return { type: "partial", owners };
2349
+ }
2350
+ return { type: "full" };
2351
+ }), filter((rebuild) => rebuild.type === "partial" ? rebuild.owners.size > 0 : true));
2352
+ const crxHmrPayload$ = hmrPayload$.pipe(filter((p) => !isCrxHMRPayload(p)), buffer(filesReady$), mergeMap((pps) => {
2353
+ let fullReload;
2354
+ const payloads = [];
2355
+ for (const p of pps.slice(-50))
2356
+ if (p.type === "full-reload") {
2357
+ fullReload = p;
2358
+ } else {
2359
+ payloads.push(p);
2360
+ }
2361
+ if (fullReload)
2362
+ payloads.push(fullReload);
2363
+ return payloads;
2364
+ }), map((p) => {
2365
+ switch (p.type) {
2366
+ case "full-reload": {
2367
+ const path = p.path && outputByOwner.get(p.path);
2368
+ const fullReload = {
2369
+ type: "full-reload",
2370
+ path
2371
+ };
2372
+ return fullReload;
2373
+ }
2374
+ case "prune": {
2375
+ const paths = [];
2376
+ for (const owner of p.paths)
2377
+ if (outputByOwner.has(owner))
2378
+ paths.push(outputByOwner.get(owner));
2379
+ return { type: "prune", paths };
2380
+ }
2381
+ case "update": {
2382
+ const updates = [];
2383
+ for (const { acceptedPath, path, ...rest } of p.updates)
2384
+ if (outputByOwner.has(acceptedPath) && outputByOwner.has(path))
2385
+ updates.push({
2386
+ ...rest,
2387
+ acceptedPath: outputByOwner.get(acceptedPath),
2388
+ path: outputByOwner.get(path)
2389
+ });
2390
+ return { type: "update", updates };
2391
+ }
2392
+ default:
2393
+ return p;
2394
+ }
2395
+ }), withLatestFrom(filesReady$), filter(([p, { bundle }]) => {
2396
+ switch (p.type) {
2397
+ case "full-reload":
2398
+ return typeof p.path === "undefined" || p.path in bundle;
2399
+ case "prune":
2400
+ return p.paths.length > 0;
2401
+ case "update":
2402
+ return p.updates.length > 0;
2403
+ default:
2404
+ return true;
2405
+ }
2406
+ }), map(([p]) => ({
2407
+ type: "custom",
2408
+ event: "crx:content-script-payload",
2409
+ data: p
2410
+ })));
2411
+
2157
2412
  function sortPlugins(plugins, command) {
2158
2413
  const pre = [];
2159
2414
  const mid = [];
@@ -2250,6 +2505,18 @@ const pluginFileWriter = (crxPlugins) => (options) => {
2250
2505
  writerEvent$.next({ type: "error", error, code, frame });
2251
2506
  }
2252
2507
  });
2508
+ const rebuildSub = rebuildSignal$.subscribe((rebuild) => {
2509
+ if (rebuild.type === "partial") {
2510
+ for (const owner of rebuild.owners)
2511
+ transformResultByOwner.delete(owner);
2512
+ } else {
2513
+ transformResultByOwner.clear();
2514
+ }
2515
+ rebuildFiles();
2516
+ });
2517
+ watcher.on("close", () => {
2518
+ rebuildSub.unsubscribe();
2519
+ });
2253
2520
  });
2254
2521
  },
2255
2522
  closeBundle() {
@@ -2258,87 +2525,30 @@ const pluginFileWriter = (crxPlugins) => (options) => {
2258
2525
  };
2259
2526
  };
2260
2527
 
2261
- const debug$2 = _debug("hmr");
2262
2528
  function isImporter(file) {
2263
- const pred = (node) => {
2264
- if (node.file === file)
2529
+ const seen = /* @__PURE__ */ new Set();
2530
+ const pred = (changedNode) => {
2531
+ seen.add(changedNode);
2532
+ if (changedNode.file === file)
2265
2533
  return true;
2266
- for (const node2 of node.importers)
2267
- if (pred(node2))
2534
+ for (const parentNode of changedNode.importers) {
2535
+ const unseen = !seen.has(parentNode);
2536
+ if (unseen && pred(parentNode))
2268
2537
  return true;
2538
+ }
2539
+ return false;
2269
2540
  };
2270
2541
  return pred;
2271
2542
  }
2272
- function isCrxHMRPayload(x) {
2273
- return x.type === "custom" && x.event.startsWith("crx:");
2274
- }
2275
- const hmrPayload$ = new Subject();
2276
- const crxHmrPayload$ = hmrPayload$.pipe(filter((p) => !isCrxHMRPayload(p)), buffer(filesReady$), mergeMap((pps) => {
2277
- let fullReload;
2278
- const payloads = [];
2279
- for (const p of pps.slice(-50))
2280
- if (p.type === "full-reload") {
2281
- fullReload = p;
2282
- } else {
2283
- payloads.push(p);
2284
- }
2285
- if (fullReload)
2286
- payloads.push(fullReload);
2287
- return payloads;
2288
- }), map((p) => {
2289
- switch (p.type) {
2290
- case "full-reload": {
2291
- const path = p.path && outputByOwner.get(p.path);
2292
- const fullReload = {
2293
- type: "full-reload",
2294
- path
2295
- };
2296
- return fullReload;
2297
- }
2298
- case "prune": {
2299
- const paths = [];
2300
- for (const owner of p.paths)
2301
- if (outputByOwner.has(owner))
2302
- paths.push(outputByOwner.get(owner));
2303
- return { type: "prune", paths };
2304
- }
2305
- case "update": {
2306
- const updates = [];
2307
- for (const { acceptedPath, path, ...rest } of p.updates)
2308
- if (outputByOwner.has(acceptedPath) && outputByOwner.has(path))
2309
- updates.push({
2310
- ...rest,
2311
- acceptedPath: outputByOwner.get(acceptedPath),
2312
- path: outputByOwner.get(path)
2313
- });
2314
- return { type: "update", updates };
2315
- }
2316
- default:
2317
- return p;
2318
- }
2319
- }), withLatestFrom(filesReady$), filter(([p, { bundle }]) => {
2320
- switch (p.type) {
2321
- case "full-reload":
2322
- return typeof p.path === "undefined" || p.path in bundle;
2323
- case "prune":
2324
- return p.paths.length > 0;
2325
- case "update":
2326
- return p.updates.length > 0;
2327
- default:
2328
- return true;
2329
- }
2330
- }), map(([p]) => ({
2331
- type: "custom",
2332
- event: "crx:content-script-payload",
2333
- data: p
2334
- })));
2543
+
2544
+ const debug$2 = _debug("hmr");
2335
2545
  const crxRuntimeReload = {
2336
2546
  type: "custom",
2337
2547
  event: "crx:runtime-reload"
2338
2548
  };
2339
2549
  const pluginHMR = () => {
2340
2550
  let files;
2341
- let server;
2551
+ let decoratedSend;
2342
2552
  return [
2343
2553
  {
2344
2554
  name: "crx:hmr",
@@ -2355,38 +2565,41 @@ const pluginHMR = () => {
2355
2565
  name: "crx:hmr",
2356
2566
  apply: "serve",
2357
2567
  enforce: "pre",
2358
- config({ server: server2 = {}, ...config }) {
2359
- if (server2.hmr === false)
2568
+ config({ server = {}, ...config }) {
2569
+ if (server.hmr === false)
2360
2570
  return;
2361
- if (server2.hmr === true)
2362
- server2.hmr = {};
2363
- server2.hmr = server2.hmr ?? {};
2364
- server2.hmr.host = "localhost";
2365
- return { server: server2, ...config };
2571
+ if (server.hmr === true)
2572
+ server.hmr = {};
2573
+ server.hmr = server.hmr ?? {};
2574
+ server.hmr.host = "localhost";
2575
+ return { server, ...config };
2366
2576
  },
2367
2577
  configResolved(config) {
2368
2578
  const { watch = {} } = config.server;
2369
2579
  config.server.watch = watch;
2370
2580
  watch.ignored = watch.ignored ? [...new Set([watch.ignored].flat())] : [];
2371
- watch.ignored.push(config.build.outDir);
2581
+ const outDir = isAbsolute(config.build.outDir) ? config.build.outDir : join(config.root, config.build.outDir, "**/*");
2582
+ watch.ignored.push(outDir);
2372
2583
  },
2373
- configureServer(_server) {
2374
- server = _server;
2375
- const { send } = server.ws;
2376
- server.ws.send = (payload) => {
2377
- hmrPayload$.next(payload);
2378
- send(payload);
2379
- };
2380
- crxHmrPayload$.subscribe((payload) => {
2381
- send(payload);
2382
- });
2584
+ configureServer(server) {
2585
+ if (server.ws.send !== decoratedSend) {
2586
+ const { send } = server.ws;
2587
+ decoratedSend = (payload) => {
2588
+ hmrPayload$.next(payload);
2589
+ send(payload);
2590
+ };
2591
+ server.ws.send = decoratedSend;
2592
+ crxHmrPayload$.subscribe((payload) => {
2593
+ send(payload);
2594
+ });
2595
+ }
2383
2596
  },
2384
- handleHotUpdate({ file, modules, server: server2 }) {
2385
- const background = files.background[0] && join(server2.config.root, files.background[0]);
2597
+ handleHotUpdate({ file, modules, server }) {
2598
+ const background = files.background[0] && join(server.config.root, files.background[0]);
2386
2599
  if (background) {
2387
2600
  if (file === background || modules.some(isImporter(background))) {
2388
2601
  debug$2("sending runtime reload");
2389
- server2.ws.send(crxRuntimeReload);
2602
+ server.ws.send(crxRuntimeReload);
2390
2603
  return [];
2391
2604
  }
2392
2605
  }
@@ -2538,17 +2751,28 @@ const pluginManifest = (_manifest) => () => {
2538
2751
  async config(config2, env) {
2539
2752
  manifest = await (typeof _manifest === "function" ? _manifest(env) : _manifest);
2540
2753
  if (manifest.manifest_version !== 3)
2541
- throw new Error(`Manifest v${manifest.manifest_version} is currently unsupported, please use manifest v3`);
2754
+ throw new Error(`CRXJS does not support Manifest v${manifest.manifest_version}, please use Manifest v3`);
2542
2755
  if (env.command === "serve") {
2543
2756
  const {
2544
2757
  contentScripts: js,
2545
2758
  background: sw,
2546
2759
  html
2547
2760
  } = await manifestFiles(manifest);
2548
- let { entries = [] } = config2.optimizeDeps ?? {};
2549
- entries = [entries].flat();
2550
- const set = new Set(entries);
2551
- for (const x of [...js, ...sw, ...html])
2761
+ const { entries = [] } = config2.optimizeDeps ?? {};
2762
+ let { input = [] } = config2.build?.rollupOptions ?? {};
2763
+ if (typeof input === "string")
2764
+ input = [input];
2765
+ else
2766
+ input = Object.values(input);
2767
+ input = input.map((f) => {
2768
+ let result = f;
2769
+ if (isAbsolute(f)) {
2770
+ result = relative(config2.root ?? process.cwd(), f);
2771
+ }
2772
+ return result;
2773
+ });
2774
+ const set = new Set([entries, input].flat());
2775
+ for (const x of [js, sw, html].flat())
2552
2776
  set.add(x);
2553
2777
  return {
2554
2778
  ...config2,
@@ -3092,6 +3316,7 @@ const pluginResources = ({ contentScripts = {} }) => {
3092
3316
  resource.resources.push(...css);
3093
3317
  }
3094
3318
  if (resource.resources.length) {
3319
+ resource.matches = resource.matches.map(stubMatchPattern);
3095
3320
  manifest.web_accessible_resources.push(resource);
3096
3321
  }
3097
3322
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crxjs/vite-plugin",
3
- "version": "1.0.5",
3
+ "version": "1.0.8",
4
4
  "description": "Build Chrome Extensions with this Vite plugin.",
5
5
  "keywords": [
6
6
  "rollup-plugin",
@@ -50,12 +50,13 @@
50
50
  "lint": "run-s lint:eslint lint:types",
51
51
  "lint:eslint": "eslint \"{src,test}/**/*.ts\"",
52
52
  "lint:types": "tsc --noEmit",
53
- "test": "run-s test:update:*",
53
+ "test": "run-s test:units test:update:*",
54
54
  "test:ci:e2e:build": "node --expose-gc ./node_modules/jest/bin/jest.js --logHeapUsage --runInBand --forceExit --testPathIgnorePatterns=\\(/node_modules/ /templates/ /mv3/\\) -t build",
55
55
  "test:ci:e2e:serve": "npm run test:ci:e2e:serve:cmd || npm run test:ci:e2e:serve:cmd",
56
56
  "test:ci:e2e:serve:cmd": "node --expose-gc ./node_modules/jest/bin/jest.js --logHeapUsage --runInBand --forceExit --testPathIgnorePatterns=\\(/node_modules/ /templates/ /mv3/\\) -t serve",
57
57
  "test:ci:mv3:build": "node --expose-gc ./node_modules/jest/bin/jest.js --logHeapUsage --runInBand --forceExit --testPathIgnorePatterns=\\(/node_modules/ /templates/ /e2e/\\) --updateSnapshot build",
58
58
  "test:ci:mv3:serve": "node --expose-gc ./node_modules/jest/bin/jest.js --logHeapUsage --runInBand --forceExit --testPathIgnorePatterns=\\(/node_modules/ /templates/ /e2e/\\) --updateSnapshot serve",
59
+ "test:units": "jest src",
59
60
  "test:update:build": "jest build -u",
60
61
  "test:update:serve": "jest serve -u"
61
62
  },
@@ -82,22 +83,22 @@
82
83
  "@rollup/plugin-commonjs": "21.1.0",
83
84
  "@rollup/plugin-node-resolve": "13.2.0",
84
85
  "@types/acorn": "4.0.6",
85
- "@types/chrome": "0.0.184",
86
+ "@types/chrome": "0.0.188",
86
87
  "@types/debug": "4.1.7",
87
88
  "@types/fs-extra": "9.0.13",
88
- "@types/jest": "27.5.0",
89
+ "@types/jest": "27.5.1",
89
90
  "@types/jest-image-snapshot": "4.3.1",
90
91
  "@types/jsesc": "3.0.1",
91
92
  "@types/node": "17.0.18",
92
93
  "@types/react": "17.0.44",
93
- "@types/react-dom": "17.0.16",
94
- "@typescript-eslint/eslint-plugin": "5.21.0",
95
- "@typescript-eslint/parser": "5.21.0",
96
- "@vitejs/plugin-react": "1.3.1",
97
- "@vitejs/plugin-vue": "2.3.2",
98
- "esbuild": "0.14.38",
94
+ "@types/react-dom": "17.0.17",
95
+ "@typescript-eslint/eslint-plugin": "5.23.0",
96
+ "@typescript-eslint/parser": "5.23.0",
97
+ "@vitejs/plugin-react": "1.3.2",
98
+ "@vitejs/plugin-vue": "2.3.3",
99
+ "esbuild": "0.14.42",
99
100
  "esbuild-runner": "2.2.1",
100
- "eslint": "^8.14.0",
101
+ "eslint": "8.15.0",
101
102
  "jest": "27.5.1",
102
103
  "jest-image-snapshot": "4.5.1",
103
104
  "playwright-chromium": "1.21.1",
@@ -107,9 +108,10 @@
107
108
  "rollup-plugin-dts": "^4.2.0",
108
109
  "rollup-plugin-esbuild": "4.9.1",
109
110
  "rxjs": "7.5.5",
111
+ "typescript": "^4.6.4",
110
112
  "vite": "^2.9.5",
111
113
  "vite-plugin-inspect": "0.5.0",
112
- "vue": "3.2.33"
114
+ "vue": "3.2.36"
113
115
  },
114
116
  "peerDependencies": {
115
117
  "vite": "^2.9.0"