@remix-run/assets 0.1.0 → 0.3.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 (72) hide show
  1. package/README.md +88 -67
  2. package/dist/lib/access.d.ts.map +1 -1
  3. package/dist/lib/access.js +3 -0
  4. package/dist/lib/asset-server.d.ts +50 -45
  5. package/dist/lib/asset-server.d.ts.map +1 -1
  6. package/dist/lib/asset-server.js +159 -50
  7. package/dist/lib/compilation-error.d.ts +2 -2
  8. package/dist/lib/compilation-error.d.ts.map +1 -1
  9. package/dist/lib/compilation-error.js +1 -1
  10. package/dist/lib/file-matcher.d.ts.map +1 -1
  11. package/dist/lib/file-matcher.js +3 -2
  12. package/dist/lib/injected-packages.d.ts +11 -0
  13. package/dist/lib/injected-packages.d.ts.map +1 -0
  14. package/dist/lib/injected-packages.js +86 -0
  15. package/dist/lib/module-store.d.ts +41 -0
  16. package/dist/lib/module-store.d.ts.map +1 -0
  17. package/dist/lib/{scripts/store.js → module-store.js} +43 -41
  18. package/dist/lib/paths.d.ts +1 -0
  19. package/dist/lib/paths.d.ts.map +1 -1
  20. package/dist/lib/paths.js +12 -0
  21. package/dist/lib/routes.d.ts +5 -7
  22. package/dist/lib/routes.d.ts.map +1 -1
  23. package/dist/lib/routes.js +13 -16
  24. package/dist/lib/scripts/compiler.d.ts +15 -15
  25. package/dist/lib/scripts/compiler.d.ts.map +1 -1
  26. package/dist/lib/scripts/compiler.js +50 -46
  27. package/dist/lib/scripts/emit.js +2 -2
  28. package/dist/lib/scripts/resolve.d.ts +7 -17
  29. package/dist/lib/scripts/resolve.d.ts.map +1 -1
  30. package/dist/lib/scripts/resolve.js +47 -14
  31. package/dist/lib/scripts/transform.d.ts +11 -9
  32. package/dist/lib/scripts/transform.d.ts.map +1 -1
  33. package/dist/lib/scripts/transform.js +110 -23
  34. package/dist/lib/source-maps.d.ts +1 -1
  35. package/dist/lib/source-maps.d.ts.map +1 -1
  36. package/dist/lib/source-maps.js +7 -1
  37. package/dist/lib/styles/compiler.d.ts +52 -0
  38. package/dist/lib/styles/compiler.d.ts.map +1 -0
  39. package/dist/lib/styles/compiler.js +272 -0
  40. package/dist/lib/styles/emit.d.ts +25 -0
  41. package/dist/lib/styles/emit.d.ts.map +1 -0
  42. package/dist/lib/styles/emit.js +78 -0
  43. package/dist/lib/styles/resolve.d.ts +48 -0
  44. package/dist/lib/styles/resolve.d.ts.map +1 -0
  45. package/dist/lib/styles/resolve.js +188 -0
  46. package/dist/lib/styles/transform.d.ts +47 -0
  47. package/dist/lib/styles/transform.d.ts.map +1 -0
  48. package/dist/lib/styles/transform.js +131 -0
  49. package/dist/lib/target.d.ts +21 -0
  50. package/dist/lib/target.d.ts.map +1 -0
  51. package/dist/lib/target.js +127 -0
  52. package/package.json +13 -4
  53. package/src/lib/access.ts +2 -0
  54. package/src/lib/asset-server.ts +239 -99
  55. package/src/lib/compilation-error.ts +7 -7
  56. package/src/lib/file-matcher.ts +3 -2
  57. package/src/lib/injected-packages.ts +117 -0
  58. package/src/lib/{scripts/store.ts → module-store.ts} +100 -87
  59. package/src/lib/paths.ts +28 -0
  60. package/src/lib/routes.ts +31 -22
  61. package/src/lib/scripts/compiler.ts +88 -70
  62. package/src/lib/scripts/emit.ts +2 -2
  63. package/src/lib/scripts/resolve.ts +85 -28
  64. package/src/lib/scripts/transform.ts +153 -36
  65. package/src/lib/source-maps.ts +8 -1
  66. package/src/lib/styles/compiler.ts +400 -0
  67. package/src/lib/styles/emit.ts +137 -0
  68. package/src/lib/styles/resolve.ts +316 -0
  69. package/src/lib/styles/transform.ts +226 -0
  70. package/src/lib/target.ts +196 -0
  71. package/dist/lib/scripts/store.d.ts +0 -40
  72. package/dist/lib/scripts/store.d.ts.map +0 -1
@@ -21,41 +21,50 @@ import {
21
21
  } from './resolve.ts'
22
22
  import type { ResolveArgs, ResolvedModule } from './resolve.ts'
23
23
  import type { CompiledRoutes } from '../routes.ts'
24
- import type { ScriptsTarget } from '../asset-server.ts'
25
- import { createModuleStore } from './store.ts'
26
- import type { FileSnapshot, ModuleRecord, ModuleSnapshot } from './store.ts'
24
+ import type { ResolvedScriptTarget } from '../target.ts'
25
+ import { createModuleStore } from '../module-store.ts'
26
+ import type {
27
+ FileSnapshot,
28
+ ModuleRecord,
29
+ ModuleSnapshot,
30
+ ModuleStore,
31
+ ModuleWatchEvent,
32
+ } from '../module-store.ts'
27
33
  import { createTsconfigTransformOptionsResolver, transformModule } from './transform.ts'
28
34
  import type { ResolveModuleResult, TransformArgs, TransformedModule } from './transform.ts'
29
35
  import { ResolverFactory } from 'oxc-resolver'
30
36
  import type { EmittedAsset, EmittedModule } from './emit.ts'
31
37
 
32
- type ModuleCompileResult = {
38
+ type ScriptRecord = ModuleRecord<TransformedModule, ResolvedModule, EmittedModule>
39
+ type ScriptStore = ModuleStore<TransformedModule, ResolvedModule, EmittedModule>
40
+
41
+ type ScriptCompileResult = {
33
42
  code: EmittedAsset
34
43
  fingerprint: string | null
35
44
  sourceMap: EmittedAsset | null
36
45
  }
37
46
 
38
- type ModuleGetResult =
47
+ type ScriptGetResult =
39
48
  | {
40
- type: 'module'
41
- module: ModuleCompileResult
49
+ script: ScriptCompileResult
50
+ type: 'script'
42
51
  }
43
52
  | {
44
53
  type: 'not-modified'
45
54
  etag: string
46
55
  }
47
56
 
48
- type ModuleGetOptions = {
57
+ type ScriptGetOptions = {
49
58
  ifNoneMatch: string | null
50
59
  isSourceMapRequest: boolean
51
60
  requestedFingerprint: string | null
52
61
  }
53
62
 
54
- type ModuleCompilerOptions = {
63
+ type ScriptCompilerOptions = {
55
64
  buildId?: string
56
65
  define?: Record<string, string>
57
66
  external: string[]
58
- fingerprintModules: boolean
67
+ fingerprintAssets: boolean
59
68
  isAllowed(absolutePath: string): boolean
60
69
  minify: boolean
61
70
  onWatchDirectoriesChange?: (delta: { add: string[]; remove: string[] }) => void
@@ -63,16 +72,14 @@ type ModuleCompilerOptions = {
63
72
  routes: CompiledRoutes
64
73
  sourceMapSourcePaths: 'absolute' | 'url'
65
74
  sourceMaps?: 'external' | 'inline'
66
- target?: ScriptsTarget
75
+ target?: ResolvedScriptTarget
67
76
  watchIgnore?: readonly string[]
68
77
  watchMode: boolean
69
78
  }
70
79
 
71
- type ModuleWatchEvent = 'add' | 'change' | 'unlink'
72
-
73
- type ModuleCompiler = {
74
- getModule(filePath: string, options: ModuleGetOptions): Promise<ModuleGetResult>
75
- getPreloadUrls(filePath: string | readonly string[]): Promise<string[]>
80
+ type ScriptCompiler = {
81
+ getScript(filePath: string, options: ScriptGetOptions): Promise<ScriptGetResult>
82
+ getPreloadLayers(filePath: string | readonly string[]): Promise<string[][]>
76
83
  getHref(filePath: string): Promise<string>
77
84
  handleFileEvent(filePath: string, event: ModuleWatchEvent): Promise<void>
78
85
  parseRequestPathname(pathname: string): ParsedRequestPathname | null
@@ -88,7 +95,7 @@ type ParsedRequestPathname = {
88
95
  const supportedScriptExtensionSet = new Set<string>(supportedScriptExtensions)
89
96
  const preloadConcurrency = Math.max(1, Math.min(8, os.availableParallelism() - 1))
90
97
 
91
- export function createModuleCompiler(options: ModuleCompilerOptions): ModuleCompiler {
98
+ export function createScriptCompiler(options: ScriptCompilerOptions): ScriptCompiler {
92
99
  let resolvedOptions = {
93
100
  ...options,
94
101
  externalSet: new Set(options.external),
@@ -96,7 +103,11 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
96
103
  createFileMatcher(pattern, options.rootDir),
97
104
  ),
98
105
  }
99
- let store = createModuleStore({
106
+ let scriptStore: ScriptStore = createModuleStore<
107
+ TransformedModule,
108
+ ResolvedModule,
109
+ EmittedModule
110
+ >({
100
111
  onWatchDirectoriesChange: options.onWatchDirectoriesChange,
101
112
  })
102
113
  let tsconfigTransformOptionsResolver = createTsconfigTransformOptionsResolver()
@@ -133,25 +144,25 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
133
144
  }
134
145
 
135
146
  return {
136
- async getModule(filePath, getOptions) {
137
- let resolvedModule = resolveServedModuleOrThrow(resolveInputFilePath(filePath))
138
- let record = store.get(resolvedModule.identityPath)
139
- let notModified = getNotModifiedModule(record, getOptions)
147
+ async getScript(filePath, getOptions) {
148
+ let resolvedModule = resolveServedScriptOrThrow(resolveInputFilePath(filePath))
149
+ let record = scriptStore.get(resolvedModule.identityPath)
150
+ let notModified = getNotModifiedScript(record, getOptions)
140
151
  if (notModified) return notModified
141
152
 
142
- let emitted = await getOrCreateEmittedModule(record)
153
+ let emitted = await getOrCreateEmittedScript(record)
143
154
  return {
144
- type: 'module',
145
- module: toModuleCompileResult(emitted),
155
+ script: toScriptCompileResult(emitted),
156
+ type: 'script',
146
157
  }
147
158
  },
148
159
 
149
- async getPreloadUrls(filePath) {
160
+ async getPreloadLayers(filePath) {
150
161
  let resolvedEntries: string[] = []
151
162
  let seen = new Set<string>()
152
163
 
153
164
  for (let resolvedModule of (Array.isArray(filePath) ? filePath : [filePath]).map((nextPath) =>
154
- resolveServedModuleOrThrow(resolveInputFilePath(nextPath)),
165
+ resolveServedScriptOrThrow(resolveInputFilePath(nextPath)),
155
166
  )) {
156
167
  if (seen.has(resolvedModule.identityPath)) continue
157
168
  seen.add(resolvedModule.identityPath)
@@ -160,17 +171,18 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
160
171
 
161
172
  let visited = new Set(resolvedEntries)
162
173
  let queue = [...resolvedEntries]
163
- let urls: string[] = []
174
+ let layers: string[][] = []
164
175
 
165
176
  while (queue.length > 0) {
166
177
  let frontier = queue
167
178
  queue = []
168
- let resolvedModules = await getOrCreateResolvedModules(
169
- frontier.map((identityPath) => store.get(identityPath)),
179
+ let resolvedModules = await getOrCreateResolvedScripts(
180
+ frontier.map((identityPath) => scriptStore.get(identityPath)),
170
181
  )
182
+ let layer: string[] = []
171
183
 
172
184
  for (let resolvedModule of resolvedModules) {
173
- urls.push(getServedUrlForResolvedModule(resolvedModule))
185
+ layer.push(getServedUrlForResolvedScript(resolvedModule))
174
186
 
175
187
  for (let dep of resolvedModule.deps) {
176
188
  if (visited.has(dep)) continue
@@ -178,13 +190,15 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
178
190
  queue.push(dep)
179
191
  }
180
192
  }
193
+
194
+ layers.push(layer)
181
195
  }
182
196
 
183
- return urls
197
+ return layers
184
198
  },
185
199
 
186
200
  async getHref(filePath) {
187
- let resolvedModule = resolveServedModuleOrThrow(resolveInputFilePath(filePath))
201
+ let resolvedModule = resolveServedScriptOrThrow(resolveInputFilePath(filePath))
188
202
  return getServedUrl(resolvedModule.identityPath)
189
203
  },
190
204
 
@@ -198,23 +212,23 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
198
212
 
199
213
  if (isTsconfigPath(normalizedFilePath)) {
200
214
  tsconfigTransformOptionsResolver.clear()
201
- store.invalidateAll()
215
+ scriptStore.invalidateAll()
202
216
  return
203
217
  }
204
218
 
205
219
  if (isPackageJsonPath(normalizedFilePath)) {
206
- store.invalidateAll()
220
+ scriptStore.invalidateAll()
207
221
  return
208
222
  }
209
223
 
210
- store.invalidateForFileEvent(normalizedFilePath, event)
224
+ scriptStore.invalidateForFileEvent(normalizedFilePath, event)
211
225
  },
212
226
 
213
227
  parseRequestPathname(pathname) {
214
228
  let parsedPathname = parseServedPathname(pathname)
215
229
  let filePath = resolvedOptions.routes.resolveUrlPathname(parsedPathname.stablePathname)
216
230
  if (!filePath) return null
217
- if (resolvedOptions.fingerprintModules && parsedPathname.requestedFingerprint === null)
231
+ if (resolvedOptions.fingerprintAssets && parsedPathname.requestedFingerprint === null)
218
232
  return null
219
233
 
220
234
  return {
@@ -238,19 +252,19 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
238
252
  return resolveFilePath(resolvedOptions.rootDir, filePath)
239
253
  }
240
254
 
241
- function resolveServedModuleOrThrow(absolutePath: string): ResolveModuleResult {
255
+ function resolveServedScriptOrThrow(absolutePath: string): ResolveModuleResult {
242
256
  let resolvedModule = resolveModulePath(absolutePath)
243
257
  if (!resolvedModule) {
244
- throw createAssetServerCompilationError(`Module not found: ${absolutePath}`, {
245
- code: 'MODULE_NOT_FOUND',
258
+ throw createAssetServerCompilationError(`File not found: ${absolutePath}`, {
259
+ code: 'FILE_NOT_FOUND',
246
260
  })
247
261
  }
248
262
 
249
263
  if (!resolvedOptions.isAllowed(resolvedModule.identityPath)) {
250
264
  throw createAssetServerCompilationError(
251
- `Module is not allowed: ${resolvedModule.identityPath}`,
265
+ `File is not allowed: ${resolvedModule.identityPath}`,
252
266
  {
253
- code: 'MODULE_NOT_ALLOWED',
267
+ code: 'FILE_NOT_ALLOWED',
254
268
  },
255
269
  )
256
270
  }
@@ -258,10 +272,10 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
258
272
  return resolvedModule
259
273
  }
260
274
 
261
- function getNotModifiedModule(
262
- record: ModuleRecord,
263
- options: ModuleGetOptions,
264
- ): ModuleGetResult | null {
275
+ function getNotModifiedScript(
276
+ record: ScriptRecord,
277
+ options: ScriptGetOptions,
278
+ ): ScriptGetResult | null {
265
279
  let current = getNotModifiedResult(record.emitted, options)
266
280
  if (current) return current
267
281
 
@@ -272,13 +286,13 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
272
286
  return getNotModifiedResult(record.staleEmitted, options)
273
287
  }
274
288
 
275
- async function getOrCreateResolvedModules(records: ModuleRecord[]): Promise<ResolvedModule[]> {
289
+ async function getOrCreateResolvedScripts(records: ScriptRecord[]): Promise<ResolvedModule[]> {
276
290
  return mapWithConcurrency(records, preloadConcurrency, (record) =>
277
- getOrCreateResolvedModule(record),
291
+ getOrCreateResolvedScript(record),
278
292
  )
279
293
  }
280
294
 
281
- async function getOrCreateResolvedModule(record: ModuleRecord): Promise<ResolvedModule> {
295
+ async function getOrCreateResolvedScript(record: ScriptRecord): Promise<ResolvedModule> {
282
296
  if (record.resolved) return record.resolved
283
297
 
284
298
  let cacheKey = getRecordCacheKey(record)
@@ -287,7 +301,7 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
287
301
 
288
302
  let promise = (async () => {
289
303
  let startedVersion = record.invalidationVersion
290
- let transformedModule = await getOrCreateTransformedModule(record)
304
+ let transformedModule = await getOrCreateTransformedScript(record)
291
305
  if (
292
306
  resolvedOptions.watchMode &&
293
307
  transformedModule.unresolvedImports.some((unresolved) =>
@@ -300,13 +314,15 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
300
314
 
301
315
  if (!resolveModuleResult.ok) {
302
316
  if (isFresh(record, startedVersion)) {
303
- store.setResolveFailure(record.identityPath, resolveModuleResult.tracking)
317
+ scriptStore.clearResolved(record.identityPath, [resolveModuleResult.tracking])
304
318
  }
305
319
  throw resolveModuleResult.error
306
320
  }
307
321
 
308
322
  if (isFresh(record, startedVersion)) {
309
- store.setResolved(record.identityPath, resolveModuleResult.value)
323
+ scriptStore.setResolved(record.identityPath, resolveModuleResult.value, [
324
+ resolveModuleResult.tracking,
325
+ ])
310
326
  }
311
327
 
312
328
  return resolveModuleResult.value
@@ -323,7 +339,7 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
323
339
  }
324
340
  }
325
341
 
326
- async function getOrCreateTransformedModule(record: ModuleRecord): Promise<TransformedModule> {
342
+ async function getOrCreateTransformedScript(record: ScriptRecord): Promise<TransformedModule> {
327
343
  if (record.transformed) return record.transformed
328
344
 
329
345
  let startedVersion = record.invalidationVersion
@@ -331,21 +347,21 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
331
347
 
332
348
  if (!transformModuleResult.ok) {
333
349
  if (isFresh(record, startedVersion)) {
334
- store.setTransformFailure(record.identityPath, {
335
- trackedFiles: transformModuleResult.trackedFiles,
336
- })
350
+ scriptStore.clearTransformed(record.identityPath, [transformModuleResult.tracking])
337
351
  }
338
352
  throw transformModuleResult.error
339
353
  }
340
354
 
341
355
  if (isFresh(record, startedVersion)) {
342
- store.setTransformed(record.identityPath, transformModuleResult.value)
356
+ scriptStore.setTransformed(record.identityPath, transformModuleResult.value, [
357
+ transformModuleResult.tracking,
358
+ ])
343
359
  }
344
360
 
345
361
  return transformModuleResult.value
346
362
  }
347
363
 
348
- async function getOrCreateEmittedModule(record: ModuleRecord): Promise<EmittedModule> {
364
+ async function getOrCreateEmittedScript(record: ScriptRecord): Promise<EmittedModule> {
349
365
  if (record.emitted) return record.emitted
350
366
 
351
367
  let cacheKey = getRecordCacheKey(record)
@@ -354,7 +370,7 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
354
370
 
355
371
  let promise = (async () => {
356
372
  let startedVersion = record.invalidationVersion
357
- let resolvedModule = await getOrCreateResolvedModule(record)
373
+ let resolvedModule = await getOrCreateResolvedScript(record)
358
374
  let emitResolvedModuleResult = await emitResolvedModule(resolvedModule, {
359
375
  getServedUrl,
360
376
  sourceMaps: resolvedOptions.sourceMaps,
@@ -365,7 +381,7 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
365
381
  }
366
382
 
367
383
  if (isFresh(record, startedVersion)) {
368
- store.setEmitted(
384
+ scriptStore.setEmitted(
369
385
  record.identityPath,
370
386
  emitResolvedModuleResult.value,
371
387
  createModuleSnapshot(resolvedModule.trackedFiles),
@@ -387,13 +403,15 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
387
403
  }
388
404
 
389
405
  async function getServedUrl(identityPath: string): Promise<string> {
390
- return getServedUrlForResolvedModule(await getOrCreateResolvedModule(store.get(identityPath)))
406
+ return getServedUrlForResolvedScript(
407
+ await getOrCreateResolvedScript(scriptStore.get(identityPath)),
408
+ )
391
409
  }
392
410
 
393
- function getServedUrlForResolvedModule(resolvedModule: ResolvedModule): string {
411
+ function getServedUrlForResolvedScript(resolvedModule: ResolvedModule): string {
394
412
  return formatFingerprintedPathname(
395
413
  resolvedModule.stableUrlPathname,
396
- resolvedOptions.fingerprintModules ? resolvedModule.fingerprint : null,
414
+ resolvedOptions.fingerprintAssets ? resolvedModule.fingerprint : null,
397
415
  )
398
416
  }
399
417
 
@@ -402,18 +420,18 @@ export function createModuleCompiler(options: ModuleCompilerOptions): ModuleComp
402
420
  }
403
421
  }
404
422
 
405
- function getRecordCacheKey(record: ModuleRecord): string {
423
+ function getRecordCacheKey(record: ScriptRecord): string {
406
424
  return `${record.identityPath}\0${record.invalidationVersion}`
407
425
  }
408
426
 
409
- function isFresh(record: ModuleRecord, version: number): boolean {
427
+ function isFresh(record: ScriptRecord, version: number): boolean {
410
428
  return record.invalidationVersion === version
411
429
  }
412
430
 
413
431
  function getNotModifiedResult(
414
432
  emittedModule: EmittedModule | undefined,
415
- options: ModuleGetOptions,
416
- ): ModuleGetResult | null {
433
+ options: ScriptGetOptions,
434
+ ): ScriptGetResult | null {
417
435
  if (!emittedModule || options.ifNoneMatch === null) return null
418
436
 
419
437
  if (
@@ -510,7 +528,7 @@ async function mapWithConcurrency<item, result>(
510
528
  return results
511
529
  }
512
530
 
513
- function toModuleCompileResult(emittedModule: EmittedModule): ModuleCompileResult {
531
+ function toScriptCompileResult(emittedModule: EmittedModule): ScriptCompileResult {
514
532
  return {
515
533
  code: emittedModule.code,
516
534
  fingerprint: emittedModule.fingerprint,
@@ -582,8 +600,8 @@ function isNoEntityError(
582
600
  )
583
601
  }
584
602
 
585
- export function createResponseForModule(
586
- result: ModuleCompileResult,
603
+ export function createResponseForScript(
604
+ result: ScriptCompileResult,
587
605
  options: {
588
606
  cacheControl: string
589
607
  ifNoneMatch: string | null
@@ -113,10 +113,10 @@ function toEmitError(error: unknown, identityPath: string): AssetServerCompilati
113
113
  if (isAssetServerCompilationError(error)) return error
114
114
 
115
115
  return createAssetServerCompilationError(
116
- `Failed to emit module ${identityPath}. ${error instanceof Error ? error.message : String(error)}`,
116
+ `Failed to emit script ${identityPath}. ${error instanceof Error ? error.message : String(error)}`,
117
117
  {
118
118
  cause: error,
119
- code: 'MODULE_EMIT_FAILED',
119
+ code: 'EMIT_FAILED',
120
120
  },
121
121
  )
122
122
  }
@@ -7,10 +7,18 @@ import {
7
7
  isAssetServerCompilationError,
8
8
  } from '../compilation-error.ts'
9
9
  import type { AssetServerCompilationError } from '../compilation-error.ts'
10
+ import {
11
+ getInjectedPackageNameForSpecifier,
12
+ getInjectedPackageImporterPath,
13
+ restoreAuthoredInjectedPackageSpecifier,
14
+ } from '../injected-packages.ts'
15
+ import type { ModuleRecord, ModuleTracking } from '../module-store.ts'
10
16
  import { normalizeFilePath } from '../paths.ts'
11
17
  import type { CompiledRoutes } from '../routes.ts'
12
- import type { ModuleRecord } from './store.ts'
13
18
  import type { ResolveModuleResult, TransformedModule } from './transform.ts'
19
+ import type { EmittedModule } from './emit.ts'
20
+
21
+ type ScriptRecord = ModuleRecord<TransformedModule, ResolvedModule, EmittedModule>
14
22
 
15
23
  export const resolverExtensionAlias = {
16
24
  '.js': ['.js', '.ts', '.tsx', '.jsx'],
@@ -35,7 +43,7 @@ type RelativeImportResolution = {
35
43
  specifier: string
36
44
  }
37
45
 
38
- export type TrackedResolution = RelativeImportResolution & {
46
+ type TrackedResolution = RelativeImportResolution & {
39
47
  resolvedIdentityPath: string | null
40
48
  }
41
49
 
@@ -45,19 +53,15 @@ export type ResolvedModule = {
45
53
  identityPath: string
46
54
  imports: ResolvedImport[]
47
55
  trackedFiles: string[]
48
- trackedResolutions: TrackedResolution[]
49
56
  rawCode: string
50
57
  resolvedPath: string
51
58
  sourceMap: string | null
52
59
  stableUrlPathname: string
53
60
  }
54
61
 
55
- export type ResolutionFailureState = {
56
- trackedFiles: readonly string[]
57
- trackedResolutions: readonly TrackedResolution[]
58
- }
59
-
60
- type ResolveResult =
62
+ type ResolveResult = {
63
+ tracking: ModuleTracking
64
+ } & (
61
65
  | {
62
66
  ok: true
63
67
  value: ResolvedModule
@@ -65,8 +69,8 @@ type ResolveResult =
65
69
  | {
66
70
  ok: false
67
71
  error: AssetServerCompilationError
68
- tracking: ResolutionFailureState
69
72
  }
73
+ )
70
74
 
71
75
  export type ResolveArgs = {
72
76
  isAllowed(absolutePath: string): boolean
@@ -82,8 +86,13 @@ type ResolvedSpec = {
82
86
  specifier: string
83
87
  }
84
88
 
89
+ type NormalizedSpecifierResolution = {
90
+ importerPath: string
91
+ specifier: string
92
+ }
93
+
85
94
  export async function resolveModule(
86
- record: ModuleRecord,
95
+ record: ScriptRecord,
87
96
  transformed: TransformedModule,
88
97
  args: ResolveArgs,
89
98
  ): Promise<ResolveResult> {
@@ -110,9 +119,10 @@ export async function resolveModule(
110
119
  let deps = new Set<string>()
111
120
 
112
121
  for (let unresolved of transformed.unresolvedImports) {
122
+ let displaySpecifier = getDisplayImportSpecifier(unresolved.specifier)
113
123
  let trackedResolution = getTrackedRelativeImportResolution(
114
124
  transformed.importerDir,
115
- unresolved.specifier,
125
+ displaySpecifier,
116
126
  args.isWatchIgnored,
117
127
  )
118
128
 
@@ -120,7 +130,7 @@ export async function resolveModule(
120
130
  if (!resolvedSpec?.absolutePath) {
121
131
  return failResolve(
122
132
  createAssetServerCompilationError(
123
- `Failed to resolve import "${unresolved.specifier}" in ${transformed.resolvedPath}. ` +
133
+ `Failed to resolve import "${displaySpecifier}" in ${transformed.resolvedPath}. ` +
124
134
  `Ensure it resolves to a file within the configured asset server fileMap, or mark it as external.`,
125
135
  {
126
136
  code: 'IMPORT_RESOLUTION_FAILED',
@@ -137,7 +147,7 @@ export async function resolveModule(
137
147
  if (!resolvedImport) {
138
148
  return failResolve(
139
149
  createAssetServerCompilationError(
140
- `Resolved import "${unresolved.specifier}" in ${transformed.resolvedPath} is not a supported script module. ` +
150
+ `Import "${displaySpecifier}" in ${transformed.resolvedPath}, resolved to "${resolvedSpec.absolutePath}", is not a supported script file. ` +
141
151
  `Supported extensions are ${supportedScriptExtensions.join(', ')}.`,
142
152
  {
143
153
  code: 'IMPORT_NOT_SUPPORTED',
@@ -153,8 +163,8 @@ export async function resolveModule(
153
163
  if (!args.isAllowed(resolvedImport.identityPath)) {
154
164
  return failResolve(
155
165
  createAssetServerCompilationError(
156
- `Resolved import "${unresolved.specifier}" in ${transformed.resolvedPath} is not allowed by the asset server allow/deny configuration. ` +
157
- `Add a matching allow rule, remove a conflicting deny rule, or mark this import as external.`,
166
+ `Import "${displaySpecifier}" in ${transformed.resolvedPath}, resolved to "${resolvedImport.identityPath}", is not allowed by the asset server allow/deny configuration. ` +
167
+ `Add a matching allow rule for this file path, remove a conflicting deny rule for this file path, or mark this import as external.`,
158
168
  {
159
169
  code: 'IMPORT_NOT_ALLOWED',
160
170
  },
@@ -170,7 +180,7 @@ export async function resolveModule(
170
180
  if (!stableUrlPathname) {
171
181
  return failResolve(
172
182
  createAssetServerCompilationError(
173
- `Resolved import "${unresolved.specifier}" in ${transformed.resolvedPath} is outside all configured fileMap entries. ` +
183
+ `Import "${displaySpecifier}" in ${transformed.resolvedPath}, resolved to "${resolvedImport.identityPath}", is outside all configured fileMap entries. ` +
174
184
  `Add a matching fileMap entry for this file path, or mark this import as external.`,
175
185
  {
176
186
  code: 'IMPORT_OUTSIDE_FILE_MAP',
@@ -210,13 +220,13 @@ export async function resolveModule(
210
220
 
211
221
  return {
212
222
  ok: true,
223
+ tracking: toResolveTracking(trackedFiles, trackedResolutions),
213
224
  value: {
214
225
  deps: [...deps],
215
226
  fingerprint: transformed.fingerprint,
216
227
  identityPath: record.identityPath,
217
228
  imports: importsWithPaths,
218
229
  trackedFiles: [...trackedFiles],
219
- trackedResolutions,
220
230
  rawCode: transformed.rawCode,
221
231
  resolvedPath: transformed.resolvedPath,
222
232
  sourceMap: transformed.sourceMap,
@@ -324,11 +334,17 @@ async function batchResolveSpecifiers(
324
334
 
325
335
  try {
326
336
  for (let specifier of specifiers) {
327
- let resolutionResult = await resolverFactory.resolveFileAsync(importerPath, specifier)
337
+ let normalizedResolution = normalizeSpecifierResolution(specifier, importerPath)
338
+ let resolutionResult = await resolverFactory.resolveFileAsync(
339
+ normalizedResolution.importerPath,
340
+ normalizedResolution.specifier,
341
+ )
328
342
  if (resolutionResult.error) {
329
343
  throw createAssetServerCompilationError(
330
- `Failed to resolve import "${specifier}" in ${importerPath}. ` +
331
- `Ensure it resolves to a file within the configured asset server fileMap, or mark it as external.`,
344
+ normalizedResolution.importerPath === getInjectedPackageImporterPath()
345
+ ? `Failed to resolve injected import "${specifier}" from asset server.`
346
+ : `Failed to resolve import "${normalizedResolution.specifier}" in ${normalizedResolution.importerPath}. ` +
347
+ `Ensure it resolves to a file within the configured asset server fileMap, or mark it as external.`,
332
348
  {
333
349
  code: 'IMPORT_RESOLUTION_FAILED',
334
350
  },
@@ -371,6 +387,35 @@ function formatUnknownError(error: unknown): string {
371
387
  return error instanceof Error ? error.message : String(error)
372
388
  }
373
389
 
390
+ function normalizeSpecifierResolution(
391
+ specifier: string,
392
+ importerPath: string,
393
+ ): NormalizedSpecifierResolution {
394
+ let authoredInjectedPackageSpecifier = restoreAuthoredInjectedPackageSpecifier(specifier)
395
+ if (authoredInjectedPackageSpecifier) {
396
+ return {
397
+ importerPath,
398
+ specifier: authoredInjectedPackageSpecifier,
399
+ }
400
+ }
401
+
402
+ if (getInjectedPackageNameForSpecifier(specifier)) {
403
+ return {
404
+ importerPath: getInjectedPackageImporterPath(),
405
+ specifier,
406
+ }
407
+ }
408
+
409
+ return {
410
+ importerPath,
411
+ specifier,
412
+ }
413
+ }
414
+
415
+ function getDisplayImportSpecifier(specifier: string): string {
416
+ return restoreAuthoredInjectedPackageSpecifier(specifier) ?? specifier
417
+ }
418
+
374
419
  function failResolve(
375
420
  error: unknown,
376
421
  trackedFiles: ReadonlySet<string>,
@@ -384,13 +429,25 @@ function failResolve(
384
429
  return {
385
430
  ok: false,
386
431
  error: toResolveError(error, importerPath),
387
- tracking: {
388
- trackedFiles: [...trackedFiles],
389
- trackedResolutions: appendFailedTrackedResolution(
390
- trackedResolutions,
391
- options.trackedResolution,
392
- ),
393
- },
432
+ tracking: toResolveTracking(
433
+ trackedFiles,
434
+ appendFailedTrackedResolution(trackedResolutions, options.trackedResolution),
435
+ ),
436
+ }
437
+ }
438
+
439
+ function toResolveTracking(
440
+ trackedFiles: ReadonlySet<string> | readonly string[],
441
+ trackedResolutions: readonly TrackedResolution[],
442
+ ): ModuleTracking {
443
+ return {
444
+ trackedFiles: [
445
+ ...trackedFiles,
446
+ ...trackedResolutions.flatMap((trackedResolution) => trackedResolution.candidatePaths),
447
+ ],
448
+ trackedDirectories: trackedResolutions.flatMap(
449
+ (trackedResolution) => trackedResolution.candidatePrefixes,
450
+ ),
394
451
  }
395
452
  }
396
453