@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
@@ -2,10 +2,13 @@ import * as fs from 'node:fs'
2
2
  import * as fsp from 'node:fs/promises'
3
3
  import * as path from 'node:path'
4
4
  import { getTsconfig } from 'get-tsconfig'
5
+ import MagicString from 'magic-string'
5
6
  import { minify } from 'oxc-minify'
7
+ import { parseSync, visitorKeys } from 'oxc-parser'
6
8
  import { transform as oxcTransform } from 'oxc-transform'
7
9
  import { init as esModuleLexerInit, parse as esModuleLexer } from 'es-module-lexer'
8
10
  import type { Cache, TsConfigJsonResolved } from 'get-tsconfig'
11
+ import type { Node, Program } from 'oxc-parser'
9
12
  import type { TransformOptions as OxcTransformOptions } from 'oxc-transform'
10
13
 
11
14
  import { isCommonJS, mayContainCommonJSModuleGlobals } from './cjs-check.ts'
@@ -15,11 +18,20 @@ import {
15
18
  } from '../compilation-error.ts'
16
19
  import type { AssetServerCompilationError } from '../compilation-error.ts'
17
20
  import { generateFingerprint } from '../fingerprint.ts'
21
+ import {
22
+ maskAuthoredInjectedPackageSpecifier,
23
+ mayContainInjectedPackageSpecifier,
24
+ restoreAuthoredInjectedPackageSpecifier,
25
+ } from '../injected-packages.ts'
26
+ import type { ModuleRecord, ModuleTracking } from '../module-store.ts'
18
27
  import { normalizeFilePath } from '../paths.ts'
19
28
  import type { CompiledRoutes } from '../routes.ts'
20
- import type { ScriptsTarget } from '../asset-server.ts'
21
- import type { ModuleRecord } from './store.ts'
22
29
  import { composeSourceMaps, rewriteSourceMapSources, stringifySourceMap } from '../source-maps.ts'
30
+ import type { EmittedModule } from './emit.ts'
31
+ import type { ResolvedScriptTarget } from '../target.ts'
32
+ import type { ResolvedModule } from './resolve.ts'
33
+
34
+ type ScriptRecord = ModuleRecord<TransformedModule, ResolvedModule, EmittedModule>
23
35
 
24
36
  type SourceLanguage = 'js' | 'jsx' | 'ts' | 'tsx'
25
37
 
@@ -72,19 +84,18 @@ export type TransformedModule = {
72
84
  unresolvedImports: UnresolvedImport[]
73
85
  }
74
86
 
75
- export type TransformFailureState = {
76
- trackedFiles: readonly string[]
77
- }
78
-
79
- type TransformResult =
87
+ type TransformResult = {
88
+ tracking: ModuleTracking
89
+ } & (
80
90
  | {
81
91
  ok: true
82
92
  value: TransformedModule
83
93
  }
84
- | ({
94
+ | {
85
95
  ok: false
86
96
  error: AssetServerCompilationError
87
- } & TransformFailureState)
97
+ }
98
+ )
88
99
 
89
100
  type TsconfigTransformOptions = {
90
101
  trackedFiles: string[]
@@ -103,7 +114,7 @@ export type TransformArgs = {
103
114
  routes: CompiledRoutes
104
115
  sourceMapSourcePaths: 'absolute' | 'url'
105
116
  sourceMaps: 'external' | 'inline' | null
106
- target: ScriptsTarget | null
117
+ target: ResolvedScriptTarget | null
107
118
  tsconfigTransformOptionsResolver: TsconfigTransformOptionsResolver
108
119
  }
109
120
 
@@ -144,17 +155,19 @@ export function createTsconfigTransformOptionsResolver() {
144
155
  }
145
156
 
146
157
  export async function transformModule(
147
- record: ModuleRecord,
158
+ record: ScriptRecord,
148
159
  args: TransformArgs,
149
160
  ): Promise<TransformResult> {
150
161
  let resolvedPath = args.resolveActualPath(record.identityPath)
151
162
  if (!resolvedPath) {
152
163
  return {
153
164
  ok: false,
154
- error: createAssetServerCompilationError(`Module not found: ${record.identityPath}`, {
155
- code: 'MODULE_NOT_FOUND',
165
+ error: createAssetServerCompilationError(`File not found: ${record.identityPath}`, {
166
+ code: 'FILE_NOT_FOUND',
156
167
  }),
157
- trackedFiles: args.isWatchIgnored(record.identityPath) ? [] : [record.identityPath],
168
+ tracking: {
169
+ trackedFiles: args.isWatchIgnored(record.identityPath) ? [] : [record.identityPath],
170
+ },
158
171
  }
159
172
  }
160
173
 
@@ -173,17 +186,21 @@ export async function transformModule(
173
186
  if (isNoEntityError(error)) {
174
187
  return {
175
188
  ok: false,
176
- error: createAssetServerCompilationError(`Module not found: ${resolvedPath}`, {
189
+ error: createAssetServerCompilationError(`File not found: ${resolvedPath}`, {
177
190
  cause: error,
178
- code: 'MODULE_NOT_FOUND',
191
+ code: 'FILE_NOT_FOUND',
179
192
  }),
180
- trackedFiles,
193
+ tracking: {
194
+ trackedFiles,
195
+ },
181
196
  }
182
197
  }
183
198
  return {
184
199
  ok: false,
185
200
  error: toTransformFailedError(error, resolvedPath),
186
- trackedFiles,
201
+ tracking: {
202
+ trackedFiles,
203
+ },
187
204
  }
188
205
  }
189
206
 
@@ -196,7 +213,7 @@ export async function transformModule(
196
213
  })
197
214
 
198
215
  analysis.unresolvedImports = analysis.unresolvedImports.filter(
199
- (unresolved) => !args.externalSet.has(unresolved.specifier),
216
+ (unresolved) => !args.externalSet.has(getDisplayImportSpecifier(unresolved.specifier)),
200
217
  )
201
218
 
202
219
  if (mayContainCommonJSModuleGlobals(sourceText) && isCommonJS(analysis.rawCode)) {
@@ -205,7 +222,7 @@ export async function transformModule(
205
222
  `This module uses CommonJS (require/module.exports) which is not supported. ` +
206
223
  `Please use an ESM-compatible module.`,
207
224
  {
208
- code: 'MODULE_COMMONJS_NOT_SUPPORTED',
225
+ code: 'COMMONJS_NOT_SUPPORTED',
209
226
  },
210
227
  )
211
228
  }
@@ -213,9 +230,9 @@ export async function transformModule(
213
230
  let stableUrlPathname = args.routes.toUrlPathname(record.identityPath)
214
231
  if (!stableUrlPathname) {
215
232
  throw createAssetServerCompilationError(
216
- `Module ${record.identityPath} is outside all configured fileMap entries.`,
233
+ `File ${record.identityPath} is outside all configured fileMap entries.`,
217
234
  {
218
- code: 'MODULE_OUTSIDE_FILE_MAP',
235
+ code: 'FILE_OUTSIDE_FILE_MAP',
219
236
  },
220
237
  )
221
238
  }
@@ -226,11 +243,15 @@ export async function transformModule(
226
243
  resolvedPath,
227
244
  stableUrlPathname,
228
245
  args.sourceMapSourcePaths,
246
+ sourceText,
229
247
  )
230
248
  : null
231
249
 
232
250
  return {
233
251
  ok: true,
252
+ tracking: {
253
+ trackedFiles,
254
+ },
234
255
  value: {
235
256
  fingerprint:
236
257
  args.buildId === null
@@ -256,7 +277,9 @@ export async function transformModule(
256
277
  return {
257
278
  ok: false,
258
279
  error: toTransformFailedError(error, resolvedPath),
259
- trackedFiles,
280
+ tracking: {
281
+ trackedFiles,
282
+ },
260
283
  }
261
284
  }
262
285
  }
@@ -288,24 +311,25 @@ async function analyzeModuleSource(
288
311
  define?: Record<string, string>
289
312
  minify: boolean
290
313
  sourceMaps?: 'external' | 'inline'
291
- target?: ScriptsTarget
314
+ target?: ResolvedScriptTarget
292
315
  },
293
316
  ) {
317
+ let maskedSourceText = maskAuthoredInjectedPackageImports(sourceText, resolvedPath)
294
318
  let transformResult: { code: string; errors?: Array<{ message?: string }>; map?: unknown }
295
319
  try {
296
320
  transformResult = await oxcTransform(
297
321
  resolvedPath,
298
- sourceText,
322
+ maskedSourceText,
299
323
  getTransformOptions(resolvedPath, transformOptions, options),
300
324
  )
301
325
  assertNoCompilerErrors(transformResult.errors, resolvedPath, 'transform')
302
326
  } catch (error) {
303
327
  if (isAssetServerCompilationError(error)) throw error
304
328
  throw createAssetServerCompilationError(
305
- `Failed to transform module ${resolvedPath}. ${formatUnknownError(error)}`,
329
+ `Failed to transform script ${resolvedPath}. ${formatUnknownError(error)}`,
306
330
  {
307
331
  cause: error,
308
- code: 'MODULE_TRANSFORM_FAILED',
332
+ code: 'TRANSFORM_FAILED',
309
333
  },
310
334
  )
311
335
  }
@@ -335,7 +359,7 @@ async function analyzeModuleSource(
335
359
  async function minifyModule(
336
360
  rawCode: string,
337
361
  resolvedPath: string,
338
- target: string | undefined,
362
+ target: ResolvedScriptTarget | undefined,
339
363
  sourceMaps?: 'external' | 'inline',
340
364
  ) {
341
365
  try {
@@ -350,10 +374,10 @@ async function minifyModule(
350
374
  } catch (error) {
351
375
  if (isAssetServerCompilationError(error)) throw error
352
376
  throw createAssetServerCompilationError(
353
- `Failed to minify module ${resolvedPath}. ${formatUnknownError(error)}`,
377
+ `Failed to minify script ${resolvedPath}. ${formatUnknownError(error)}`,
354
378
  {
355
379
  cause: error,
356
- code: 'MODULE_TRANSFORM_FAILED',
380
+ code: 'TRANSFORM_FAILED',
357
381
  },
358
382
  )
359
383
  }
@@ -365,7 +389,7 @@ function getTransformOptions(
365
389
  options: {
366
390
  define?: Record<string, string>
367
391
  sourceMaps?: 'external' | 'inline'
368
- target?: string
392
+ target?: ResolvedScriptTarget
369
393
  },
370
394
  ): OxcTransformOptions {
371
395
  let compilerOptions = transformOptions.tsconfigRaw?.compilerOptions as
@@ -436,7 +460,7 @@ function getJsxOptions(
436
460
  `Unsupported tsconfig compilerOptions.jsx = "${jsx}" for ${resolvedPath}. ` +
437
461
  `Asset server must compile JSX to browser-runnable JavaScript.`,
438
462
  {
439
- code: 'MODULE_TRANSFORM_FAILED',
463
+ code: 'TRANSFORM_FAILED',
440
464
  },
441
465
  )
442
466
  }
@@ -500,9 +524,9 @@ function assertNoCompilerErrors(
500
524
  if (!errors || errors.length === 0) return
501
525
 
502
526
  throw createAssetServerCompilationError(
503
- `Failed to ${operation} module ${resolvedPath}. ${errors[0].message ?? 'Unknown error'}`,
527
+ `Failed to ${operation} script ${resolvedPath}. ${errors[0].message ?? 'Unknown error'}`,
504
528
  {
505
- code: 'MODULE_TRANSFORM_FAILED',
529
+ code: 'TRANSFORM_FAILED',
506
530
  },
507
531
  )
508
532
  }
@@ -526,6 +550,99 @@ async function getUnresolvedImportsFromLexer(rawCode: string): Promise<Unresolve
526
550
  return unresolvedImports
527
551
  }
528
552
 
553
+ function getDisplayImportSpecifier(specifier: string): string {
554
+ return restoreAuthoredInjectedPackageSpecifier(specifier) ?? specifier
555
+ }
556
+
557
+ function maskAuthoredInjectedPackageImports(sourceText: string, resolvedPath: string): string {
558
+ if (!mayContainInjectedPackageSpecifier(sourceText)) {
559
+ return sourceText
560
+ }
561
+
562
+ let parseResult = parseSync(resolvedPath, sourceText, {
563
+ lang: getSourceLanguageForPath(resolvedPath),
564
+ sourceType: 'module',
565
+ })
566
+ if (parseResult.errors.length > 0) {
567
+ return sourceText
568
+ }
569
+
570
+ let replacements: Array<{ end: number; specifier: string; start: number }> = []
571
+
572
+ walkAst(parseResult.program, (node) => {
573
+ if (
574
+ node.type !== 'ImportDeclaration' &&
575
+ node.type !== 'ExportAllDeclaration' &&
576
+ node.type !== 'ExportNamedDeclaration' &&
577
+ node.type !== 'ImportExpression'
578
+ ) {
579
+ return
580
+ }
581
+
582
+ let source = 'source' in node ? node.source : null
583
+ if (!isStringLiteralNode(source)) return
584
+
585
+ let maskedSpecifier = maskAuthoredInjectedPackageSpecifier(source.value)
586
+ if (maskedSpecifier == null) return
587
+
588
+ replacements.push({
589
+ end: source.end - 1,
590
+ specifier: maskedSpecifier,
591
+ start: source.start + 1,
592
+ })
593
+ })
594
+
595
+ if (replacements.length === 0) return sourceText
596
+
597
+ let rewrittenSource = new MagicString(sourceText)
598
+ for (let replacement of replacements) {
599
+ rewrittenSource.overwrite(replacement.start, replacement.end, replacement.specifier)
600
+ }
601
+
602
+ return rewrittenSource.toString()
603
+ }
604
+
605
+ function walkAst(node: Program | Node, visit: (node: Program | Node) => void): void {
606
+ visit(node)
607
+
608
+ let keys = visitorKeys[node.type]
609
+ if (!keys) return
610
+
611
+ let walkableNode = node as unknown as Record<string, unknown>
612
+ for (let key of keys) {
613
+ let value = walkableNode[key]
614
+ if (Array.isArray(value)) {
615
+ for (let child of value) {
616
+ if (isAstNode(child)) {
617
+ walkAst(child, visit)
618
+ }
619
+ }
620
+ continue
621
+ }
622
+
623
+ if (isAstNode(value)) {
624
+ walkAst(value, visit)
625
+ }
626
+ }
627
+ }
628
+
629
+ function isAstNode(value: unknown): value is Node {
630
+ return typeof value === 'object' && value !== null && 'type' in value
631
+ }
632
+
633
+ function isStringLiteralNode(node: Node | null | undefined): node is Node & {
634
+ end: number
635
+ start: number
636
+ value: string
637
+ } {
638
+ return (
639
+ node?.type === 'Literal' &&
640
+ typeof node.start === 'number' &&
641
+ typeof node.end === 'number' &&
642
+ typeof node.value === 'string'
643
+ )
644
+ }
645
+
529
646
  function getStaticImportSpecifier(
530
647
  source: string,
531
648
  imported: ReturnType<typeof esModuleLexer>[0][number],
@@ -579,10 +696,10 @@ function toTransformFailedError(error: unknown, resolvedPath: string): AssetServ
579
696
  if (isAssetServerCompilationError(error)) return error
580
697
 
581
698
  return createAssetServerCompilationError(
582
- `Failed to transform module ${resolvedPath}. ${formatUnknownError(error)}`,
699
+ `Failed to transform script ${resolvedPath}. ${formatUnknownError(error)}`,
583
700
  {
584
701
  cause: error,
585
- code: 'MODULE_TRANSFORM_FAILED',
702
+ code: 'TRANSFORM_FAILED',
586
703
  },
587
704
  )
588
705
  }
@@ -52,17 +52,24 @@ export function rewriteSourceMapSources(
52
52
  resolvedPath: string,
53
53
  stableUrlPathname: string,
54
54
  sourceMapSourcePaths: 'absolute' | 'url',
55
+ sourceContent?: string,
55
56
  ): string {
56
- let json = JSON.parse(sourceMap) as { sources?: string[] }
57
+ let json = JSON.parse(sourceMap) as { sources?: string[]; sourcesContent?: string[] }
57
58
  json.sources = [
58
59
  sourceMapSourcePaths === 'absolute' ? normalizeFilePath(resolvedPath) : stableUrlPathname,
59
60
  ]
61
+ if (sourceContent !== undefined) {
62
+ json.sourcesContent = [sourceContent]
63
+ }
60
64
  return JSON.stringify(json)
61
65
  }
62
66
 
63
67
  export function stringifySourceMap(map: unknown): string | null {
64
68
  if (!map) return null
65
69
  if (typeof map === 'string') return map
70
+ if (map instanceof Uint8Array) {
71
+ return Buffer.from(map).toString('utf8')
72
+ }
66
73
  if (typeof map === 'object' && map !== null) return JSON.stringify(map)
67
74
  return String(map)
68
75
  }