@remix-run/assets 0.4.4 → 0.5.0

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 (74) hide show
  1. package/README.md +322 -56
  2. package/dist/assets.d.ts +2 -1
  3. package/dist/assets.d.ts.map +1 -1
  4. package/dist/assets.js +2 -2
  5. package/dist/lib/access.d.ts +6 -2
  6. package/dist/lib/access.d.ts.map +1 -1
  7. package/dist/lib/access.js +300 -5
  8. package/dist/lib/asset-server.d.ts +118 -5
  9. package/dist/lib/asset-server.d.ts.map +1 -1
  10. package/dist/lib/asset-server.js +260 -24
  11. package/dist/lib/compilation-error.d.ts +1 -1
  12. package/dist/lib/compilation-error.d.ts.map +1 -1
  13. package/dist/lib/file-matcher.js +1 -1
  14. package/dist/lib/files/compiler.d.ts.map +1 -1
  15. package/dist/lib/files/compiler.js +7 -6
  16. package/dist/lib/files/config.js +1 -1
  17. package/dist/lib/hmr.d.ts +37 -0
  18. package/dist/lib/hmr.d.ts.map +1 -0
  19. package/dist/lib/hmr.js +357 -0
  20. package/dist/lib/injected-packages.d.ts.map +1 -1
  21. package/dist/lib/injected-packages.js +36 -13
  22. package/dist/lib/loaders.d.ts +57 -0
  23. package/dist/lib/loaders.d.ts.map +1 -0
  24. package/dist/lib/loaders.js +1 -0
  25. package/dist/lib/module-store.d.ts +24 -0
  26. package/dist/lib/module-store.d.ts.map +1 -1
  27. package/dist/lib/module-store.js +136 -11
  28. package/dist/lib/routes.js +1 -1
  29. package/dist/lib/scripts/compiler.d.ts +24 -1
  30. package/dist/lib/scripts/compiler.d.ts.map +1 -1
  31. package/dist/lib/scripts/compiler.js +183 -29
  32. package/dist/lib/scripts/conditions.d.ts +2 -0
  33. package/dist/lib/scripts/conditions.d.ts.map +1 -0
  34. package/dist/lib/scripts/conditions.js +1 -0
  35. package/dist/lib/scripts/emit.d.ts +3 -0
  36. package/dist/lib/scripts/emit.d.ts.map +1 -1
  37. package/dist/lib/scripts/emit.js +24 -5
  38. package/dist/lib/scripts/resolve.d.ts +4 -0
  39. package/dist/lib/scripts/resolve.d.ts.map +1 -1
  40. package/dist/lib/scripts/resolve.js +70 -5
  41. package/dist/lib/scripts/transform.d.ts +9 -0
  42. package/dist/lib/scripts/transform.d.ts.map +1 -1
  43. package/dist/lib/scripts/transform.js +222 -18
  44. package/dist/lib/source-maps.js +1 -1
  45. package/dist/lib/styles/compiler.d.ts +14 -1
  46. package/dist/lib/styles/compiler.d.ts.map +1 -1
  47. package/dist/lib/styles/compiler.js +78 -14
  48. package/dist/lib/styles/emit.js +4 -4
  49. package/dist/lib/styles/resolve.d.ts.map +1 -1
  50. package/dist/lib/styles/resolve.js +8 -7
  51. package/dist/lib/styles/transform.js +3 -3
  52. package/dist/lib/target.d.ts +1 -1
  53. package/dist/lib/target.d.ts.map +1 -1
  54. package/dist/lib/watch.js +1 -1
  55. package/dist/types/hmr.d.ts +36 -0
  56. package/package.json +17 -11
  57. package/src/assets.ts +2 -1
  58. package/src/lib/access.ts +386 -5
  59. package/src/lib/asset-server.ts +429 -18
  60. package/src/lib/compilation-error.ts +1 -0
  61. package/src/lib/files/compiler.ts +7 -3
  62. package/src/lib/hmr.ts +397 -0
  63. package/src/lib/injected-packages.ts +41 -11
  64. package/src/lib/loaders.ts +80 -0
  65. package/src/lib/module-store.ts +190 -9
  66. package/src/lib/scripts/compiler.ts +248 -24
  67. package/src/lib/scripts/conditions.ts +1 -0
  68. package/src/lib/scripts/emit.ts +50 -5
  69. package/src/lib/scripts/resolve.ts +124 -2
  70. package/src/lib/scripts/transform.ts +290 -19
  71. package/src/lib/styles/compiler.ts +108 -8
  72. package/src/lib/styles/emit.ts +1 -1
  73. package/src/lib/styles/resolve.ts +11 -7
  74. package/src/types/hmr.d.ts +36 -0
@@ -1,8 +1,12 @@
1
- import { getFilePathDirectory } from "./paths.js";
1
+ import { getFilePathDirectory } from './paths.js';
2
2
  export function createModuleStore(options = {}) {
3
3
  let recordsByIdentityPath = new Map();
4
+ let importersByDepPath = new Map();
5
+ let acceptedImportersByDepPath = new Map();
4
6
  let recordsByTrackedFile = new Map();
5
7
  let watchDirectoryRefCountByPath = new Map();
8
+ let watchFileRefCountByPath = new Map();
9
+ let emptyImporters = new Set();
6
10
  return {
7
11
  get(identityPath) {
8
12
  let existing = recordsByIdentityPath.get(identityPath);
@@ -11,17 +15,46 @@ export function createModuleStore(options = {}) {
11
15
  let record = {
12
16
  identityPath,
13
17
  invalidationVersion: 0,
18
+ links: createEmptyLinks(),
14
19
  trackedFiles: new Set(),
15
20
  trackedDirectories: new Set(),
16
21
  };
17
22
  recordsByIdentityPath.set(identityPath, record);
18
23
  return record;
19
24
  },
25
+ getAcceptedImporters(identityPath) {
26
+ return acceptedImportersByDepPath.get(identityPath) ?? emptyImporters;
27
+ },
28
+ getHmrUpdateTimestamp(identityPath) {
29
+ return recordsByIdentityPath.get(identityPath)?.hmrUpdateTimestamp;
30
+ },
31
+ getImporters(identityPath) {
32
+ return importersByDepPath.get(identityPath) ?? emptyImporters;
33
+ },
34
+ getLastResolved(identityPath) {
35
+ return recordsByIdentityPath.get(identityPath)?.lastResolved;
36
+ },
37
+ isEmittedFresh(record) {
38
+ return record.emittedVersion === record.invalidationVersion;
39
+ },
40
+ isResolvedFresh(record) {
41
+ return record.resolvedVersion === record.invalidationVersion;
42
+ },
43
+ isTransformedFresh(record) {
44
+ return record.transformedVersion === record.invalidationVersion;
45
+ },
46
+ setHmrUpdateTimestamp(identityPath, timestamp) {
47
+ let record = getOrCreateMutableRecord(identityPath);
48
+ record.hmrUpdateTimestamp = timestamp;
49
+ },
20
50
  clearTransformed(identityPath, tracking) {
21
51
  let record = getOrCreateMutableRecord(identityPath);
22
52
  record.transformed = undefined;
53
+ record.transformedVersion = undefined;
23
54
  record.resolved = undefined;
55
+ record.resolvedVersion = undefined;
24
56
  record.emitted = undefined;
57
+ record.emittedVersion = undefined;
25
58
  record.emittedSnapshot = undefined;
26
59
  record.staleEmitted = undefined;
27
60
  record.staleEmittedSnapshot = undefined;
@@ -30,8 +63,11 @@ export function createModuleStore(options = {}) {
30
63
  setTransformed(identityPath, transformed, tracking) {
31
64
  let record = getOrCreateMutableRecord(identityPath);
32
65
  record.transformed = transformed;
66
+ record.transformedVersion = record.invalidationVersion;
33
67
  record.resolved = undefined;
68
+ record.resolvedVersion = undefined;
34
69
  record.emitted = undefined;
70
+ record.emittedVersion = undefined;
35
71
  record.emittedSnapshot = undefined;
36
72
  record.staleEmitted = undefined;
37
73
  record.staleEmittedSnapshot = undefined;
@@ -39,17 +75,25 @@ export function createModuleStore(options = {}) {
39
75
  },
40
76
  setResolved(identityPath, resolved, tracking) {
41
77
  let record = getOrCreateMutableRecord(identityPath);
78
+ removeResolvedIndexes(record);
42
79
  record.resolved = resolved;
80
+ record.resolvedVersion = record.invalidationVersion;
81
+ record.lastResolved = resolved;
82
+ record.links = createLinks(resolved);
43
83
  record.emitted = undefined;
84
+ record.emittedVersion = undefined;
44
85
  record.emittedSnapshot = undefined;
45
86
  record.staleEmitted = undefined;
46
87
  record.staleEmittedSnapshot = undefined;
47
88
  setTracking(record, tracking);
89
+ addResolvedIndexes(record);
48
90
  },
49
91
  clearResolved(identityPath, tracking) {
50
92
  let record = getOrCreateMutableRecord(identityPath);
51
93
  record.resolved = undefined;
94
+ record.resolvedVersion = undefined;
52
95
  record.emitted = undefined;
96
+ record.emittedVersion = undefined;
53
97
  record.emittedSnapshot = undefined;
54
98
  record.staleEmitted = undefined;
55
99
  record.staleEmittedSnapshot = undefined;
@@ -58,6 +102,7 @@ export function createModuleStore(options = {}) {
58
102
  setEmitted(identityPath, emitted, snapshot) {
59
103
  let record = getOrCreateMutableRecord(identityPath);
60
104
  record.emitted = emitted;
105
+ record.emittedVersion = record.invalidationVersion;
61
106
  record.emittedSnapshot = snapshot ?? undefined;
62
107
  record.staleEmitted = undefined;
63
108
  record.staleEmittedSnapshot = undefined;
@@ -73,19 +118,28 @@ export function createModuleStore(options = {}) {
73
118
  }
74
119
  for (let identityPath of affected) {
75
120
  let record = recordsByIdentityPath.get(identityPath);
76
- if (record)
77
- invalidateRecord(record, { retainStale: event === 'change' });
121
+ if (record) {
122
+ if (event === 'change') {
123
+ invalidateContent(record, { retainStale: true });
124
+ }
125
+ else {
126
+ invalidateGraph(record);
127
+ }
128
+ }
78
129
  }
79
130
  if (event === 'unlink') {
80
131
  let deletedRecord = recordsByIdentityPath.get(filePath);
81
132
  if (deletedRecord) {
133
+ if (!affected.has(filePath)) {
134
+ invalidateGraph(deletedRecord);
135
+ }
82
136
  clearTracking(deletedRecord);
83
137
  }
84
138
  }
85
139
  },
86
140
  invalidateAll() {
87
141
  for (let record of recordsByIdentityPath.values()) {
88
- invalidateRecord(record, { retainStale: false });
142
+ invalidateGraph(record);
89
143
  }
90
144
  },
91
145
  };
@@ -96,13 +150,14 @@ export function createModuleStore(options = {}) {
96
150
  let record = {
97
151
  identityPath,
98
152
  invalidationVersion: 0,
153
+ links: createEmptyLinks(),
99
154
  trackedFiles: new Set(),
100
155
  trackedDirectories: new Set(),
101
156
  };
102
157
  recordsByIdentityPath.set(identityPath, record);
103
158
  return record;
104
159
  }
105
- function invalidateRecord(record, options) {
160
+ function invalidateContent(record, options) {
106
161
  if (!options.retainStale) {
107
162
  record.staleEmitted = undefined;
108
163
  record.staleEmittedSnapshot = undefined;
@@ -115,14 +170,39 @@ export function createModuleStore(options = {}) {
115
170
  record.staleEmitted = undefined;
116
171
  record.staleEmittedSnapshot = undefined;
117
172
  }
118
- record.emitted = undefined;
119
- record.emittedSnapshot = undefined;
120
- record.resolved = undefined;
121
- record.transformed = undefined;
122
173
  record.invalidationVersion += 1;
123
174
  }
175
+ function invalidateGraph(record) {
176
+ record.hmrUpdateTimestamp = undefined;
177
+ invalidateContent(record, { retainStale: false });
178
+ }
179
+ function createLinks(resolved) {
180
+ return {
181
+ acceptedDependencies: new Set(options.getAcceptedDependencies?.(resolved) ?? []),
182
+ dependencies: new Set(options.getDependencies?.(resolved) ?? []),
183
+ };
184
+ }
185
+ function createEmptyLinks() {
186
+ return {
187
+ acceptedDependencies: new Set(),
188
+ dependencies: new Set(),
189
+ };
190
+ }
191
+ function addResolvedIndexes(record) {
192
+ for (let depPath of record.links.dependencies) {
193
+ addToIndexedSet(importersByDepPath, depPath, record.identityPath);
194
+ }
195
+ for (let depPath of record.links.acceptedDependencies) {
196
+ addToIndexedSet(acceptedImportersByDepPath, depPath, record.identityPath);
197
+ }
198
+ }
199
+ function removeResolvedIndexes(record) {
200
+ removeFromIndexedSets(importersByDepPath, record.identityPath);
201
+ removeFromIndexedSets(acceptedImportersByDepPath, record.identityPath);
202
+ }
124
203
  function setTracking(record, tracking) {
125
204
  let previousWatchedDirectories = getWatchedDirectories(record);
205
+ let previousWatchedFiles = new Set(record.trackedFiles);
126
206
  removeIndexes(record);
127
207
  let normalizedTracking = mergeTracking(tracking);
128
208
  record.trackedFiles = normalizedTracking.trackedFiles;
@@ -131,8 +211,10 @@ export function createModuleStore(options = {}) {
131
211
  addToIndexedSet(recordsByTrackedFile, trackedFile, record.identityPath);
132
212
  }
133
213
  let nextWatchedDirectories = getWatchedDirectories(record);
134
- let delta = updateWatchDirectoryRefCounts(previousWatchedDirectories, nextWatchedDirectories);
135
- emitWatchDirectoryDelta(delta);
214
+ let directoryDelta = updateWatchDirectoryRefCounts(previousWatchedDirectories, nextWatchedDirectories);
215
+ let fileDelta = updateWatchFileRefCounts(previousWatchedFiles, record.trackedFiles);
216
+ emitWatchDirectoryDelta(directoryDelta);
217
+ emitWatchFileDelta(fileDelta);
136
218
  }
137
219
  function clearTracking(record) {
138
220
  setTracking(record, []);
@@ -170,6 +252,34 @@ export function createModuleStore(options = {}) {
170
252
  }
171
253
  return { add, remove };
172
254
  }
255
+ function updateWatchFileRefCounts(previousWatchedFiles, nextWatchedFiles) {
256
+ let add = [];
257
+ let remove = [];
258
+ for (let file of previousWatchedFiles) {
259
+ if (nextWatchedFiles.has(file))
260
+ continue;
261
+ let previousCount = watchFileRefCountByPath.get(file);
262
+ if (!previousCount)
263
+ continue;
264
+ if (previousCount === 1) {
265
+ watchFileRefCountByPath.delete(file);
266
+ remove.push(file);
267
+ }
268
+ else {
269
+ watchFileRefCountByPath.set(file, previousCount - 1);
270
+ }
271
+ }
272
+ for (let file of nextWatchedFiles) {
273
+ if (previousWatchedFiles.has(file))
274
+ continue;
275
+ let previousCount = watchFileRefCountByPath.get(file) ?? 0;
276
+ watchFileRefCountByPath.set(file, previousCount + 1);
277
+ if (previousCount === 0) {
278
+ add.push(file);
279
+ }
280
+ }
281
+ return { add, remove };
282
+ }
173
283
  function emitWatchDirectoryDelta(delta) {
174
284
  if (!options.onWatchDirectoriesChange)
175
285
  return;
@@ -177,6 +287,13 @@ export function createModuleStore(options = {}) {
177
287
  return;
178
288
  options.onWatchDirectoriesChange(delta);
179
289
  }
290
+ function emitWatchFileDelta(delta) {
291
+ if (!options.onWatchFilesChange)
292
+ return;
293
+ if (delta.add.length === 0 && delta.remove.length === 0)
294
+ return;
295
+ options.onWatchFilesChange(delta);
296
+ }
180
297
  }
181
298
  function addToIndexedSet(map, key, value) {
182
299
  let existing = map.get(key) ?? new Set();
@@ -192,6 +309,14 @@ function removeFromIndexedSet(map, key, value) {
192
309
  map.delete(key);
193
310
  }
194
311
  }
312
+ function removeFromIndexedSets(map, value) {
313
+ for (let [key, values] of map) {
314
+ values.delete(value);
315
+ if (values.size === 0) {
316
+ map.delete(key);
317
+ }
318
+ }
319
+ }
195
320
  function matchesTrackedDirectory(trackedDirectories, filePath) {
196
321
  for (let trackedDirectory of trackedDirectories) {
197
322
  if (filePath === trackedDirectory || filePath.startsWith(`${trackedDirectory}/`))
@@ -1,7 +1,7 @@
1
1
  import { getRoutePatternCaptures, RoutePattern, } from '@remix-run/route-pattern';
2
2
  import { createHref } from '@remix-run/route-pattern/href';
3
3
  import { createMatcher } from '@remix-run/route-pattern/match';
4
- import { getRelativeFilePath, isAbsoluteFilePath, normalizeFilePath, normalizePathname, resolveFilePath, } from "./paths.js";
4
+ import { getRelativeFilePath, isAbsoluteFilePath, normalizeFilePath, normalizePathname, resolveFilePath, } from './paths.js';
5
5
  function normalizeFilePattern(pattern) {
6
6
  if (isAbsoluteFilePath(pattern)) {
7
7
  throw new Error(`File route patterns must be relative to the asset server root.\nPattern: ${pattern}`);
@@ -1,5 +1,6 @@
1
1
  import type { CompiledRoutes } from '../routes.ts';
2
2
  import type { ResolvedScriptTarget } from '../target.ts';
3
+ import type { ModuleLoader } from '../loaders.ts';
3
4
  import type { ModuleWatchEvent } from '../module-store.ts';
4
5
  import type { EmittedAsset } from './emit.ts';
5
6
  type ScriptCompileResult = {
@@ -24,12 +25,21 @@ type ScriptCompilerOptions = {
24
25
  define?: Record<string, string>;
25
26
  external: string[];
26
27
  fingerprintAssets: boolean;
28
+ hmr?: {
29
+ clientPathname: string;
30
+ send(updates: ScriptHmrUpdate[]): void;
31
+ };
27
32
  isAllowed(absolutePath: string): boolean;
28
33
  minify: boolean;
34
+ loaders: readonly ModuleLoader[];
29
35
  onWatchDirectoriesChange?: (delta: {
30
36
  add: string[];
31
37
  remove: string[];
32
38
  }) => void;
39
+ onWatchFilesChange?: (delta: {
40
+ add: string[];
41
+ remove: string[];
42
+ }) => void;
33
43
  rootDir: string;
34
44
  routes: CompiledRoutes;
35
45
  sourceMapSourcePaths: 'absolute' | 'url';
@@ -42,7 +52,8 @@ type ScriptCompiler = {
42
52
  getScript(filePath: string, options: ScriptGetOptions): Promise<ScriptGetResult>;
43
53
  getPreloadLayers(filePath: string | readonly string[]): Promise<string[][]>;
44
54
  getHref(filePath: string): Promise<string>;
45
- handleFileEvent(filePath: string, event: ModuleWatchEvent): Promise<void>;
55
+ classifyHmrFileEvent(filePath: string, event: ModuleWatchEvent): Promise<ScriptHmrUpdate[]>;
56
+ invalidateFileEvent(filePath: string, event: ModuleWatchEvent): void;
46
57
  parseRequestPathname(pathname: string): ParsedRequestPathname | null;
47
58
  };
48
59
  type ParsedRequestPathname = {
@@ -51,6 +62,18 @@ type ParsedRequestPathname = {
51
62
  isSourceMapRequest: boolean;
52
63
  requestedFingerprint: string | null;
53
64
  };
65
+ export type ScriptHmrUpdate = {
66
+ accepted: false;
67
+ filePath: string;
68
+ path: string;
69
+ timestamp: number;
70
+ } | {
71
+ accepted: true;
72
+ acceptedPath: string;
73
+ filePath: string;
74
+ path: string;
75
+ timestamp: number;
76
+ };
54
77
  export declare function createScriptCompiler(options: ScriptCompilerOptions): ScriptCompiler;
55
78
  export declare function createResponseForScript(result: ScriptCompileResult, options: {
56
79
  cacheControl: string;
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/compiler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/compiler.ts"],"names":[],"mappings":"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"}
@@ -3,14 +3,14 @@ import * as os from 'node:os';
3
3
  import * as path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import { IfNoneMatch } from '@remix-run/headers/if-none-match';
6
- import { createAssetServerCompilationError } from "../compilation-error.js";
7
- import { createFileMatcher } from "../file-matcher.js";
8
- import { formatFingerprintedPathname, getFingerprintRequestCacheControl, parseFingerprintSuffix, } from "../fingerprint.js";
9
- import { emitResolvedModule } from "./emit.js";
10
- import { normalizeFilePath, resolveFilePath } from "../paths.js";
11
- import { resolveModule, resolverExtensionAlias, resolverExtensions, supportedScriptExtensions, } from "./resolve.js";
12
- import { createModuleStore } from "../module-store.js";
13
- import { createTsconfigTransformOptionsResolver, transformModule } from "./transform.js";
6
+ import { createAssetServerCompilationError } from '../compilation-error.js';
7
+ import { createFileMatcher } from '../file-matcher.js';
8
+ import { formatFingerprintedPathname, getFingerprintRequestCacheControl, parseFingerprintSuffix, } from '../fingerprint.js';
9
+ import { emitResolvedModule } from './emit.js';
10
+ import { normalizeFilePath, resolveFilePath } from '../paths.js';
11
+ import { resolveModule, resolverExtensionAlias, resolverExtensions, supportedScriptExtensions, } from './resolve.js';
12
+ import { createModuleStore } from '../module-store.js';
13
+ import { createTsconfigTransformOptionsResolver, transformModule } from './transform.js';
14
14
  import { ResolverFactory } from 'oxc-resolver';
15
15
  const supportedScriptExtensionSet = new Set(supportedScriptExtensions);
16
16
  const preloadConcurrency = Math.max(1, Math.min(8, os.availableParallelism() - 1));
@@ -21,7 +21,14 @@ export function createScriptCompiler(options) {
21
21
  watchIgnoreMatchers: (options.watchIgnore ?? []).map((pattern) => createFileMatcher(pattern, options.rootDir)),
22
22
  };
23
23
  let scriptStore = createModuleStore({
24
+ getAcceptedDependencies(resolvedModule) {
25
+ return resolvedModule.hmr.acceptedDeps.map((acceptedDep) => acceptedDep.depPath);
26
+ },
27
+ getDependencies(resolvedModule) {
28
+ return resolvedModule.deps;
29
+ },
24
30
  onWatchDirectoriesChange: options.onWatchDirectoriesChange,
31
+ onWatchFilesChange: options.onWatchFilesChange,
25
32
  });
26
33
  let tsconfigTransformOptionsResolver = createTsconfigTransformOptionsResolver();
27
34
  let resolverFactory = new ResolverFactory({
@@ -40,6 +47,7 @@ export function createScriptCompiler(options) {
40
47
  externalSet: resolvedOptions.externalSet,
41
48
  isWatchIgnored,
42
49
  minify: resolvedOptions.minify,
50
+ loaders: resolvedOptions.loaders,
43
51
  resolveActualPath,
44
52
  routes: resolvedOptions.routes,
45
53
  sourceMapSourcePaths: resolvedOptions.sourceMapSourcePaths,
@@ -101,23 +109,27 @@ export function createScriptCompiler(options) {
101
109
  let resolvedModule = resolveServedScriptOrThrow(resolveInputFilePath(filePath));
102
110
  return getServedUrl(resolvedModule.identityPath);
103
111
  },
104
- async handleFileEvent(filePath, event) {
112
+ async classifyHmrFileEvent(filePath, event) {
105
113
  let normalizedFilePath = normalizeFilePath(filePath);
106
114
  if (isWatchIgnored(normalizedFilePath))
107
- return;
108
- if (shouldClearResolverCacheForFileEvent(normalizedFilePath, event)) {
109
- resolverFactory.clearCache();
110
- }
111
- if (isTsconfigPath(normalizedFilePath)) {
112
- tsconfigTransformOptionsResolver.clear();
113
- scriptStore.invalidateAll();
114
- return;
115
- }
116
- if (isPackageJsonPath(normalizedFilePath)) {
117
- scriptStore.invalidateAll();
118
- return;
115
+ return [];
116
+ let timestamp = Date.now();
117
+ let previousResolvedModule = scriptStore.getLastResolved(normalizedFilePath);
118
+ let updatePathname = previousResolvedModule?.stableUrlPathname;
119
+ invalidateScriptFileEvent(normalizedFilePath, event);
120
+ let resolvedModule = event === 'change' && updatePathname
121
+ ? await tryGetOrCreateResolvedScript(scriptStore.get(normalizedFilePath))
122
+ : undefined;
123
+ let hmrUpdate = event === 'change' && updatePathname
124
+ ? getHmrUpdatesForChange(resolvedModule ?? previousResolvedModule, previousResolvedModule, updatePathname, timestamp)
125
+ : [];
126
+ if (hmrUpdate.length > 0) {
127
+ resolvedOptions.hmr?.send(hmrUpdate);
119
128
  }
120
- scriptStore.invalidateForFileEvent(normalizedFilePath, event);
129
+ return hmrUpdate;
130
+ },
131
+ invalidateFileEvent(filePath, event) {
132
+ invalidateScriptFileEvent(normalizeFilePath(filePath), event);
121
133
  },
122
134
  parseRequestPathname(pathname) {
123
135
  let parsedPathname = parseServedPathname(pathname);
@@ -143,6 +155,23 @@ export function createScriptCompiler(options) {
143
155
  }
144
156
  return resolveFilePath(resolvedOptions.rootDir, filePath);
145
157
  }
158
+ function invalidateScriptFileEvent(normalizedFilePath, event) {
159
+ if (isWatchIgnored(normalizedFilePath))
160
+ return;
161
+ if (shouldClearResolverCacheForFileEvent(normalizedFilePath, event)) {
162
+ resolverFactory.clearCache();
163
+ }
164
+ if (isTsconfigPath(normalizedFilePath)) {
165
+ tsconfigTransformOptionsResolver.clear();
166
+ scriptStore.invalidateAll();
167
+ return;
168
+ }
169
+ if (isPackageJsonPath(normalizedFilePath)) {
170
+ scriptStore.invalidateAll();
171
+ return;
172
+ }
173
+ scriptStore.invalidateForFileEvent(normalizedFilePath, event);
174
+ }
146
175
  function resolveServedScriptOrThrow(absolutePath) {
147
176
  let resolvedModule = resolveModulePath(absolutePath);
148
177
  if (!resolvedModule) {
@@ -151,16 +180,22 @@ export function createScriptCompiler(options) {
151
180
  });
152
181
  }
153
182
  if (!resolvedOptions.isAllowed(resolvedModule.identityPath)) {
154
- throw createAssetServerCompilationError(`File is not allowed: ${resolvedModule.identityPath}`, {
183
+ throw createAssetServerCompilationError(`File "${resolvedModule.identityPath}" is not allowed by the asset server access configuration. ` +
184
+ `Add a matching allowFiles or allowPackages rule, or remove a conflicting denyFiles rule.`, {
155
185
  code: 'FILE_NOT_ALLOWED',
156
186
  });
157
187
  }
158
188
  return resolvedModule;
159
189
  }
160
190
  function getNotModifiedScript(record, options) {
161
- let current = getNotModifiedResult(record.emitted, options);
162
- if (current)
163
- return current;
191
+ if (hasHmrTimestampedDependency(record.resolved)) {
192
+ return null;
193
+ }
194
+ if (scriptStore.isEmittedFresh(record)) {
195
+ let current = getNotModifiedResult(record.emitted, options);
196
+ if (current)
197
+ return current;
198
+ }
164
199
  if (!record.staleEmittedSnapshot || !isModuleSnapshotFresh(record.staleEmittedSnapshot)) {
165
200
  return null;
166
201
  }
@@ -170,7 +205,7 @@ export function createScriptCompiler(options) {
170
205
  return mapWithConcurrency(records, preloadConcurrency, (record) => getOrCreateResolvedScript(record));
171
206
  }
172
207
  async function getOrCreateResolvedScript(record) {
173
- if (record.resolved)
208
+ if (record.resolved && scriptStore.isResolvedFresh(record))
174
209
  return record.resolved;
175
210
  let cacheKey = getRecordCacheKey(record);
176
211
  let existing = resolveInFlightByCacheKey.get(cacheKey);
@@ -207,8 +242,16 @@ export function createScriptCompiler(options) {
207
242
  }
208
243
  }
209
244
  }
245
+ async function tryGetOrCreateResolvedScript(record) {
246
+ try {
247
+ return await getOrCreateResolvedScript(record);
248
+ }
249
+ catch {
250
+ return undefined;
251
+ }
252
+ }
210
253
  async function getOrCreateTransformedScript(record) {
211
- if (record.transformed)
254
+ if (record.transformed && scriptStore.isTransformedFresh(record))
212
255
  return record.transformed;
213
256
  let startedVersion = record.invalidationVersion;
214
257
  let transformModuleResult = await transformModule(record, transformArgs);
@@ -226,8 +269,11 @@ export function createScriptCompiler(options) {
226
269
  return transformModuleResult.value;
227
270
  }
228
271
  async function getOrCreateEmittedScript(record) {
229
- if (record.emitted)
272
+ if (record.emitted &&
273
+ scriptStore.isEmittedFresh(record) &&
274
+ !hasHmrTimestampedDependency(record.resolved)) {
230
275
  return record.emitted;
276
+ }
231
277
  let cacheKey = getRecordCacheKey(record);
232
278
  let existing = emitInFlightByCacheKey.get(cacheKey);
233
279
  if (existing)
@@ -237,6 +283,9 @@ export function createScriptCompiler(options) {
237
283
  let resolvedModule = await getOrCreateResolvedScript(record);
238
284
  let emitResolvedModuleResult = await emitResolvedModule(resolvedModule, {
239
285
  getServedUrl,
286
+ getStableUrl,
287
+ getHmrImportTimestamp,
288
+ hmrClientPathname: resolvedOptions.hmr?.clientPathname,
240
289
  sourceMaps: resolvedOptions.sourceMaps,
241
290
  });
242
291
  if (!emitResolvedModuleResult.ok) {
@@ -263,10 +312,115 @@ export function createScriptCompiler(options) {
263
312
  function getServedUrlForResolvedScript(resolvedModule) {
264
313
  return formatFingerprintedPathname(resolvedModule.stableUrlPathname, resolvedOptions.fingerprintAssets ? resolvedModule.fingerprint : null);
265
314
  }
315
+ function getStableUrl(identityPath) {
316
+ let stableUrlPathname = resolvedOptions.routes.toUrlPathname(identityPath);
317
+ if (!stableUrlPathname) {
318
+ throw createAssetServerCompilationError(`File ${identityPath} is outside all configured fileMap entries.`, {
319
+ code: 'FILE_OUTSIDE_FILE_MAP',
320
+ });
321
+ }
322
+ return stableUrlPathname;
323
+ }
324
+ function getHmrImportTimestamp(identityPath) {
325
+ return scriptStore.getHmrUpdateTimestamp(identityPath) ?? null;
326
+ }
327
+ function hasHmrTimestampedDependency(resolvedModule) {
328
+ return resolvedModule?.deps.some((depPath) => getHmrImportTimestamp(depPath) !== null) === true;
329
+ }
330
+ function getHmrUpdatesForChange(resolvedModule, previousResolvedModule, updatePathname, timestamp) {
331
+ if (resolvedModule) {
332
+ scriptStore.setHmrUpdateTimestamp(resolvedModule.identityPath, timestamp);
333
+ }
334
+ if (resolvedModule?.hmr.selfAccepting === true) {
335
+ return [
336
+ {
337
+ accepted: true,
338
+ acceptedPath: updatePathname,
339
+ filePath: resolvedModule.identityPath,
340
+ path: updatePathname,
341
+ timestamp,
342
+ },
343
+ ];
344
+ }
345
+ let sourceFilePath = resolvedModule?.identityPath;
346
+ let boundaries = findHmrBoundaries(sourceFilePath);
347
+ if (sourceFilePath !== undefined && boundaries) {
348
+ return dedupeHmrBoundaries(boundaries).map(({ acceptedModule, boundaryModule }) => ({
349
+ accepted: true,
350
+ acceptedPath: acceptedModule.stableUrlPathname,
351
+ filePath: sourceFilePath,
352
+ path: boundaryModule.stableUrlPathname,
353
+ timestamp,
354
+ }));
355
+ }
356
+ return [
357
+ {
358
+ accepted: false,
359
+ filePath: resolvedModule?.identityPath ?? previousResolvedModule?.identityPath ?? updatePathname,
360
+ path: updatePathname,
361
+ timestamp,
362
+ },
363
+ ];
364
+ }
365
+ function findHmrBoundaries(identityPath) {
366
+ if (identityPath === undefined)
367
+ return null;
368
+ return propagateHmrUpdate(identityPath, new Set());
369
+ }
370
+ function propagateHmrUpdate(identityPath, traversed) {
371
+ if (traversed.has(identityPath))
372
+ return [];
373
+ traversed.add(identityPath);
374
+ let resolvedModule = scriptStore.getLastResolved(identityPath);
375
+ if (!resolvedModule)
376
+ return null;
377
+ if (resolvedModule.hmr.selfAccepting) {
378
+ return [
379
+ {
380
+ acceptedModule: resolvedModule,
381
+ boundaryModule: resolvedModule,
382
+ },
383
+ ];
384
+ }
385
+ let importerPaths = scriptStore.getImporters(identityPath);
386
+ if (!importerPaths || importerPaths.size === 0)
387
+ return null;
388
+ let acceptedImporterPaths = scriptStore.getAcceptedImporters(identityPath);
389
+ let boundaries = [];
390
+ for (let importerPath of importerPaths) {
391
+ let importer = scriptStore.getLastResolved(importerPath);
392
+ if (!importer)
393
+ return null;
394
+ if (acceptedImporterPaths?.has(importerPath)) {
395
+ boundaries.push({
396
+ acceptedModule: resolvedModule,
397
+ boundaryModule: importer,
398
+ });
399
+ continue;
400
+ }
401
+ let importerBoundaries = propagateHmrUpdate(importerPath, traversed);
402
+ if (!importerBoundaries)
403
+ return null;
404
+ boundaries.push(...importerBoundaries);
405
+ }
406
+ return boundaries;
407
+ }
266
408
  function isWatchIgnored(filePath) {
267
409
  return resolvedOptions.watchIgnoreMatchers.some((matcher) => matcher(filePath));
268
410
  }
269
411
  }
412
+ function dedupeHmrBoundaries(boundaries) {
413
+ let seen = new Set();
414
+ let result = [];
415
+ for (let boundary of boundaries) {
416
+ let key = `${boundary.boundaryModule.identityPath}\0${boundary.acceptedModule.identityPath}`;
417
+ if (seen.has(key))
418
+ continue;
419
+ seen.add(key);
420
+ result.push(boundary);
421
+ }
422
+ return result;
423
+ }
270
424
  function getRecordCacheKey(record) {
271
425
  return `${record.identityPath}\0${record.invalidationVersion}`;
272
426
  }
@@ -0,0 +1,2 @@
1
+ export declare const scriptLoaderConditions: readonly ['browser', 'import', 'module', 'default'];
2
+ //# sourceMappingURL=conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/conditions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,YAAI,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAU,CAAA"}
@@ -0,0 +1 @@
1
+ export const scriptLoaderConditions = ['browser', 'import', 'module', 'default'];