@remix-run/assets 0.3.0 → 0.4.1

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 (66) hide show
  1. package/README.md +206 -8
  2. package/dist/assets.d.ts +1 -0
  3. package/dist/assets.d.ts.map +1 -1
  4. package/dist/assets.js +1 -0
  5. package/dist/lib/access.d.ts +1 -0
  6. package/dist/lib/access.d.ts.map +1 -1
  7. package/dist/lib/access.js +7 -1
  8. package/dist/lib/asset-server.d.ts +29 -6
  9. package/dist/lib/asset-server.d.ts.map +1 -1
  10. package/dist/lib/asset-server.js +176 -17
  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/files/compiler.d.ts +71 -0
  14. package/dist/lib/files/compiler.d.ts.map +1 -0
  15. package/dist/lib/files/compiler.js +552 -0
  16. package/dist/lib/files/config.d.ts +101 -0
  17. package/dist/lib/files/config.d.ts.map +1 -0
  18. package/dist/lib/files/config.js +219 -0
  19. package/dist/lib/files/store.d.ts +31 -0
  20. package/dist/lib/files/store.d.ts.map +1 -0
  21. package/dist/lib/files/store.js +63 -0
  22. package/dist/lib/fingerprint.d.ts +3 -3
  23. package/dist/lib/fingerprint.d.ts.map +1 -1
  24. package/dist/lib/fingerprint.js +5 -5
  25. package/dist/lib/routes.d.ts.map +1 -1
  26. package/dist/lib/routes.js +28 -20
  27. package/dist/lib/scripts/compiler.d.ts +1 -0
  28. package/dist/lib/scripts/compiler.d.ts.map +1 -1
  29. package/dist/lib/scripts/compiler.js +31 -14
  30. package/dist/lib/scripts/resolve.d.ts.map +1 -1
  31. package/dist/lib/scripts/resolve.js +35 -8
  32. package/dist/lib/scripts/specifiers.d.ts +2 -0
  33. package/dist/lib/scripts/specifiers.d.ts.map +1 -0
  34. package/dist/lib/scripts/specifiers.js +9 -0
  35. package/dist/lib/scripts/transform.d.ts.map +1 -1
  36. package/dist/lib/scripts/transform.js +3 -5
  37. package/dist/lib/styles/compiler.d.ts +4 -0
  38. package/dist/lib/styles/compiler.d.ts.map +1 -1
  39. package/dist/lib/styles/compiler.js +2 -0
  40. package/dist/lib/styles/emit.d.ts +3 -0
  41. package/dist/lib/styles/emit.d.ts.map +1 -1
  42. package/dist/lib/styles/emit.js +36 -1
  43. package/dist/lib/styles/resolve.d.ts +8 -1
  44. package/dist/lib/styles/resolve.d.ts.map +1 -1
  45. package/dist/lib/styles/resolve.js +85 -32
  46. package/dist/lib/watch.d.ts +2 -0
  47. package/dist/lib/watch.d.ts.map +1 -1
  48. package/dist/lib/watch.js +25 -8
  49. package/package.json +7 -5
  50. package/src/assets.ts +1 -0
  51. package/src/lib/access.ts +8 -1
  52. package/src/lib/asset-server.ts +273 -28
  53. package/src/lib/compilation-error.ts +9 -0
  54. package/src/lib/files/compiler.ts +885 -0
  55. package/src/lib/files/config.ts +479 -0
  56. package/src/lib/files/store.ts +109 -0
  57. package/src/lib/fingerprint.ts +8 -7
  58. package/src/lib/routes.ts +36 -33
  59. package/src/lib/scripts/compiler.ts +44 -17
  60. package/src/lib/scripts/resolve.ts +57 -9
  61. package/src/lib/scripts/specifiers.ts +11 -0
  62. package/src/lib/scripts/transform.ts +3 -6
  63. package/src/lib/styles/compiler.ts +9 -0
  64. package/src/lib/styles/emit.ts +75 -1
  65. package/src/lib/styles/resolve.ts +132 -35
  66. package/src/lib/watch.ts +34 -12
@@ -3,6 +3,7 @@ import * as path from 'node:path';
3
3
  import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
4
4
  import { getInjectedPackageNameForSpecifier, getInjectedPackageImporterPath, restoreAuthoredInjectedPackageSpecifier, } from "../injected-packages.js";
5
5
  import { normalizeFilePath } from "../paths.js";
6
+ import { isBareImportSpecifier } from "./specifiers.js";
6
7
  export const resolverExtensionAlias = {
7
8
  '.js': ['.js', '.ts', '.tsx', '.jsx'],
8
9
  '.jsx': ['.jsx', '.tsx'],
@@ -18,7 +19,10 @@ export async function resolveModule(record, transformed, args) {
18
19
  try {
19
20
  resolvedImports =
20
21
  transformed.unresolvedImports.length > 0
21
- ? await batchResolveSpecifiers(getUniqueSpecifiers(transformed.unresolvedImports), transformed.resolvedPath, args.resolverFactory)
22
+ ? await batchResolveSpecifiers(getUniqueSpecifiers(transformed.unresolvedImports), {
23
+ identityPath: transformed.identityPath,
24
+ resolvedPath: transformed.resolvedPath,
25
+ }, args.resolverFactory)
22
26
  : new Map();
23
27
  }
24
28
  catch (error) {
@@ -60,7 +64,7 @@ export async function resolveModule(record, transformed, args) {
60
64
  }
61
65
  deps.add(resolvedImport.identityPath);
62
66
  if (transformed.packageSpecifiers.includes(unresolved.specifier)) {
63
- let packageJsonPath = resolvedSpec.packageJsonPath ?? findNearestPackageJsonPath(resolvedImport.resolvedPath);
67
+ let packageJsonPath = resolvePackageJsonPath(resolvedSpec.packageJsonPath, resolvedImport.resolvedPath);
64
68
  if (packageJsonPath && !args.isWatchIgnored(packageJsonPath)) {
65
69
  trackedFiles.add(packageJsonPath);
66
70
  }
@@ -94,6 +98,20 @@ export async function resolveModule(record, transformed, args) {
94
98
  },
95
99
  };
96
100
  }
101
+ function resolvePackageJsonPath(packageJsonPath, resolvedPath) {
102
+ return ((packageJsonPath ? resolveExistingPath(packageJsonPath) : null) ??
103
+ findNearestPackageJsonPath(resolvedPath));
104
+ }
105
+ function resolveExistingPath(filePath) {
106
+ try {
107
+ return normalizeFilePath(fs.realpathSync(filePath));
108
+ }
109
+ catch (error) {
110
+ if (isNoEntityError(error))
111
+ return null;
112
+ throw error;
113
+ }
114
+ }
97
115
  function findNearestPackageJsonPath(filePath) {
98
116
  let directory = path.dirname(filePath);
99
117
  while (true) {
@@ -107,6 +125,12 @@ function findNearestPackageJsonPath(filePath) {
107
125
  directory = parentDirectory;
108
126
  }
109
127
  }
128
+ function isNoEntityError(error) {
129
+ return (error instanceof Error &&
130
+ 'code' in error &&
131
+ (error.code === 'ENOENT' ||
132
+ error.code === 'ENOTDIR'));
133
+ }
110
134
  function isRelativeImportSpecifier(specifier) {
111
135
  return specifier.startsWith('./') || specifier.startsWith('../');
112
136
  }
@@ -160,13 +184,13 @@ function getTrackedRelativeImportResolution(importerDir, specifier, isWatchIgnor
160
184
  function resolveCandidateBasePath(importerDir, specifier) {
161
185
  return normalizeFilePath(path.resolve(importerDir, specifier));
162
186
  }
163
- async function batchResolveSpecifiers(specifiers, importerPath, resolverFactory) {
187
+ async function batchResolveSpecifiers(specifiers, importer, resolverFactory) {
164
188
  let resolvedBySpecifier = new Map();
165
189
  if (specifiers.length === 0)
166
190
  return resolvedBySpecifier;
167
191
  try {
168
192
  for (let specifier of specifiers) {
169
- let normalizedResolution = normalizeSpecifierResolution(specifier, importerPath);
193
+ let normalizedResolution = normalizeSpecifierResolution(specifier, importer);
170
194
  let resolutionResult = await resolverFactory.resolveFileAsync(normalizedResolution.importerPath, normalizedResolution.specifier);
171
195
  if (resolutionResult.error) {
172
196
  throw createAssetServerCompilationError(normalizedResolution.importerPath === getInjectedPackageImporterPath()
@@ -191,7 +215,7 @@ async function batchResolveSpecifiers(specifiers, importerPath, resolverFactory)
191
215
  if (isAssetServerCompilationError(error) && error.code === 'IMPORT_RESOLUTION_FAILED') {
192
216
  throw error;
193
217
  }
194
- throw createAssetServerCompilationError(`Failed to resolve imports in ${importerPath}. ${formatUnknownError(error)}`, {
218
+ throw createAssetServerCompilationError(`Failed to resolve imports in ${importer.identityPath}. ${formatUnknownError(error)}`, {
195
219
  cause: error,
196
220
  code: 'IMPORT_RESOLUTION_FAILED',
197
221
  });
@@ -204,11 +228,11 @@ function getUniqueSpecifiers(unresolvedImports) {
204
228
  function formatUnknownError(error) {
205
229
  return error instanceof Error ? error.message : String(error);
206
230
  }
207
- function normalizeSpecifierResolution(specifier, importerPath) {
231
+ function normalizeSpecifierResolution(specifier, importer) {
208
232
  let authoredInjectedPackageSpecifier = restoreAuthoredInjectedPackageSpecifier(specifier);
209
233
  if (authoredInjectedPackageSpecifier) {
210
234
  return {
211
- importerPath,
235
+ importerPath: getSpecifierImporterPath(authoredInjectedPackageSpecifier, importer),
212
236
  specifier: authoredInjectedPackageSpecifier,
213
237
  };
214
238
  }
@@ -219,10 +243,13 @@ function normalizeSpecifierResolution(specifier, importerPath) {
219
243
  };
220
244
  }
221
245
  return {
222
- importerPath,
246
+ importerPath: getSpecifierImporterPath(specifier, importer),
223
247
  specifier,
224
248
  };
225
249
  }
250
+ function getSpecifierImporterPath(specifier, importer) {
251
+ return isBareImportSpecifier(specifier) ? importer.resolvedPath : importer.identityPath;
252
+ }
226
253
  function getDisplayImportSpecifier(specifier) {
227
254
  return restoreAuthoredInjectedPackageSpecifier(specifier) ?? specifier;
228
255
  }
@@ -0,0 +1,2 @@
1
+ export declare function isBareImportSpecifier(specifier: string): boolean;
2
+ //# sourceMappingURL=specifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specifiers.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/specifiers.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAUhE"}
@@ -0,0 +1,9 @@
1
+ export function isBareImportSpecifier(specifier) {
2
+ return (!specifier.startsWith('./') &&
3
+ !specifier.startsWith('../') &&
4
+ !specifier.startsWith('/') &&
5
+ !specifier.startsWith('file:') &&
6
+ !specifier.startsWith('data:') &&
7
+ !specifier.startsWith('http://') &&
8
+ !specifier.startsWith('https://'));
9
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/transform.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAS,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAS/D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAO1E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,KAAK,YAAY,GAAG,YAAY,CAAC,iBAAiB,EAAE,cAAc,EAAE,aAAa,CAAC,CAAA;AA4BlF,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,KAAK,gBAAgB,GAAG;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,iBAAiB,EAAE,gBAAgB,EAAE,CAAA;CACtC,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,QAAQ,EAAE,cAAc,CAAA;CACzB,GAAG,CACA;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,iBAAiB,CAAA;CACzB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CACJ,CAAA;AAED,KAAK,wBAAwB,GAAG;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,oBAAoB,CAAA;CACnC,CAAA;AAED,KAAK,gCAAgC,GAAG,UAAU,CAAC,OAAO,sCAAsC,CAAC,CAAA;AAEjG,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IACrC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAChC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACzC,MAAM,EAAE,OAAO,CAAA;IACf,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACtD,MAAM,EAAE,cAAc,CAAA;IACtB,oBAAoB,EAAE,UAAU,GAAG,KAAK,CAAA;IACxC,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAAA;IACxC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAA;IACnC,gCAAgC,EAAE,gCAAgC,CAAA;CACnE,CAAA;AAED,wBAAgB,sCAAsC;;;EAkCrD;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,eAAe,CAAC,CA6H1B"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/transform.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAS,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAS/D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAO1E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD,KAAK,YAAY,GAAG,YAAY,CAAC,iBAAiB,EAAE,cAAc,EAAE,aAAa,CAAC,CAAA;AA4BlF,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,KAAK,gBAAgB,GAAG;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,iBAAiB,EAAE,gBAAgB,EAAE,CAAA;CACtC,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,QAAQ,EAAE,cAAc,CAAA;CACzB,GAAG,CACA;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,iBAAiB,CAAA;CACzB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CACJ,CAAA;AAED,KAAK,wBAAwB,GAAG;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,oBAAoB,CAAA;CACnC,CAAA;AAED,KAAK,gCAAgC,GAAG,UAAU,CAAC,OAAO,sCAAsC,CAAC,CAAA;AAEjG,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IACrC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAChC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACzC,MAAM,EAAE,OAAO,CAAA;IACf,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACtD,MAAM,EAAE,cAAc,CAAA;IACtB,oBAAoB,EAAE,UAAU,GAAG,KAAK,CAAA;IACxC,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAAA;IACxC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAA;IACnC,gCAAgC,EAAE,gCAAgC,CAAA;CACnE,CAAA;AAED,wBAAgB,sCAAsC;;;EAkCrD;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,eAAe,CAAC,CA6H1B"}
@@ -13,6 +13,7 @@ import { generateFingerprint } from "../fingerprint.js";
13
13
  import { maskAuthoredInjectedPackageSpecifier, mayContainInjectedPackageSpecifier, restoreAuthoredInjectedPackageSpecifier, } from "../injected-packages.js";
14
14
  import { normalizeFilePath } from "../paths.js";
15
15
  import { composeSourceMaps, rewriteSourceMapSources, stringifySourceMap } from "../source-maps.js";
16
+ import { isBareImportSpecifier } from "./specifiers.js";
16
17
  const scriptModuleTypes = [
17
18
  { extension: '.js', lang: 'js' },
18
19
  { extension: '.jsx', lang: 'jsx' },
@@ -141,9 +142,9 @@ export async function transformModule(record, args) {
141
142
  content: sourceText,
142
143
  }),
143
144
  identityPath: record.identityPath,
144
- importerDir: path.dirname(resolvedPath),
145
+ importerDir: path.dirname(record.identityPath),
145
146
  packageSpecifiers: analysis.unresolvedImports
146
- .filter((unresolved) => isPackageImportSpecifier(unresolved.specifier))
147
+ .filter((unresolved) => isBareImportSpecifier(unresolved.specifier))
147
148
  .map((unresolved) => unresolved.specifier),
148
149
  rawCode: analysis.rawCode,
149
150
  resolvedPath,
@@ -177,9 +178,6 @@ function findNearestTsconfigPath(directory) {
177
178
  currentDirectory = parentDirectory;
178
179
  }
179
180
  }
180
- function isPackageImportSpecifier(specifier) {
181
- return !specifier.startsWith('./') && !specifier.startsWith('../') && !specifier.startsWith('/');
182
- }
183
181
  async function analyzeModuleSource(sourceText, resolvedPath, transformOptions, options) {
184
182
  let maskedSourceText = maskAuthoredInjectedPackageImports(sourceText, resolvedPath);
185
183
  let transformResult;
@@ -21,7 +21,11 @@ type StyleGetOptions = {
21
21
  type StyleCompilerOptions = {
22
22
  buildId?: string;
23
23
  fingerprintAssets: boolean;
24
+ getServedFileUrl?(identityPath: string, options: {
25
+ transform: readonly string[] | null;
26
+ }): Promise<string>;
24
27
  isAllowed(absolutePath: string): boolean;
28
+ isServedFilePath(filePath: string): boolean;
25
29
  minify: boolean;
26
30
  onWatchDirectoriesChange?: (delta: {
27
31
  add: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/compiler.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,WAAW,CAAA;AAS3D,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,YAAY,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,KAAK,cAAc,GACf;IACE,KAAK,EAAE,kBAAkB,CAAA;IACzB,IAAI,EAAE,OAAO,CAAA;CACd,GACD;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,cAAc,CAAA;CACrB,CAAA;AAEL,KAAK,eAAe,GAAG;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AAED,KAAK,oBAAoB,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,MAAM,EAAE,OAAO,CAAA;IACf,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,IAAI,CAAA;IAC/E,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,cAAc,CAAA;IACtB,oBAAoB,EAAE,UAAU,GAAG,KAAK,CAAA;IACxC,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC,OAAO,CAAC,EAAE,mBAAmB,CAAA;IAC7B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAChC,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC1C,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IAC7E,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACrF,CAAA;AAKD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAiOhF;AAkED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE;IACP,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;CACf,GACA,QAAQ,CA6BV"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/compiler.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,WAAW,CAAA;AAS3D,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,YAAY,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,KAAK,cAAc,GACf;IACE,KAAK,EAAE,kBAAkB,CAAA;IACzB,IAAI,EAAE,OAAO,CAAA;CACd,GACD;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,cAAc,CAAA;CACrB,CAAA;AAEL,KAAK,eAAe,GAAG;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AAED,KAAK,oBAAoB,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,gBAAgB,CAAC,CACf,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE;QACP,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;KACpC,GACA,OAAO,CAAC,MAAM,CAAC,CAAA;IAClB,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3C,MAAM,EAAE,OAAO,CAAA;IACf,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,IAAI,CAAA;IAC/E,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,cAAc,CAAA;IACtB,oBAAoB,EAAE,UAAU,GAAG,KAAK,CAAA;IACxC,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC,OAAO,CAAC,EAAE,mBAAmB,CAAA;IAC7B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAChC,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC1C,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IAC7E,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACrF,CAAA;AAKD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAmOhF;AAkED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE;IACP,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;CACf,GACA,QAAQ,CA6BV"}
@@ -23,6 +23,7 @@ export function createStyleCompiler(options) {
23
23
  let emitInFlightByCacheKey = new Map();
24
24
  let resolveArgs = {
25
25
  isAllowed: resolvedOptions.isAllowed,
26
+ isServedFilePath: resolvedOptions.isServedFilePath,
26
27
  isWatchIgnored,
27
28
  routes: resolvedOptions.routes,
28
29
  };
@@ -164,6 +165,7 @@ export function createStyleCompiler(options) {
164
165
  let startedVersion = record.invalidationVersion;
165
166
  let resolvedStyle = await getOrCreateResolvedStyle(record);
166
167
  let emitResolvedStyleResult = await emitResolvedStyle(resolvedStyle, {
168
+ getServedFileUrl: resolvedOptions.getServedFileUrl,
167
169
  getServedUrl,
168
170
  sourceMaps: resolvedOptions.sourceMaps,
169
171
  });
@@ -18,6 +18,9 @@ type EmitResult = {
18
18
  ok: false;
19
19
  };
20
20
  export declare function emitResolvedStyle(resolvedStyle: ResolvedStyle, options: {
21
+ getServedFileUrl?(identityPath: string, options: {
22
+ transform: readonly string[] | null;
23
+ }): Promise<string>;
21
24
  getServedUrl(identityPath: string): Promise<string>;
22
25
  sourceMaps?: 'external' | 'inline';
23
26
  }): Promise<EmitResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/emit.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,SAAS,EAAE,YAAY,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,KAAK,UAAU,GACX;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,YAAY,CAAA;CACpB,GACD;IACE,KAAK,EAAE,2BAA2B,CAAA;IAClC,EAAE,EAAE,KAAK,CAAA;CACV,CAAA;AAEL,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE;IACP,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACnD,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;CACnC,GACA,OAAO,CAAC,UAAU,CAAC,CAkCrB"}
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/emit.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,SAAS,EAAE,YAAY,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,KAAK,UAAU,GACX;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,YAAY,CAAA;CACpB,GACD;IACE,KAAK,EAAE,2BAA2B,CAAA;IAClC,EAAE,EAAE,KAAK,CAAA;CACV,CAAA;AAEL,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE;IACP,gBAAgB,CAAC,CACf,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE;QACP,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;KACpC,GACA,OAAO,CAAC,MAAM,CAAC,CAAA;IAClB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACnD,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;CACnC,GACA,OAAO,CAAC,UAAU,CAAC,CAkCrB"}
@@ -46,7 +46,11 @@ async function rewriteDependencies(resolvedStyle, options) {
46
46
  for (let dependency of resolvedStyle.dependencies) {
47
47
  let replacement = dependency.kind === 'external'
48
48
  ? dependency.replacement
49
- : `${await options.getServedUrl(dependency.depPath)}${dependency.suffix}`;
49
+ : dependency.kind === 'style'
50
+ ? `${await options.getServedUrl(dependency.depPath)}${dependency.suffix}`
51
+ : appendUrlSuffix(await getServedFileUrl(options, resolvedStyle.identityPath, dependency.depPath, {
52
+ transform: dependency.requestTransform,
53
+ }), dependency.suffix);
50
54
  let start = resolvedStyle.rawCode.indexOf(dependency.placeholder);
51
55
  if (start < 0) {
52
56
  throw createAssetServerCompilationError(`Missing dependency placeholder "${dependency.placeholder}" while emitting style ${resolvedStyle.identityPath}.`, {
@@ -62,6 +66,37 @@ async function rewriteDependencies(resolvedStyle, options) {
62
66
  : null,
63
67
  };
64
68
  }
69
+ function appendUrlSuffix(url, suffix) {
70
+ if (!suffix.startsWith('?') || !url.includes('?')) {
71
+ return `${url}${suffix}`;
72
+ }
73
+ return `${url}&${suffix.slice(1)}`;
74
+ }
75
+ async function getServedFileUrl(options, importerPath, identityPath, request) {
76
+ if (!options.getServedFileUrl) {
77
+ throw createAssetServerCompilationError(`Missing file URL resolver for ${identityPath}.`, {
78
+ code: 'EMIT_FAILED',
79
+ });
80
+ }
81
+ try {
82
+ return await options.getServedFileUrl(identityPath, request);
83
+ }
84
+ catch (error) {
85
+ if (request.transform !== null &&
86
+ isAssetServerCompilationError(error) &&
87
+ error.code === 'FILE_TRANSFORM_QUERY_INVALID') {
88
+ console.warn(`Invalid file transform request "${request.transform.join(',')}" in CSS asset ${importerPath} for ${identityPath}: ${error.message}`);
89
+ let href = await options.getServedFileUrl(identityPath, { transform: null });
90
+ let searchParams = new URLSearchParams();
91
+ for (let transform of request.transform) {
92
+ searchParams.append('transform', transform);
93
+ }
94
+ let search = searchParams.toString();
95
+ return search.length > 0 ? `${href}?${search}` : href;
96
+ }
97
+ throw error;
98
+ }
99
+ }
65
100
  async function createEmittedAsset(content) {
66
101
  return {
67
102
  content,
@@ -10,9 +10,15 @@ type ResolvedDependency = {
10
10
  replacement: string;
11
11
  } | {
12
12
  depPath: string;
13
- kind: 'local';
13
+ kind: 'style';
14
14
  placeholder: string;
15
15
  suffix: string;
16
+ } | {
17
+ depPath: string;
18
+ kind: 'file';
19
+ placeholder: string;
20
+ requestTransform: readonly string[] | null;
21
+ suffix: string;
16
22
  };
17
23
  export type ResolvedStyle = {
18
24
  dependencies: ResolvedDependency[];
@@ -27,6 +33,7 @@ export type ResolvedStyle = {
27
33
  };
28
34
  export type ResolveArgs = {
29
35
  isAllowed(absolutePath: string): boolean;
36
+ isServedFilePath(filePath: string): boolean;
30
37
  isWatchIgnored(filePath: string): boolean;
31
38
  routes: CompiledRoutes;
32
39
  };
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/resolve.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,KAAK,WAAW,GAAG,YAAY,CAAC,gBAAgB,EAAE,aAAa,EAAE,YAAY,CAAC,CAAA;AAE9E,KAAK,kBAAkB,GACnB;IACE,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;CACpB,GACD;IACE,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAEL,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,kBAAkB,EAAE,CAAA;IAClC,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACzC,MAAM,EAAE,cAAc,CAAA;CACvB,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,cAAc,CAAA;CACzB,GAAG,CACA;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,aAAa,CAAA;CACrB,GACD;IACE,KAAK,EAAE,2BAA2B,CAAA;IAClC,EAAE,EAAE,KAAK,CAAA;CACV,CACJ,CAAA;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,gBAAgB,EAC7B,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CAuDxB;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,GAChB;IACD,YAAY,EAAE,MAAM,CAAA;IACpB,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CA+BA"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/resolve.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,KAAK,WAAW,GAAG,YAAY,CAAC,gBAAgB,EAAE,aAAa,EAAE,YAAY,CAAC,CAAA;AAE9E,KAAK,kBAAkB,GACnB;IACE,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;CACpB,GACD;IACE,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;CACf,GACD;IACE,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;IAC1C,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAEL,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,kBAAkB,EAAE,CAAA;IAClC,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3C,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACzC,MAAM,EAAE,cAAc,CAAA;CACvB,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,cAAc,CAAA;CACzB,GAAG,CACA;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,aAAa,CAAA;CACrB,GACD;IACE,KAAK,EAAE,2BAA2B,CAAA;IAClC,EAAE,EAAE,KAAK,CAAA;CACV,CACJ,CAAA;AAQD,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,gBAAgB,EAC7B,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CA+DxB;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,GAChB;IACD,YAAY,EAAE,MAAM,CAAA;IACpB,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CA+BA"}
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
+ import { fileURLToPath, pathToFileURL } from 'node:url';
3
4
  import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
4
5
  import { normalizeFilePath } from "../paths.js";
5
6
  export async function resolveStyle(record, transformed, args) {
@@ -9,19 +10,21 @@ export async function resolveStyle(record, transformed, args) {
9
10
  for (let unresolved of transformed.unresolvedDependencies) {
10
11
  let trackedFile = unresolved.type === 'import'
11
12
  ? getTrackedImportFilePath(unresolved.url, transformed.resolvedPath)
12
- : null;
13
+ : getTrackedUrlFilePath(unresolved.url, transformed.resolvedPath);
13
14
  if (trackedFile && !args.isWatchIgnored(trackedFile)) {
14
15
  trackedFiles.add(trackedFile);
15
16
  }
16
17
  try {
17
18
  let resolved = unresolved.type === 'import'
18
19
  ? resolveImportDependency(unresolved.url, transformed.resolvedPath, unresolved.placeholder, args)
19
- : resolveUrlDependency(unresolved.url, unresolved.placeholder);
20
+ : resolveUrlDependency(unresolved.url, transformed.resolvedPath, unresolved.placeholder, args);
20
21
  dependencies.push(resolved);
21
- if (resolved.kind === 'local') {
22
+ if (resolved.kind === 'style' || resolved.kind === 'file') {
22
23
  if (!args.isWatchIgnored(resolved.depPath)) {
23
24
  trackedFiles.add(resolved.depPath);
24
25
  }
26
+ }
27
+ if (resolved.kind === 'style') {
25
28
  deps.add(resolved.depPath);
26
29
  }
27
30
  }
@@ -80,22 +83,16 @@ function resolveImportDependency(url, importerPath, placeholder, args) {
80
83
  replacement: url,
81
84
  };
82
85
  }
83
- let { pathname, suffix } = splitUrlSuffix(url);
84
- if (pathname.length === 0 || pathname === '#') {
85
- return {
86
- kind: 'external',
87
- placeholder,
88
- replacement: url,
89
- };
90
- }
91
- if (pathname.startsWith('/')) {
86
+ let parsedUrl = parseRelativeUrl(url, importerPath);
87
+ if (parsedUrl === null) {
92
88
  return {
93
89
  kind: 'external',
94
90
  placeholder,
95
91
  replacement: url,
96
92
  };
97
93
  }
98
- let resolvedFilePath = normalizeFilePath(path.resolve(path.dirname(importerPath), pathname));
94
+ let { hash, resolvedPath, search } = parsedUrl;
95
+ let resolvedFilePath = resolvedPath;
99
96
  let identityPath = resolveExistingFilePath(resolvedFilePath);
100
97
  if (!identityPath || !isStyleFilePath(identityPath)) {
101
98
  throw createAssetServerCompilationError(`Failed to resolve import "${url}" in ${importerPath}.`, {
@@ -116,16 +113,60 @@ function resolveImportDependency(url, importerPath, placeholder, args) {
116
113
  }
117
114
  return {
118
115
  depPath: identityPath,
119
- kind: 'local',
116
+ kind: 'style',
120
117
  placeholder,
121
- suffix,
118
+ suffix: `${search}${hash}`,
122
119
  };
123
120
  }
124
- function resolveUrlDependency(url, placeholder) {
121
+ function resolveUrlDependency(url, importerPath, placeholder, args) {
122
+ if (isExternalUrl(url)) {
123
+ return {
124
+ kind: 'external',
125
+ placeholder,
126
+ replacement: url,
127
+ };
128
+ }
129
+ let parsedUrl = parseRelativeUrl(url, importerPath);
130
+ if (parsedUrl === null) {
131
+ return {
132
+ kind: 'external',
133
+ placeholder,
134
+ replacement: url,
135
+ };
136
+ }
137
+ let { hash, resolvedPath, search } = parsedUrl;
138
+ let resolvedFilePath = resolvedPath;
139
+ let identityPath = resolveExistingFilePath(resolvedFilePath);
140
+ if (!identityPath) {
141
+ throw createAssetServerCompilationError(`Failed to resolve url("${url}") in ${importerPath}.`, {
142
+ code: 'URL_RESOLUTION_FAILED',
143
+ });
144
+ }
145
+ if (!args.isServedFilePath(identityPath)) {
146
+ throw createAssetServerCompilationError(`URL "${url}" in ${importerPath}, resolved to "${identityPath}", is not a supported file asset. ` +
147
+ `Add the file extension to files.extensions to serve this asset.`, {
148
+ code: 'URL_NOT_SUPPORTED',
149
+ });
150
+ }
151
+ if (!args.isAllowed(identityPath)) {
152
+ throw createAssetServerCompilationError(`URL "${url}" in ${importerPath}, resolved to "${identityPath}", is not allowed by the asset server allow/deny configuration. ` +
153
+ `Add a matching allow rule for this file path or remove a conflicting deny rule for this file path.`, {
154
+ code: 'URL_NOT_ALLOWED',
155
+ });
156
+ }
157
+ if (!args.routes.toUrlPathname(identityPath)) {
158
+ throw createAssetServerCompilationError(`URL "${url}" in ${importerPath}, resolved to "${identityPath}", is outside all configured fileMap entries. ` +
159
+ `Add a matching fileMap entry for this file path.`, {
160
+ code: 'URL_OUTSIDE_FILE_MAP',
161
+ });
162
+ }
163
+ let parsedRequest = parseResolvedFileRequest({ hash, search });
125
164
  return {
126
- kind: 'external',
165
+ depPath: identityPath,
166
+ kind: 'file',
127
167
  placeholder,
128
- replacement: url,
168
+ requestTransform: parsedRequest.transform,
169
+ suffix: parsedRequest.suffix,
129
170
  };
130
171
  }
131
172
  function resolveExistingFilePath(filePath) {
@@ -138,27 +179,39 @@ function resolveExistingFilePath(filePath) {
138
179
  throw error;
139
180
  }
140
181
  }
141
- function splitUrlSuffix(url) {
142
- let queryIndex = url.indexOf('?');
143
- let hashIndex = url.indexOf('#');
144
- let endIndex = [queryIndex, hashIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];
145
- if (endIndex == null) {
182
+ function parseRelativeUrl(url, importerPath) {
183
+ if (url.length === 0 || url.startsWith('?') || url.startsWith('/') || isExternalUrl(url)) {
184
+ return null;
185
+ }
186
+ let parsed = new URL(url, pathToFileURL(importerPath));
187
+ return {
188
+ hash: parsed.hash,
189
+ resolvedPath: normalizeFilePath(fileURLToPath(parsed)),
190
+ search: parsed.search,
191
+ };
192
+ }
193
+ function parseResolvedFileRequest(url) {
194
+ let { hash, search } = url;
195
+ if (search.length === 0) {
146
196
  return {
147
- pathname: url,
148
- suffix: '',
197
+ suffix: hash,
198
+ transform: null,
149
199
  };
150
200
  }
201
+ let searchParams = new URLSearchParams(search.slice(1));
202
+ let transform = searchParams.getAll('transform');
203
+ searchParams.delete('transform');
204
+ let remainingSearch = searchParams.toString();
151
205
  return {
152
- pathname: url.slice(0, endIndex),
153
- suffix: url.slice(endIndex),
206
+ suffix: `${remainingSearch.length > 0 ? `?${remainingSearch}` : ''}${hash}`,
207
+ transform: transform.length > 0 ? transform : null,
154
208
  };
155
209
  }
156
210
  function getTrackedImportFilePath(specifier, importerPath) {
157
- let { pathname } = splitUrlSuffix(specifier);
158
- if (pathname.startsWith('./') || pathname.startsWith('../')) {
159
- return normalizeFilePath(path.resolve(path.dirname(importerPath), pathname));
160
- }
161
- return null;
211
+ return parseRelativeUrl(specifier, importerPath)?.resolvedPath ?? null;
212
+ }
213
+ function getTrackedUrlFilePath(url, importerPath) {
214
+ return parseRelativeUrl(url, importerPath)?.resolvedPath ?? null;
162
215
  }
163
216
  function isStyleFilePath(filePath) {
164
217
  return path.extname(filePath).toLowerCase() === '.css';
@@ -15,6 +15,8 @@ export type AssetServerWatcher = {
15
15
  updateWatchedDirectories(delta: {
16
16
  add: readonly string[];
17
17
  remove: readonly string[];
18
+ }, options?: {
19
+ includeAncestors?: boolean;
18
20
  }): void;
19
21
  };
20
22
  export declare function createAssetServerWatcher(options: AssetServerWatcherOptions): AssetServerWatcher;
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/lib/watch.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAI/B,KAAK,yBAAyB,GAAG;IAC/B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,wBAAwB,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;IAC7D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,KAAK,qBAAqB,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAA;AACxD,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAA;AAE/D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAAA;IACtC,wBAAwB,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAA;CAC7F,CAAA;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAmD/F"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/lib/watch.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAI/B,KAAK,yBAAyB,GAAG;IAC/B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,wBAAwB,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;IAC7D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,KAAK,qBAAqB,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAA;AACxD,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAA;AAE/D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAAA;IACtC,wBAAwB,CACtB,KAAK,EAAE;QAAE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,EAC5D,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE,GACvC,IAAI,CAAA;CACR,CAAA;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAiE/F"}
package/dist/lib/watch.js CHANGED
@@ -7,7 +7,8 @@ export function createAssetServerWatcher(options) {
7
7
  ...resolveChokidarWatchOptions(options),
8
8
  });
9
9
  options.onChokidarWatcherCreated?.(watcher);
10
- let watchedDirectories = new Set();
10
+ let watchedResolutionDirectories = new Set();
11
+ let watchedFileDirectories = new Set();
11
12
  let watchedTargets = new Set();
12
13
  for (let event of ['add', 'change', 'unlink']) {
13
14
  watcher.on(event, (filePath) => {
@@ -24,15 +25,29 @@ export function createAssetServerWatcher(options) {
24
25
  getWatchedTargets() {
25
26
  return [...watchedTargets];
26
27
  },
27
- updateWatchedDirectories(delta) {
28
- let nextWatchedDirectories = new Set(watchedDirectories);
28
+ updateWatchedDirectories(delta, updateOptions = {}) {
29
+ let includeAncestors = updateOptions.includeAncestors ?? true;
30
+ let previousDirectories = includeAncestors
31
+ ? watchedResolutionDirectories
32
+ : watchedFileDirectories;
33
+ let nextWatchedDirectories = new Set(previousDirectories);
29
34
  for (let directory of delta.add) {
30
35
  nextWatchedDirectories.add(directory);
31
36
  }
32
37
  for (let directory of delta.remove) {
33
38
  nextWatchedDirectories.delete(directory);
34
39
  }
35
- let nextTargets = getWatchTargetsForDirectories(options.rootDir, [...nextWatchedDirectories]);
40
+ if (includeAncestors) {
41
+ watchedResolutionDirectories = nextWatchedDirectories;
42
+ }
43
+ else {
44
+ watchedFileDirectories = nextWatchedDirectories;
45
+ }
46
+ let nextTargets = getWatchTargets({
47
+ rootDir: options.rootDir,
48
+ fileDirectories: [...watchedFileDirectories],
49
+ resolutionDirectories: [...watchedResolutionDirectories],
50
+ });
36
51
  let targetsToAdd = [...nextTargets].filter((target) => !watchedTargets.has(target));
37
52
  let targetsToRemove = [...watchedTargets].filter((target) => !nextTargets.has(target));
38
53
  if (targetsToRemove.length > 0) {
@@ -41,7 +56,6 @@ export function createAssetServerWatcher(options) {
41
56
  if (targetsToAdd.length > 0) {
42
57
  watcher.add(targetsToAdd);
43
58
  }
44
- watchedDirectories = nextWatchedDirectories;
45
59
  watchedTargets = nextTargets;
46
60
  },
47
61
  };
@@ -58,11 +72,14 @@ function resolveChokidarWatchOptions(options) {
58
72
  usePolling: options.poll ?? false,
59
73
  };
60
74
  }
61
- function getWatchTargetsForDirectories(rootDir, directories) {
62
- let normalizedRootDir = normalizeFilePath(rootDir);
75
+ function getWatchTargets(options) {
76
+ let normalizedRootDir = normalizeFilePath(options.rootDir);
63
77
  let targets = new Set();
64
78
  let configAncestors = new Set();
65
- for (let directory of directories) {
79
+ for (let directory of options.fileDirectories) {
80
+ targets.add(normalizeFilePath(directory).replace(/\/+$/, ''));
81
+ }
82
+ for (let directory of options.resolutionDirectories) {
66
83
  let normalizedDirectory = normalizeFilePath(directory).replace(/\/+$/, '');
67
84
  targets.add(normalizedDirectory);
68
85
  if (!isSameOrDescendantPath(normalizedDirectory, normalizedRootDir))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/assets",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Fetch-based server for compiling browser JS/TS and CSS assets on demand",
5
5
  "author": "Michael Jackson <mjijackson@gmail.com>",
6
6
  "license": "MIT",
@@ -38,15 +38,17 @@
38
38
  "oxc-transform": "^0.121.0",
39
39
  "picomatch": "^4.0.4",
40
40
  "source-map-js": "^1.2.1",
41
- "@remix-run/headers": "0.19.0",
42
- "@remix-run/route-pattern": "0.20.1"
41
+ "@remix-run/file-storage": "0.13.5",
42
+ "@remix-run/headers": "0.21.0",
43
+ "@remix-run/route-pattern": "0.21.1",
44
+ "@remix-run/mime": "0.4.1"
43
45
  },
44
46
  "devDependencies": {
45
47
  "@types/node": "^24.6.0",
46
48
  "@types/picomatch": "^4.0.3",
47
49
  "@typescript/native-preview": "7.0.0-dev.20251125.1",
48
- "@remix-run/assert": "0.2.0",
49
- "@remix-run/test": "0.3.0"
50
+ "@remix-run/assert": "0.2.1",
51
+ "@remix-run/test": "0.4.1"
50
52
  },
51
53
  "keywords": [
52
54
  "remix",
package/src/assets.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { createAssetServer } from './lib/asset-server.ts'
2
+ export { defineFileTransform } from './lib/files/config.ts'
2
3
  export type { AssetServer, AssetServerOptions } from './lib/asset-server.ts'