@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
@@ -18,7 +18,10 @@ type EmitResult = {
18
18
  error: AssetServerCompilationError;
19
19
  };
20
20
  export declare function emitResolvedModule(resolvedModule: ResolvedModule, options: {
21
+ getHmrImportTimestamp(identityPath: string): number | null;
21
22
  getServedUrl(identityPath: string): Promise<string>;
23
+ getStableUrl(identityPath: string): string;
24
+ hmrClientPathname?: string;
22
25
  sourceMaps?: 'external' | 'inline';
23
26
  }): Promise<EmitResult>;
24
27
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/emit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAE1E,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,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,aAAa,CAAA;CACrB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CAAA;AAEL,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,cAAc,EAC9B,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/scripts/emit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAE1E,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,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,aAAa,CAAA;CACrB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CAAA;AAQL,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE;IACP,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAC1D,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACnD,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;CACnC,GACA,OAAO,CAAC,UAAU,CAAC,CAkCrB"}
@@ -1,12 +1,12 @@
1
1
  import MagicString from 'magic-string';
2
- import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
3
- import { hashContent } from "../fingerprint.js";
4
- import { composeSourceMaps } from "../source-maps.js";
2
+ import { createAssetServerCompilationError, isAssetServerCompilationError, } from '../compilation-error.js';
3
+ import { hashContent } from '../fingerprint.js';
4
+ import { composeSourceMaps } from '../source-maps.js';
5
5
  export async function emitResolvedModule(resolvedModule, options) {
6
6
  try {
7
7
  let importUrls = await Promise.all(resolvedModule.deps.map((depPath) => options.getServedUrl(depPath)));
8
8
  let rewriteResult = await rewriteImports(resolvedModule, options);
9
- let finalCode = rewriteResult.code;
9
+ let finalCode = prependHmrContext(resolvedModule, rewriteResult.code, options);
10
10
  if (rewriteResult.sourceMap) {
11
11
  if (options.sourceMaps === 'inline') {
12
12
  let encoded = Buffer.from(rewriteResult.sourceMap).toString('base64');
@@ -39,14 +39,33 @@ async function rewriteImports(resolvedModule, options) {
39
39
  let rewrittenSource = new MagicString(resolvedModule.rawCode);
40
40
  for (let imported of resolvedModule.imports) {
41
41
  let url = await options.getServedUrl(imported.depPath);
42
+ let hmrImportTimestamp = options.getHmrImportTimestamp(imported.depPath);
43
+ if (hmrImportTimestamp !== null) {
44
+ url = addTimestampQuery(url, hmrImportTimestamp);
45
+ }
42
46
  rewrittenSource.overwrite(imported.start, imported.end, imported.quote ? `${imported.quote}${url}${imported.quote}` : url);
43
47
  }
48
+ for (let acceptedDep of resolvedModule.hmr.acceptedDeps) {
49
+ let url = options.getStableUrl(acceptedDep.depPath);
50
+ rewrittenSource.overwrite(acceptedDep.start, acceptedDep.end, acceptedDep.quote ? `${acceptedDep.quote}${url}${acceptedDep.quote}` : url);
51
+ }
44
52
  let code = rewrittenSource.toString();
45
- let sourceMap = resolvedModule.sourceMap && resolvedModule.imports.length > 0
53
+ let sourceMap = resolvedModule.sourceMap &&
54
+ (resolvedModule.imports.length > 0 || resolvedModule.hmr.acceptedDeps.length > 0)
46
55
  ? composeSourceMaps(rewrittenSource.generateMap({ hires: true }).toString(), resolvedModule.sourceMap)
47
56
  : resolvedModule.sourceMap;
48
57
  return { code, sourceMap };
49
58
  }
59
+ function addTimestampQuery(pathname, timestamp) {
60
+ return `${pathname}${pathname.includes('?') ? '&' : '?'}t=${timestamp}`;
61
+ }
62
+ function prependHmrContext(resolvedModule, code, options) {
63
+ if (!options.hmrClientPathname || !resolvedModule.hmr.usesImportMetaHot)
64
+ return code;
65
+ return (`import { createHotContext as __remixCreateHotContext } from ${JSON.stringify(options.hmrClientPathname)};\n` +
66
+ `import.meta.hot = __remixCreateHotContext(${JSON.stringify(resolvedModule.stableUrlPathname)});\n` +
67
+ code);
68
+ }
50
69
  async function createEmittedAsset(content) {
51
70
  return {
52
71
  content,
@@ -18,9 +18,13 @@ type ResolvedImport = {
18
18
  quote?: '"' | "'" | '`';
19
19
  start: number;
20
20
  };
21
+ type ResolvedHmrAcceptedDependency = ResolvedImport;
21
22
  export type ResolvedModule = {
22
23
  deps: string[];
23
24
  fingerprint: string | null;
25
+ hmr: Omit<TransformedModule['hmr'], 'acceptedDeps'> & {
26
+ acceptedDeps: ResolvedHmrAcceptedDependency[];
27
+ };
24
28
  identityPath: string;
25
29
  imports: ResolvedImport[];
26
30
  trackedFiles: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/resolve.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAMnD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAM1E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C,KAAK,YAAY,GAAG,YAAY,CAAC,iBAAiB,EAAE,cAAc,EAAE,aAAa,CAAC,CAAA;AAElF,eAAO,MAAM,sBAAsB;;;;CAIC,CAAA;AAEpC,eAAO,MAAM,kBAAkB,UAAiD,CAAA;AAChF,eAAO,MAAM,yBAAyB,UAAiD,CAAA;AAGvF,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAYD,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,cAAc,CAAA;CACzB,GAAG,CACA;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,cAAc,CAAA;CACtB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CACJ,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,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAAA;IACnE,eAAe,EAAE,eAAe,CAAA;IAChC,MAAM,EAAE,cAAc,CAAA;CACvB,CAAA;AAaD,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,iBAAiB,EAC9B,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CA0IxB"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/resolve.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAMnD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAM1E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C,KAAK,YAAY,GAAG,YAAY,CAAC,iBAAiB,EAAE,cAAc,EAAE,aAAa,CAAC,CAAA;AAElF,eAAO,MAAM,sBAAsB;;;;CAIC,CAAA;AAEpC,eAAO,MAAM,kBAAkB,UAAiD,CAAA;AAChF,eAAO,MAAM,yBAAyB,UAAiD,CAAA;AAGvF,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,6BAA6B,GAAG,cAAc,CAAA;AAYnD,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,GAAG,EAAE,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,GAAG;QACpD,YAAY,EAAE,6BAA6B,EAAE,CAAA;KAC9C,CAAA;IACD,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,cAAc,CAAA;CACzB,GAAG,CACA;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,cAAc,CAAA;CACtB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CACJ,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,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAAA;IACnE,eAAe,EAAE,eAAe,CAAA;IAChC,MAAM,EAAE,cAAc,CAAA;CACvB,CAAA;AAaD,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,iBAAiB,EAC9B,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CA2PxB"}
@@ -1,8 +1,8 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
- import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
4
- import { getInjectedPackageNameForSpecifier, getInjectedPackageImporterPath, restoreAuthoredInjectedPackageSpecifier, } from "../injected-packages.js";
5
- import { normalizeFilePath } from "../paths.js";
3
+ import { createAssetServerCompilationError, isAssetServerCompilationError, } from '../compilation-error.js';
4
+ import { getInjectedPackageNameForSpecifier, getInjectedPackageImporterPath, restoreAuthoredInjectedPackageSpecifier, } from '../injected-packages.js';
5
+ import { normalizeFilePath } from '../paths.js';
6
6
  export const resolverExtensionAlias = {
7
7
  '.js': ['.js', '.ts', '.tsx', '.jsx'],
8
8
  '.jsx': ['.jsx', '.tsx'],
@@ -27,6 +27,7 @@ export async function resolveModule(record, transformed, args) {
27
27
  });
28
28
  }
29
29
  let importsWithPaths = [];
30
+ let acceptedDepsWithPaths = [];
30
31
  let deps = new Set();
31
32
  for (let unresolved of transformed.unresolvedImports) {
32
33
  let displaySpecifier = getDisplayImportSpecifier(unresolved.specifier);
@@ -46,8 +47,8 @@ export async function resolveModule(record, transformed, args) {
46
47
  }), trackedFiles, trackedResolutions, transformed.resolvedPath, { isWatchIgnored: args.isWatchIgnored, trackedResolution });
47
48
  }
48
49
  if (!args.isAllowed(resolvedImport.identityPath)) {
49
- return failResolve(createAssetServerCompilationError(`Import "${displaySpecifier}" in ${transformed.resolvedPath}, resolved to "${resolvedImport.identityPath}", is not allowed by the asset server allow/deny configuration. ` +
50
- `Add a matching allow rule for this file path, remove a conflicting deny rule for this file path, or mark this import as external.`, {
50
+ return failResolve(createAssetServerCompilationError(`Import "${displaySpecifier}" in ${transformed.resolvedPath}, resolved to "${resolvedImport.identityPath}", is not allowed by the asset server access configuration. ` +
51
+ `Add a matching allowFiles or allowPackages rule, remove a conflicting denyFiles rule, or mark this import as external.`, {
51
52
  code: 'IMPORT_NOT_ALLOWED',
52
53
  }), trackedFiles, trackedResolutions, transformed.resolvedPath, { isWatchIgnored: args.isWatchIgnored, trackedResolution });
53
54
  }
@@ -78,12 +79,73 @@ export async function resolveModule(record, transformed, args) {
78
79
  start: unresolved.start,
79
80
  });
80
81
  }
82
+ for (let unresolved of transformed.hmr.acceptedDeps) {
83
+ if (isBrowserExternalModuleUrl(unresolved.specifier))
84
+ continue;
85
+ let displaySpecifier = getDisplayImportSpecifier(unresolved.specifier);
86
+ let trackedResolution = getTrackedRelativeImportResolution(transformed.importerDir, displaySpecifier, args.isWatchIgnored);
87
+ let resolvedSpec = resolvedImports.get(unresolved.specifier);
88
+ if (!resolvedSpec?.absolutePath) {
89
+ try {
90
+ resolvedSpec = await batchResolveSpecifiers([unresolved.specifier], transformed.resolvedPath, args.resolverFactory).then((resolved) => resolved.get(unresolved.specifier));
91
+ }
92
+ catch (error) {
93
+ return failResolve(error, trackedFiles, trackedResolutions, transformed.resolvedPath, {
94
+ isWatchIgnored: args.isWatchIgnored,
95
+ trackedResolution,
96
+ });
97
+ }
98
+ }
99
+ if (!resolvedSpec?.absolutePath) {
100
+ return failResolve(createAssetServerCompilationError(`Failed to resolve accepted HMR dependency "${displaySpecifier}" in ${transformed.resolvedPath}. ` +
101
+ `Ensure it resolves to a file within the configured asset server fileMap, or mark it as external.`, {
102
+ code: 'IMPORT_RESOLUTION_FAILED',
103
+ }), trackedFiles, trackedResolutions, transformed.resolvedPath, { isWatchIgnored: args.isWatchIgnored, trackedResolution });
104
+ }
105
+ let resolvedImport = args.resolveModulePath(resolvedSpec.absolutePath);
106
+ if (!resolvedImport) {
107
+ return failResolve(createAssetServerCompilationError(`Accepted HMR dependency "${displaySpecifier}" in ${transformed.resolvedPath}, resolved to "${resolvedSpec.absolutePath}", is not a supported script file. ` +
108
+ `Supported extensions are ${supportedScriptExtensions.join(', ')}.`, {
109
+ code: 'IMPORT_NOT_SUPPORTED',
110
+ }), trackedFiles, trackedResolutions, transformed.resolvedPath, { isWatchIgnored: args.isWatchIgnored, trackedResolution });
111
+ }
112
+ if (!args.isAllowed(resolvedImport.identityPath)) {
113
+ return failResolve(createAssetServerCompilationError(`Accepted HMR dependency "${displaySpecifier}" in ${transformed.resolvedPath}, resolved to "${resolvedImport.identityPath}", is not allowed by the asset server allow/deny configuration. ` +
114
+ `Add a matching allow rule for this file path, remove a conflicting deny rule for this file path, or mark this import as external.`, {
115
+ code: 'IMPORT_NOT_ALLOWED',
116
+ }), trackedFiles, trackedResolutions, transformed.resolvedPath, { isWatchIgnored: args.isWatchIgnored, trackedResolution });
117
+ }
118
+ let stableUrlPathname = args.routes.toUrlPathname(resolvedImport.identityPath);
119
+ if (!stableUrlPathname) {
120
+ return failResolve(createAssetServerCompilationError(`Accepted HMR dependency "${displaySpecifier}" in ${transformed.resolvedPath}, resolved to "${resolvedImport.identityPath}", is outside all configured fileMap entries. ` +
121
+ `Add a matching fileMap entry for this file path, or mark this import as external.`, {
122
+ code: 'IMPORT_OUTSIDE_FILE_MAP',
123
+ }), trackedFiles, trackedResolutions, transformed.resolvedPath, { isWatchIgnored: args.isWatchIgnored, trackedResolution });
124
+ }
125
+ if (trackedResolution) {
126
+ trackedResolutions.push({
127
+ ...trackedResolution,
128
+ resolvedIdentityPath: resolvedImport.identityPath,
129
+ });
130
+ }
131
+ acceptedDepsWithPaths.push({
132
+ depPath: resolvedImport.identityPath,
133
+ end: unresolved.end,
134
+ quote: unresolved.quote,
135
+ start: unresolved.start,
136
+ });
137
+ }
81
138
  return {
82
139
  ok: true,
83
140
  tracking: toResolveTracking(trackedFiles, trackedResolutions),
84
141
  value: {
85
142
  deps: [...deps],
86
143
  fingerprint: transformed.fingerprint,
144
+ hmr: {
145
+ acceptedDeps: acceptedDepsWithPaths,
146
+ selfAccepting: transformed.hmr.selfAccepting,
147
+ usesImportMetaHot: transformed.hmr.usesImportMetaHot,
148
+ },
87
149
  identityPath: record.identityPath,
88
150
  imports: importsWithPaths,
89
151
  trackedFiles: [...trackedFiles],
@@ -226,6 +288,9 @@ function normalizeSpecifierResolution(specifier, importerPath) {
226
288
  function getDisplayImportSpecifier(specifier) {
227
289
  return restoreAuthoredInjectedPackageSpecifier(specifier) ?? specifier;
228
290
  }
291
+ function isBrowserExternalModuleUrl(url) {
292
+ return url.startsWith('data:') || url.startsWith('http://') || url.startsWith('https://');
293
+ }
229
294
  function failResolve(error, trackedFiles, trackedResolutions, importerPath, options = {}) {
230
295
  return {
231
296
  ok: false,
@@ -1,6 +1,7 @@
1
1
  import type { TsConfigJsonResolved } from 'get-tsconfig';
2
2
  import type { AssetServerCompilationError } from '../compilation-error.ts';
3
3
  import type { ModuleRecord, ModuleTracking } from '../module-store.ts';
4
+ import type { ModuleLoader } from '../loaders.ts';
4
5
  import type { CompiledRoutes } from '../routes.ts';
5
6
  import type { EmittedModule } from './emit.ts';
6
7
  import type { ResolvedScriptTarget } from '../target.ts';
@@ -16,8 +17,14 @@ type UnresolvedImport = {
16
17
  specifier: string;
17
18
  start: number;
18
19
  };
20
+ type HmrAcceptedDependency = UnresolvedImport;
19
21
  export type TransformedModule = {
20
22
  fingerprint: string | null;
23
+ hmr: {
24
+ acceptedDeps: HmrAcceptedDependency[];
25
+ selfAccepting: boolean;
26
+ usesImportMetaHot: boolean;
27
+ };
21
28
  identityPath: string;
22
29
  importerDir: string;
23
30
  packageSpecifiers: string[];
@@ -48,6 +55,7 @@ export type TransformArgs = {
48
55
  externalSet: ReadonlySet<string>;
49
56
  isWatchIgnored(filePath: string): boolean;
50
57
  minify: boolean;
58
+ loaders: readonly ModuleLoader[];
51
59
  resolveActualPath(identityPath: string): string | null;
52
60
  routes: CompiledRoutes;
53
61
  sourceMapSourcePaths: 'absolute' | 'url';
@@ -60,5 +68,6 @@ export declare function createTsconfigTransformOptionsResolver(): {
60
68
  getTransformOptions(filePath: string, isWatchIgnored: (filePath: string) => boolean): TsconfigTransformOptions;
61
69
  };
62
70
  export declare function transformModule(record: ScriptRecord, args: TransformArgs): Promise<TransformResult>;
71
+ export declare function getHmrAnalysis(rawCode: string): TransformedModule['hmr'];
63
72
  export {};
64
73
  //# sourceMappingURL=transform.d.ts.map
@@ -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":"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"}
@@ -1,18 +1,20 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as fsp from 'node:fs/promises';
3
3
  import * as path from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
4
5
  import { getTsconfig } from 'get-tsconfig';
5
6
  import MagicString from 'magic-string';
6
7
  import { minify } from 'oxc-minify';
7
8
  import { parseSync, visitorKeys } from 'oxc-parser';
8
9
  import { transform as oxcTransform } from 'oxc-transform';
9
10
  import { init as esModuleLexerInit, parse as esModuleLexer } from 'es-module-lexer';
10
- import { isCommonJS, mayContainCommonJSModuleGlobals } from "./cjs-check.js";
11
- import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
12
- import { generateFingerprint } from "../fingerprint.js";
13
- import { maskAuthoredInjectedPackageSpecifier, mayContainInjectedPackageSpecifier, restoreAuthoredInjectedPackageSpecifier, } from "../injected-packages.js";
14
- import { normalizeFilePath } from "../paths.js";
15
- import { composeSourceMaps, rewriteSourceMapSources, stringifySourceMap } from "../source-maps.js";
11
+ import { isCommonJS, mayContainCommonJSModuleGlobals } from './cjs-check.js';
12
+ import { createAssetServerCompilationError, isAssetServerCompilationError, } from '../compilation-error.js';
13
+ import { generateFingerprint } from '../fingerprint.js';
14
+ import { maskAuthoredInjectedPackageSpecifier, mayContainInjectedPackageSpecifier, restoreAuthoredInjectedPackageSpecifier, } from '../injected-packages.js';
15
+ import { normalizeFilePath } from '../paths.js';
16
+ import { composeSourceMaps, rewriteSourceMapSources, stringifySourceMap } from '../source-maps.js';
17
+ import { scriptLoaderConditions } from './conditions.js';
16
18
  const scriptModuleTypes = [
17
19
  { extension: '.js', lang: 'js' },
18
20
  { extension: '.jsx', lang: 'jsx' },
@@ -105,9 +107,17 @@ export async function transformModule(record, args) {
105
107
  };
106
108
  }
107
109
  try {
110
+ let stableUrlPathname = args.routes.toUrlPathname(record.identityPath);
111
+ if (!stableUrlPathname) {
112
+ throw createAssetServerCompilationError(`File ${record.identityPath} is outside all configured fileMap entries.`, {
113
+ code: 'FILE_OUTSIDE_FILE_MAP',
114
+ });
115
+ }
108
116
  let analysis = await analyzeModuleSource(sourceText, resolvedPath, transformOptions, {
109
117
  define: args.define ?? undefined,
110
118
  minify: args.minify,
119
+ loaders: args.loaders,
120
+ moduleUrl: stableUrlPathname,
111
121
  sourceMaps: args.sourceMaps ?? undefined,
112
122
  target: args.target ?? undefined,
113
123
  });
@@ -119,12 +129,6 @@ export async function transformModule(record, args) {
119
129
  code: 'COMMONJS_NOT_SUPPORTED',
120
130
  });
121
131
  }
122
- let stableUrlPathname = args.routes.toUrlPathname(record.identityPath);
123
- if (!stableUrlPathname) {
124
- throw createAssetServerCompilationError(`File ${record.identityPath} is outside all configured fileMap entries.`, {
125
- code: 'FILE_OUTSIDE_FILE_MAP',
126
- });
127
- }
128
132
  let sourceMap = analysis.sourceMap
129
133
  ? rewriteSourceMapSources(analysis.sourceMap, resolvedPath, stableUrlPathname, args.sourceMapSourcePaths, sourceText)
130
134
  : null;
@@ -140,6 +144,7 @@ export async function transformModule(record, args) {
140
144
  buildId: args.buildId,
141
145
  content: sourceText,
142
146
  }),
147
+ hmr: getHmrAnalysis(analysis.rawCode),
143
148
  identityPath: record.identityPath,
144
149
  importerDir: path.dirname(resolvedPath),
145
150
  packageSpecifiers: analysis.unresolvedImports
@@ -164,6 +169,105 @@ export async function transformModule(record, args) {
164
169
  };
165
170
  }
166
171
  }
172
+ export function getHmrAnalysis(rawCode) {
173
+ let mayUseImportMetaHot = rawCode.includes('import.meta.hot');
174
+ let usesImportMetaHot = false;
175
+ let acceptedDeps = [];
176
+ let selfAccepting = false;
177
+ if (mayUseImportMetaHot) {
178
+ try {
179
+ let parseResult = parseSync('hmr-analysis.js', rawCode, {
180
+ lang: 'js',
181
+ sourceType: 'module',
182
+ });
183
+ if (parseResult.errors.length > 0) {
184
+ throw createAssetServerCompilationError(`Failed to analyze HMR usage in transformed script. ${parseResult.errors[0]?.message ?? 'Unknown parse error'}`, {
185
+ code: 'TRANSFORM_FAILED',
186
+ });
187
+ }
188
+ walkAst(parseResult.program, (node) => {
189
+ if (isImportMetaHotNode(node)) {
190
+ usesImportMetaHot = true;
191
+ }
192
+ if (node.type !== 'CallExpression')
193
+ return;
194
+ if (!isImportMetaHotAcceptCallee(node.callee))
195
+ return;
196
+ let [firstArgument] = node.arguments;
197
+ if (firstArgument === undefined || !isAcceptedDependencyArgument(firstArgument)) {
198
+ selfAccepting = true;
199
+ return;
200
+ }
201
+ acceptedDeps.push(...getAcceptedDependencies(firstArgument, rawCode));
202
+ });
203
+ }
204
+ catch (error) {
205
+ if (isAssetServerCompilationError(error))
206
+ throw error;
207
+ throw createAssetServerCompilationError(`Failed to analyze HMR usage in transformed script.`, {
208
+ cause: error,
209
+ code: 'TRANSFORM_FAILED',
210
+ });
211
+ }
212
+ }
213
+ return {
214
+ acceptedDeps,
215
+ selfAccepting,
216
+ usesImportMetaHot,
217
+ };
218
+ }
219
+ function isImportMetaHotAcceptCallee(node) {
220
+ let callee = unwrapChainExpression(node);
221
+ if (callee.type !== 'MemberExpression')
222
+ return false;
223
+ if (callee.computed || !isIdentifierNode(callee.property, 'accept'))
224
+ return false;
225
+ return isImportMetaHotNode(callee.object);
226
+ }
227
+ function isImportMetaHotNode(node) {
228
+ let hot = unwrapChainExpression(node);
229
+ if (hot.type !== 'MemberExpression')
230
+ return false;
231
+ if (hot.computed || !isIdentifierNode(hot.property, 'hot'))
232
+ return false;
233
+ let meta = unwrapChainExpression(hot.object);
234
+ return (meta.type === 'MetaProperty' &&
235
+ isIdentifierNode(meta.meta, 'import') &&
236
+ isIdentifierNode(meta.property, 'meta'));
237
+ }
238
+ function unwrapChainExpression(node) {
239
+ return node.type === 'ChainExpression' ? node.expression : node;
240
+ }
241
+ function isIdentifierNode(node, name) {
242
+ return node.type === 'Identifier' && node.name === name;
243
+ }
244
+ function isAcceptedDependencyArgument(node) {
245
+ return isStringLiteralNode(node) || node.type === 'ArrayExpression';
246
+ }
247
+ function getAcceptedDependencies(node, source) {
248
+ if (isStringLiteralNode(node)) {
249
+ return [
250
+ {
251
+ end: node.end - 1,
252
+ specifier: node.value,
253
+ start: node.start + 1,
254
+ },
255
+ ];
256
+ }
257
+ if (node.type !== 'ArrayExpression')
258
+ return [];
259
+ let deps = [];
260
+ for (let element of node.elements) {
261
+ if (!isStringLiteralNode(element))
262
+ continue;
263
+ deps.push({
264
+ end: element.end - 1,
265
+ specifier: element.value,
266
+ start: element.start + 1,
267
+ });
268
+ }
269
+ return deps;
270
+ }
167
271
  function findNearestTsconfigPath(directory) {
168
272
  let currentDirectory = directory;
169
273
  while (true) {
@@ -203,6 +307,38 @@ async function analyzeModuleSource(sourceText, resolvedPath, transformOptions, o
203
307
  }
204
308
  let rawCode = transformResult.code.trimEnd();
205
309
  let sourceMap = stringifySourceMap(transformResult.map);
310
+ if (options.loaders.length > 0) {
311
+ let loaderUrl = pathToFileURL(resolvedPath).href;
312
+ let loaderInputSource = sourceMap ? appendInlineSourceMap(rawCode, sourceMap) : rawCode;
313
+ let loaderOutputSource;
314
+ try {
315
+ let loaderResult = runModuleLoaders(loaderUrl, {
316
+ format: 'module',
317
+ loaders: options.loaders,
318
+ moduleUrl: options.moduleUrl,
319
+ source: loaderInputSource,
320
+ });
321
+ loaderOutputSource = moduleLoadSourceToString(getModuleLoadSource(loaderUrl, loaderResult));
322
+ }
323
+ catch (error) {
324
+ if (isAssetServerCompilationError(error))
325
+ throw error;
326
+ throw createAssetServerCompilationError(`Module loader failed for ${loaderUrl}. ${formatUnknownError(error)}`, {
327
+ cause: error,
328
+ code: 'LOADER_FAILED',
329
+ });
330
+ }
331
+ if (loaderOutputSource !== loaderInputSource) {
332
+ let loaderOutput = extractInlineSourceMap(loaderOutputSource);
333
+ rawCode = loaderOutput.code.trimEnd();
334
+ sourceMap =
335
+ loaderOutput.sourceMap && loaderOutput.sourceMap !== sourceMap
336
+ ? sourceMap
337
+ ? composeSourceMaps(loaderOutput.sourceMap, sourceMap)
338
+ : loaderOutput.sourceMap
339
+ : null;
340
+ }
341
+ }
206
342
  if (options.minify) {
207
343
  let minifyResult = await minifyModule(rawCode, resolvedPath, options.target, options.sourceMaps);
208
344
  rawCode = minifyResult.code.trimEnd();
@@ -220,6 +356,76 @@ async function analyzeModuleSource(sourceText, resolvedPath, transformOptions, o
220
356
  unresolvedImports: await getUnresolvedImportsFromLexer(rawCode),
221
357
  };
222
358
  }
359
+ function runModuleLoaders(url, options) {
360
+ let loadContext = {
361
+ conditions: [...scriptLoaderConditions],
362
+ format: options.format,
363
+ importAttributes: {},
364
+ moduleUrl: options.moduleUrl,
365
+ };
366
+ let load = (_url, context) => ({
367
+ format: context?.format ?? options.format,
368
+ source: options.source,
369
+ });
370
+ for (let loader of options.loaders) {
371
+ let nextLoad = load;
372
+ load = (nextUrl, nextContext) => {
373
+ let nextLoadCalled = false;
374
+ let wrappedNextLoad = (wrappedUrl, wrappedContext) => {
375
+ if (wrappedUrl !== nextUrl) {
376
+ throw createAssetServerCompilationError(`Module loader for ${nextUrl} attempted to change the module URL to ${wrappedUrl}. Loaders cannot change module URLs.`, {
377
+ code: 'LOADER_FAILED',
378
+ });
379
+ }
380
+ nextLoadCalled = true;
381
+ return nextLoad(wrappedUrl, wrappedContext);
382
+ };
383
+ let result = loader(nextUrl, {
384
+ conditions: nextContext?.conditions ?? loadContext.conditions,
385
+ format: nextContext?.format ?? loadContext.format,
386
+ importAttributes: nextContext?.importAttributes ?? loadContext.importAttributes,
387
+ moduleUrl: nextContext?.moduleUrl ?? loadContext.moduleUrl,
388
+ }, wrappedNextLoad);
389
+ if (!nextLoadCalled && result.shortCircuit !== true) {
390
+ throw createAssetServerCompilationError(`Module loader for ${nextUrl} returned without calling nextLoad or setting shortCircuit: true.`, {
391
+ code: 'LOADER_FAILED',
392
+ });
393
+ }
394
+ return result;
395
+ };
396
+ }
397
+ return load(url, loadContext);
398
+ }
399
+ function getModuleLoadSource(url, result) {
400
+ if (result.format !== 'module') {
401
+ throw createAssetServerCompilationError(`Module loader for ${url} returned unsupported format ${JSON.stringify(result.format)}. Only "module" is supported.`, {
402
+ code: 'LOADER_FAILED',
403
+ });
404
+ }
405
+ if (result.source !== undefined && result.source !== null)
406
+ return result.source;
407
+ throw createAssetServerCompilationError(`Module loader for ${url} did not return source.`, {
408
+ code: 'LOADER_FAILED',
409
+ });
410
+ }
411
+ function moduleLoadSourceToString(source) {
412
+ if (typeof source === 'string')
413
+ return source;
414
+ return new TextDecoder().decode(source);
415
+ }
416
+ function appendInlineSourceMap(source, sourceMap) {
417
+ let encoded = Buffer.from(sourceMap).toString('base64');
418
+ return `${source}\n//# sourceMappingURL=data:application/json;base64,${encoded}`;
419
+ }
420
+ function extractInlineSourceMap(source) {
421
+ let sourceMapPattern = /(?:\/\/# sourceMappingURL=data:application\/json;base64,([A-Za-z0-9+/=]+)|\/\*# sourceMappingURL=data:application\/json;base64,([A-Za-z0-9+/=]+) \*\/)\s*$/g;
422
+ let sourceMap = null;
423
+ let code = source.replace(sourceMapPattern, (_match, lineComment, blockComment) => {
424
+ sourceMap = Buffer.from(lineComment ?? blockComment, 'base64').toString('utf-8');
425
+ return '';
426
+ });
427
+ return { code, sourceMap };
428
+ }
223
429
  async function minifyModule(rawCode, resolvedPath, target, sourceMaps) {
224
430
  try {
225
431
  let result = await minify(resolvedPath, rawCode, {
@@ -324,7 +530,7 @@ async function getUnresolvedImportsFromLexer(rawCode) {
324
530
  let unresolvedImports = [];
325
531
  for (let imported of imports) {
326
532
  let specifier = getStaticImportSpecifier(rawCode, imported);
327
- if (specifier == null || shouldSkipImportSpecifier(specifier))
533
+ if (specifier == null || isBrowserExternalModuleUrl(specifier))
328
534
  continue;
329
535
  unresolvedImports.push({
330
536
  specifier,
@@ -338,6 +544,9 @@ async function getUnresolvedImportsFromLexer(rawCode) {
338
544
  function getDisplayImportSpecifier(specifier) {
339
545
  return restoreAuthoredInjectedPackageSpecifier(specifier) ?? specifier;
340
546
  }
547
+ function isBrowserExternalModuleUrl(url) {
548
+ return url.startsWith('data:') || url.startsWith('http://') || url.startsWith('https://');
549
+ }
341
550
  function maskAuthoredInjectedPackageImports(sourceText, resolvedPath) {
342
551
  if (!mayContainInjectedPackageSpecifier(sourceText)) {
343
552
  return sourceText;
@@ -423,11 +632,6 @@ function getStaticImportSpecifier(source, imported) {
423
632
  function isStaticTemplateLiteral(specifier) {
424
633
  return specifier.startsWith('`') && specifier.endsWith('`') && !specifier.includes('${');
425
634
  }
426
- function shouldSkipImportSpecifier(specifier) {
427
- return (specifier.startsWith('data:') ||
428
- specifier.startsWith('http://') ||
429
- specifier.startsWith('https://'));
430
- }
431
635
  function getImportQuote(source, start) {
432
636
  let firstCharacter = source[start];
433
637
  if (firstCharacter === '"' || firstCharacter === "'" || firstCharacter === '`') {
@@ -1,5 +1,5 @@
1
1
  import { SourceMapConsumer, SourceMapGenerator } from 'source-map-js';
2
- import { normalizeFilePath } from "./paths.js";
2
+ import { normalizeFilePath } from './paths.js';
3
3
  export function composeSourceMaps(rewriteSourceMap, transformSourceMap) {
4
4
  let rewriteConsumer = new SourceMapConsumer(JSON.parse(rewriteSourceMap));
5
5
  let transformConsumer = new SourceMapConsumer(JSON.parse(transformSourceMap));
@@ -24,6 +24,9 @@ type StyleCompilerOptions = {
24
24
  getServedFileUrl?(identityPath: string, options: {
25
25
  transform: readonly string[] | null;
26
26
  }): Promise<string>;
27
+ hmr?: {
28
+ send(pathname: string, timestamp: number): void;
29
+ };
27
30
  isAllowed(absolutePath: string): boolean;
28
31
  isServedFilePath(filePath: string): boolean;
29
32
  minify: boolean;
@@ -31,6 +34,10 @@ type StyleCompilerOptions = {
31
34
  add: string[];
32
35
  remove: string[];
33
36
  }) => void;
37
+ onWatchFilesChange?: (delta: {
38
+ add: string[];
39
+ remove: string[];
40
+ }) => void;
34
41
  rootDir: string;
35
42
  routes: CompiledRoutes;
36
43
  sourceMapSourcePaths: 'absolute' | 'url';
@@ -42,7 +49,13 @@ type StyleCompiler = {
42
49
  getHref(filePath: string): Promise<string>;
43
50
  getPreloadLayers(filePath: string | readonly string[]): Promise<string[][]>;
44
51
  getStyle(filePath: string, options: StyleGetOptions): Promise<StyleGetResult>;
45
- handleFileEvent(filePath: string, event: 'add' | 'change' | 'unlink'): Promise<void>;
52
+ classifyHmrFileEvent(filePath: string, event: 'add' | 'change' | 'unlink'): Promise<StyleHmrUpdate[]>;
53
+ invalidateFileEvent(filePath: string, event: 'add' | 'change' | 'unlink'): void;
54
+ };
55
+ export type StyleHmrUpdate = {
56
+ filePath: string;
57
+ path: string;
58
+ timestamp: number;
46
59
  };
47
60
  export declare function createStyleCompiler(options: StyleCompilerOptions): StyleCompiler;
48
61
  export declare function isStyleFilePath(filePath: string): boolean;
@@ -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,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"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/compiler.ts"],"names":[],"mappings":"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"}