@remix-run/assets 0.6.0 → 0.7.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.
- package/README.md +101 -13
- package/dist/assets.d.ts +2 -1
- package/dist/assets.d.ts.map +1 -1
- package/dist/lib/asset-server.d.ts +41 -19
- package/dist/lib/asset-server.d.ts.map +1 -1
- package/dist/lib/asset-server.js +98 -41
- package/dist/lib/compilation-error.d.ts +1 -1
- package/dist/lib/compilation-error.d.ts.map +1 -1
- package/dist/lib/files/compiler.d.ts +1 -1
- package/dist/lib/files/compiler.d.ts.map +1 -1
- package/dist/lib/files/compiler.js +26 -29
- package/dist/lib/files/config.d.ts +6 -0
- package/dist/lib/files/config.d.ts.map +1 -1
- package/dist/lib/files/config.js +9 -0
- package/dist/lib/fingerprint.d.ts +0 -4
- package/dist/lib/fingerprint.d.ts.map +1 -1
- package/dist/lib/fingerprint.js +0 -4
- package/dist/lib/hmr.d.ts +7 -0
- package/dist/lib/hmr.d.ts.map +1 -1
- package/dist/lib/hmr.js +198 -25
- package/dist/lib/routes.d.ts +1 -0
- package/dist/lib/routes.d.ts.map +1 -1
- package/dist/lib/routes.js +1 -1
- package/dist/lib/scripts/compiler.d.ts +8 -2
- package/dist/lib/scripts/compiler.d.ts.map +1 -1
- package/dist/lib/scripts/compiler.js +186 -36
- package/dist/lib/scripts/emit.d.ts +2 -1
- package/dist/lib/scripts/emit.d.ts.map +1 -1
- package/dist/lib/scripts/emit.js +25 -16
- package/dist/lib/scripts/resolve.d.ts +7 -1
- package/dist/lib/scripts/resolve.d.ts.map +1 -1
- package/dist/lib/scripts/resolve.js +110 -3
- package/dist/lib/scripts/specifiers.d.ts +2 -0
- package/dist/lib/scripts/specifiers.d.ts.map +1 -0
- package/dist/lib/scripts/specifiers.js +9 -0
- package/dist/lib/scripts/transform.d.ts +2 -3
- package/dist/lib/scripts/transform.d.ts.map +1 -1
- package/dist/lib/scripts/transform.js +2 -16
- package/dist/lib/styles/compiler.d.ts +0 -1
- package/dist/lib/styles/compiler.d.ts.map +1 -1
- package/dist/lib/styles/compiler.js +105 -25
- package/dist/lib/styles/emit.d.ts +2 -1
- package/dist/lib/styles/emit.d.ts.map +1 -1
- package/dist/lib/styles/emit.js +12 -10
- package/dist/lib/styles/resolve.d.ts +0 -1
- package/dist/lib/styles/resolve.d.ts.map +1 -1
- package/dist/lib/styles/resolve.js +0 -1
- package/dist/lib/styles/transform.d.ts +0 -2
- package/dist/lib/styles/transform.d.ts.map +1 -1
- package/dist/lib/styles/transform.js +0 -7
- package/dist/lib/virtual-store.d.ts +8 -0
- package/dist/lib/virtual-store.d.ts.map +1 -0
- package/dist/lib/virtual-store.js +100 -0
- package/package.json +6 -5
- package/src/assets.ts +7 -1
- package/src/lib/asset-server.ts +175 -73
- package/src/lib/compilation-error.ts +1 -0
- package/src/lib/files/compiler.ts +30 -40
- package/src/lib/files/config.ts +17 -0
- package/src/lib/fingerprint.ts +0 -9
- package/src/lib/hmr.ts +210 -26
- package/src/lib/routes.ts +1 -1
- package/src/lib/scripts/compiler.ts +238 -52
- package/src/lib/scripts/emit.ts +34 -19
- package/src/lib/scripts/resolve.ts +166 -4
- package/src/lib/scripts/specifiers.ts +11 -0
- package/src/lib/scripts/transform.ts +4 -23
- package/src/lib/styles/compiler.ts +137 -39
- package/src/lib/styles/emit.ts +18 -13
- package/src/lib/styles/resolve.ts +0 -2
- package/src/lib/styles/transform.ts +0 -10
- package/src/lib/virtual-store.ts +124 -0
package/src/lib/asset-server.ts
CHANGED
|
@@ -23,7 +23,7 @@ import { normalizeFilePath, normalizePathname } from './paths.ts'
|
|
|
23
23
|
import { compileRoutes } from './routes.ts'
|
|
24
24
|
import type { CompiledRoutes } from './routes.ts'
|
|
25
25
|
import { createResponseForScript, createScriptCompiler } from './scripts/compiler.ts'
|
|
26
|
-
import type { ScriptHmrUpdate } from './scripts/compiler.ts'
|
|
26
|
+
import type { ScriptHmrUpdate, ScriptImportMap } from './scripts/compiler.ts'
|
|
27
27
|
import { supportedScriptExtensions } from './scripts/resolve.ts'
|
|
28
28
|
import { createResponseForStyle, createStyleCompiler, isStyleFilePath } from './styles/compiler.ts'
|
|
29
29
|
import { resolveScriptTarget, resolveStyleTarget } from './target.ts'
|
|
@@ -31,6 +31,7 @@ import type { AssetTarget, ResolvedScriptTarget, ResolvedStyleTarget } from './t
|
|
|
31
31
|
import { createAssetServerWatcher } from './watch.ts'
|
|
32
32
|
import { createAssetInspector, type AssetDetails } from './inspection.ts'
|
|
33
33
|
import type { AssetServerWatcher, ChokidarWatcher } from './watch.ts'
|
|
34
|
+
import { getVirtualStoreMountConfigs } from './virtual-store.ts'
|
|
34
35
|
|
|
35
36
|
interface AssetServerWatchOptions {
|
|
36
37
|
/**
|
|
@@ -90,6 +91,18 @@ export type BrowserHmrChannelFactory = () =>
|
|
|
90
91
|
| undefined
|
|
91
92
|
| Promise<BrowserHmrChannel | undefined>
|
|
92
93
|
|
|
94
|
+
/** Browser HMR integration options. */
|
|
95
|
+
export interface BrowserHmrOptions {
|
|
96
|
+
/** Creates the channel that delivers browser HMR events. */
|
|
97
|
+
channel: BrowserHmrChannelFactory
|
|
98
|
+
/**
|
|
99
|
+
* Module specifier resolved relative to the asset server's root directory. It must point to a
|
|
100
|
+
* browser module exporting `importModule(specifier, parentUrl)` for evaluating JavaScript updates.
|
|
101
|
+
* The module and its dependencies must be allowed and reachable through configured mounts.
|
|
102
|
+
*/
|
|
103
|
+
moduleImporter?: string
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
/**
|
|
94
107
|
* Converts a watcher batch into ordered browser update or reload events.
|
|
95
108
|
*
|
|
@@ -125,14 +138,12 @@ export type BrowserHmrFileEvent = {
|
|
|
125
138
|
*/
|
|
126
139
|
export type BrowserHmrEvent =
|
|
127
140
|
| {
|
|
141
|
+
/** Consumer-owned data keyed by a stable, versioned namespace. */
|
|
142
|
+
data: Record<string, BrowserHmrData>
|
|
128
143
|
/** Absolute source file paths that triggered this update. */
|
|
129
144
|
files?: string[]
|
|
130
|
-
/** Update time used to bypass browser module and stylesheet caches. */
|
|
131
|
-
timestamp: number
|
|
132
145
|
/** Browser update event. */
|
|
133
146
|
type: 'update'
|
|
134
|
-
/** Accepted JavaScript and CSS module updates for the browser to apply in place. */
|
|
135
|
-
updates: Extract<HmrPayload, { type: 'browser:update' }>['updates']
|
|
136
147
|
}
|
|
137
148
|
| {
|
|
138
149
|
/** Absolute source file paths that could not be handled in place. */
|
|
@@ -141,16 +152,15 @@ export type BrowserHmrEvent =
|
|
|
141
152
|
type: 'reload'
|
|
142
153
|
}
|
|
143
154
|
|
|
144
|
-
interface FingerprintOptions {
|
|
145
|
-
/**
|
|
146
|
-
* Per-build invalidation token that must change whenever fingerprinted asset URLs
|
|
147
|
-
* should be invalidated together.
|
|
148
|
-
*/
|
|
149
|
-
buildId: string
|
|
150
|
-
}
|
|
151
|
-
|
|
152
155
|
type AssetSourceMaps = 'inline' | 'external'
|
|
153
156
|
type AssetSourceMapSourcePaths = 'url' | 'absolute'
|
|
157
|
+
type BrowserHmrData =
|
|
158
|
+
| null
|
|
159
|
+
| boolean
|
|
160
|
+
| number
|
|
161
|
+
| string
|
|
162
|
+
| BrowserHmrData[]
|
|
163
|
+
| { [key: string]: BrowserHmrData }
|
|
154
164
|
|
|
155
165
|
interface AssetServerScriptOptions {
|
|
156
166
|
/**
|
|
@@ -158,7 +168,7 @@ interface AssetServerScriptOptions {
|
|
|
158
168
|
* `{ 'process.env.NODE_ENV': '"production"' }`
|
|
159
169
|
*/
|
|
160
170
|
define?: Record<string, string>
|
|
161
|
-
/** Import specifiers to
|
|
171
|
+
/** Import specifiers to treat as external dependencies (CDN URLs, import map entries, etc.) */
|
|
162
172
|
external?: string[]
|
|
163
173
|
/**
|
|
164
174
|
* Synchronous loaders that post-process compiled JavaScript.
|
|
@@ -210,12 +220,12 @@ export interface AssetServerOptions<transforms extends AssetRequestTransformMap
|
|
|
210
220
|
*/
|
|
211
221
|
denyFiles?: readonly string[]
|
|
212
222
|
/**
|
|
213
|
-
* Controls optional
|
|
223
|
+
* Controls optional content-based URL fingerprinting for served asset URLs.
|
|
214
224
|
*
|
|
215
225
|
* When omitted, all served assets use stable non-fingerprinted URLs with `Cache-Control: no-cache`.
|
|
216
226
|
* Cannot be used together with active watch mode. Set `watch: false` when fingerprinting.
|
|
217
227
|
*/
|
|
218
|
-
fingerprint?:
|
|
228
|
+
fingerprint?: boolean
|
|
219
229
|
/**
|
|
220
230
|
* Shared compatibility target for scripts and styles. Browser targets apply to both
|
|
221
231
|
* pipelines, and `es` only affects scripts.
|
|
@@ -253,7 +263,7 @@ export interface AssetServerOptions<transforms extends AssetRequestTransformMap
|
|
|
253
263
|
* HMR requires `watch` to be enabled. The factory is called once for this asset server. Returning
|
|
254
264
|
* `undefined` leaves HMR inactive; a returned channel is closed by `assetServer.close()`.
|
|
255
265
|
*/
|
|
256
|
-
hmr?: BrowserHmrChannelFactory
|
|
266
|
+
hmr?: BrowserHmrChannelFactory | BrowserHmrOptions
|
|
257
267
|
/**
|
|
258
268
|
* Enable filesystem-backed cache invalidation for long-lived server instances.
|
|
259
269
|
* Enabled by default. Pass `true` to use the default watcher options, an options
|
|
@@ -282,6 +292,18 @@ export type AssetServerGetHrefOptions<transforms extends AssetRequestTransformMa
|
|
|
282
292
|
transform: readonly AssetTransformInvocation<transforms>[]
|
|
283
293
|
}
|
|
284
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Metadata needed to render or load a script entry module.
|
|
297
|
+
*/
|
|
298
|
+
export interface ScriptEntry {
|
|
299
|
+
/** Public URL for the script entry module. */
|
|
300
|
+
href: string
|
|
301
|
+
/** Public URLs that should be emitted as `modulepreload` hints for this script graph. */
|
|
302
|
+
preloads: string[]
|
|
303
|
+
/** Import map entries required to resolve this script graph in the browser. */
|
|
304
|
+
importMap: ScriptImportMap
|
|
305
|
+
}
|
|
306
|
+
|
|
285
307
|
/**
|
|
286
308
|
* Serves compiled scripts and styles for asset requests routed to it.
|
|
287
309
|
* Construct with {@link createAssetServer}.
|
|
@@ -296,10 +318,18 @@ export interface AssetServer<transforms extends AssetRequestTransformMap = {}> {
|
|
|
296
318
|
* Returns the request href for a served asset file.
|
|
297
319
|
*/
|
|
298
320
|
getHref(filePath: string, options?: AssetServerGetHrefOptions<transforms>): Promise<string>
|
|
321
|
+
/**
|
|
322
|
+
* Returns the href, preload URLs, and import map for a script entry module.
|
|
323
|
+
*/
|
|
324
|
+
getScriptEntry(filePath: string): Promise<ScriptEntry>
|
|
299
325
|
/**
|
|
300
326
|
* Returns preload URLs for one or more served asset files, ordered shallowest-first.
|
|
301
327
|
*/
|
|
302
328
|
getPreloads(filePath: string | readonly string[]): Promise<string[]>
|
|
329
|
+
/**
|
|
330
|
+
* Returns an import map for one or more script entry modules.
|
|
331
|
+
*/
|
|
332
|
+
getImportMap(filePath: string | readonly string[]): Promise<ScriptImportMap>
|
|
303
333
|
/**
|
|
304
334
|
* Returns diagnostic details about one public asset URL or file path, including the matched mount
|
|
305
335
|
* roots, access rules, file type, and browser-reachability status.
|
|
@@ -322,13 +352,13 @@ type ResolvedAssetServerOptions<transforms extends AssetRequestTransformMap> = {
|
|
|
322
352
|
allowFiles: readonly string[]
|
|
323
353
|
allowPackages?: readonly string[]
|
|
324
354
|
basePath: string
|
|
325
|
-
buildId?: string
|
|
326
355
|
define?: Record<string, string>
|
|
327
356
|
denyFiles?: readonly string[]
|
|
328
357
|
external: string[]
|
|
329
358
|
files: ResolvedAssetServerFilesOptions
|
|
330
359
|
fingerprintAssets: boolean
|
|
331
360
|
hmr: BrowserHmrChannelFactory | null
|
|
361
|
+
hmrModuleImporter: string | null
|
|
332
362
|
minify: boolean
|
|
333
363
|
loaders: readonly ModuleLoader[]
|
|
334
364
|
onError: NonNullable<AssetServerOptions['onError']>
|
|
@@ -361,7 +391,7 @@ export function getInternalWatchTargets<transforms extends AssetRequestTransform
|
|
|
361
391
|
* Create an asset server instance
|
|
362
392
|
*
|
|
363
393
|
* Compiles TypeScript/JavaScript scripts and CSS styles on demand with optional
|
|
364
|
-
*
|
|
394
|
+
* content-based URL fingerprinting, caching, and configurable directory mounts.
|
|
365
395
|
*
|
|
366
396
|
* @param options Server configuration
|
|
367
397
|
* @returns A {@link AssetServer} with `fetch()`, `getHref()`, and `getPreloads()` methods
|
|
@@ -418,8 +448,8 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
418
448
|
})
|
|
419
449
|
let sendHmrPayload = resolvedOptions.hmr ? createHmrPayloadSender() : null
|
|
420
450
|
let hmrPathnames = getHmrPathnames(resolvedOptions.basePath)
|
|
451
|
+
let hmrDataKey = `remix/assets@1:${resolvedOptions.basePath}`
|
|
421
452
|
let scriptCompiler = createScriptCompiler({
|
|
422
|
-
buildId: resolvedOptions.buildId,
|
|
423
453
|
define: resolvedOptions.define,
|
|
424
454
|
external: resolvedOptions.external,
|
|
425
455
|
fingerprintAssets: resolvedOptions.fingerprintAssets,
|
|
@@ -451,7 +481,6 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
451
481
|
watchMode: resolvedOptions.watchOptions !== null,
|
|
452
482
|
})
|
|
453
483
|
let styleCompiler = createStyleCompiler({
|
|
454
|
-
buildId: resolvedOptions.buildId,
|
|
455
484
|
fingerprintAssets: resolvedOptions.fingerprintAssets,
|
|
456
485
|
getServedFileUrl: (identityPath: string, options: { transform: readonly string[] | null }) => {
|
|
457
486
|
if (!fileCompiler) {
|
|
@@ -503,8 +532,8 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
503
532
|
})
|
|
504
533
|
if (resolvedOptions.files.extensions.length > 0) {
|
|
505
534
|
fileCompiler = createFileCompiler({
|
|
506
|
-
buildId: resolvedOptions.buildId,
|
|
507
535
|
cache: resolvedOptions.files.cache,
|
|
536
|
+
cacheKey: resolvedOptions.files.cacheKey,
|
|
508
537
|
extensions: resolvedOptions.files.extensions,
|
|
509
538
|
fingerprintAssets: resolvedOptions.fingerprintAssets,
|
|
510
539
|
globalTransforms: resolvedOptions.files.globalTransforms,
|
|
@@ -558,10 +587,10 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
558
587
|
for (let event of events) {
|
|
559
588
|
let normalizedFilePath = normalizeFilePath(event.filePath)
|
|
560
589
|
let scriptUpdates = await scriptCompiler.classifyHmrFileEvent(normalizedFilePath, event.event)
|
|
561
|
-
let scriptPayload =
|
|
590
|
+
let scriptPayload = await createScriptHmrPayloadWithImportMaps(scriptUpdates)
|
|
562
591
|
if (scriptPayload) {
|
|
563
592
|
browserHmrEvents.push(
|
|
564
|
-
createBrowserHmrEvent(scriptPayload, getScriptHmrUpdateFiles(scriptUpdates)),
|
|
593
|
+
createBrowserHmrEvent(scriptPayload, getScriptHmrUpdateFiles(scriptUpdates), hmrDataKey),
|
|
565
594
|
)
|
|
566
595
|
}
|
|
567
596
|
|
|
@@ -580,6 +609,7 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
580
609
|
],
|
|
581
610
|
},
|
|
582
611
|
[styleUpdate.filePath],
|
|
612
|
+
hmrDataKey,
|
|
583
613
|
),
|
|
584
614
|
)
|
|
585
615
|
}
|
|
@@ -588,6 +618,32 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
588
618
|
}
|
|
589
619
|
|
|
590
620
|
return browserHmrEvents
|
|
621
|
+
|
|
622
|
+
async function createScriptHmrPayloadWithImportMaps(
|
|
623
|
+
updates: ScriptHmrUpdate[],
|
|
624
|
+
): Promise<Extract<HmrPayload, { type: 'browser:reload' | 'browser:update' }> | null> {
|
|
625
|
+
let payload = createScriptHmrPayload(updates)
|
|
626
|
+
if (!payload || payload.type === 'browser:reload') return payload
|
|
627
|
+
|
|
628
|
+
let acceptedUpdates = updates.filter((update) => update.accepted)
|
|
629
|
+
let importMaps = await Promise.all(
|
|
630
|
+
acceptedUpdates.map(async (update) => {
|
|
631
|
+
try {
|
|
632
|
+
return await scriptCompiler.getImportMap(update.acceptedFilePath)
|
|
633
|
+
} catch (error) {
|
|
634
|
+
if (!isAssetServerCompilationError(error)) throw error
|
|
635
|
+
return undefined
|
|
636
|
+
}
|
|
637
|
+
}),
|
|
638
|
+
)
|
|
639
|
+
return {
|
|
640
|
+
...payload,
|
|
641
|
+
updates: payload.updates.map((update, index) => ({
|
|
642
|
+
...update,
|
|
643
|
+
...(importMaps[index] ? { importMap: importMaps[index] } : null),
|
|
644
|
+
})),
|
|
645
|
+
}
|
|
646
|
+
}
|
|
591
647
|
}
|
|
592
648
|
|
|
593
649
|
function updateBrowserHmrWatchedFiles(delta: BrowserHmrWatchedFileDelta): void {
|
|
@@ -615,7 +671,13 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
615
671
|
if (requestPathname === hmrPathnames.client) {
|
|
616
672
|
let browserHmrChannel = await browserHmrChannelPromise
|
|
617
673
|
assertBrowserEventUrl(browserHmrChannel?.url)
|
|
618
|
-
return createHmrClientResponse(
|
|
674
|
+
return await createHmrClientResponse(
|
|
675
|
+
browserHmrChannel.url,
|
|
676
|
+
hmrDataKey,
|
|
677
|
+
resolvedOptions.hmrModuleImporter,
|
|
678
|
+
request.method,
|
|
679
|
+
scriptCompiler,
|
|
680
|
+
)
|
|
619
681
|
}
|
|
620
682
|
}
|
|
621
683
|
|
|
@@ -651,8 +713,10 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
651
713
|
let compiledStyle = styleResult.style
|
|
652
714
|
|
|
653
715
|
if (parsedRequestPathname.requestedFingerprint !== null) {
|
|
654
|
-
|
|
655
|
-
|
|
716
|
+
let fingerprint = parsedRequestPathname.isSourceMapRequest
|
|
717
|
+
? compiledStyle.sourceMap?.fingerprint
|
|
718
|
+
: compiledStyle.fingerprint
|
|
719
|
+
if (fingerprint !== parsedRequestPathname.requestedFingerprint) return null
|
|
656
720
|
}
|
|
657
721
|
|
|
658
722
|
return createResponseForStyle(compiledStyle, {
|
|
@@ -716,7 +780,10 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
716
780
|
let compiledScript = scriptResult.script
|
|
717
781
|
|
|
718
782
|
if (parsedRequestPathname.requestedFingerprint !== null) {
|
|
719
|
-
|
|
783
|
+
let fingerprint = parsedRequestPathname.isSourceMapRequest
|
|
784
|
+
? compiledScript.sourceMap?.fingerprint
|
|
785
|
+
: compiledScript.fingerprint
|
|
786
|
+
if (fingerprint !== parsedRequestPathname.requestedFingerprint) return null
|
|
720
787
|
}
|
|
721
788
|
|
|
722
789
|
return createResponseForScript(compiledScript, {
|
|
@@ -779,6 +846,15 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
779
846
|
|
|
780
847
|
return scriptCompiler.getHref(filePath)
|
|
781
848
|
},
|
|
849
|
+
async getScriptEntry(filePath) {
|
|
850
|
+
let [href, preloads, importMap] = await Promise.all([
|
|
851
|
+
assetServer.getHref(filePath),
|
|
852
|
+
assetServer.getPreloads(filePath),
|
|
853
|
+
assetServer.getImportMap(filePath),
|
|
854
|
+
])
|
|
855
|
+
|
|
856
|
+
return { href, preloads, importMap }
|
|
857
|
+
},
|
|
782
858
|
async getPreloads(filePath) {
|
|
783
859
|
let filePaths = Array.isArray(filePath) ? filePath : [filePath]
|
|
784
860
|
let fileAssetFiles: string[] = []
|
|
@@ -843,6 +919,19 @@ export function createAssetServer<const transforms extends AssetRequestTransform
|
|
|
843
919
|
|
|
844
920
|
return mergePreloadLayers(await Promise.all(preloadLayerGroupPromises))
|
|
845
921
|
},
|
|
922
|
+
async getImportMap(filePath) {
|
|
923
|
+
let filePaths = Array.isArray(filePath) ? filePath : [filePath]
|
|
924
|
+
for (let nextFilePath of filePaths) {
|
|
925
|
+
let typeCheckFilePath = stripFilePathUrlSuffix(nextFilePath)
|
|
926
|
+
if (!isScriptFilePath(typeCheckFilePath)) {
|
|
927
|
+
throw new TypeError(
|
|
928
|
+
`assetServer.getImportMap() only supports script files: ${nextFilePath}`,
|
|
929
|
+
)
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
return scriptCompiler.getImportMap(filePath)
|
|
934
|
+
},
|
|
846
935
|
async close() {
|
|
847
936
|
if (closed) return
|
|
848
937
|
closed = true
|
|
@@ -908,13 +997,27 @@ function getHmrPathnames(basePath: string): { client: string; events: string } {
|
|
|
908
997
|
}
|
|
909
998
|
}
|
|
910
999
|
|
|
911
|
-
function createHmrClientResponse(
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1000
|
+
async function createHmrClientResponse(
|
|
1001
|
+
eventPathname: string,
|
|
1002
|
+
dataKey: string,
|
|
1003
|
+
moduleImporter: string | null,
|
|
1004
|
+
method: string,
|
|
1005
|
+
scriptCompiler: ReturnType<typeof createScriptCompiler>,
|
|
1006
|
+
): Promise<Response> {
|
|
1007
|
+
let moduleImporterHref = moduleImporter
|
|
1008
|
+
? await scriptCompiler.resolveSpecifierFromRoot(moduleImporter)
|
|
1009
|
+
: null
|
|
1010
|
+
return new Response(
|
|
1011
|
+
method === 'HEAD'
|
|
1012
|
+
? null
|
|
1013
|
+
: createHmrClientSource({ dataKey, eventPathname, moduleImporter: moduleImporterHref }),
|
|
1014
|
+
{
|
|
1015
|
+
headers: {
|
|
1016
|
+
'Cache-Control': 'no-cache',
|
|
1017
|
+
'Content-Type': 'application/javascript; charset=utf-8',
|
|
1018
|
+
},
|
|
916
1019
|
},
|
|
917
|
-
|
|
1020
|
+
)
|
|
918
1021
|
}
|
|
919
1022
|
|
|
920
1023
|
function assertBrowserEventUrl(url: string | undefined): asserts url is string {
|
|
@@ -930,6 +1033,7 @@ function createHmrPayloadSender(): (payload: HmrPayload) => void {
|
|
|
930
1033
|
function createBrowserHmrEvent(
|
|
931
1034
|
payload: Extract<HmrPayload, { type: 'browser:reload' | 'browser:update' }>,
|
|
932
1035
|
files: readonly string[],
|
|
1036
|
+
dataKey: string,
|
|
933
1037
|
): BrowserHmrEvent {
|
|
934
1038
|
if (payload.type === 'browser:reload') {
|
|
935
1039
|
return {
|
|
@@ -939,10 +1043,14 @@ function createBrowserHmrEvent(
|
|
|
939
1043
|
}
|
|
940
1044
|
|
|
941
1045
|
return {
|
|
1046
|
+
data: {
|
|
1047
|
+
[dataKey]: {
|
|
1048
|
+
timestamp: payload.timestamp,
|
|
1049
|
+
updates: payload.updates,
|
|
1050
|
+
},
|
|
1051
|
+
},
|
|
942
1052
|
...(files.length === 0 ? {} : { files: [...files] }),
|
|
943
|
-
timestamp: payload.timestamp,
|
|
944
1053
|
type: 'update',
|
|
945
|
-
updates: payload.updates,
|
|
946
1054
|
}
|
|
947
1055
|
}
|
|
948
1056
|
|
|
@@ -968,7 +1076,9 @@ export function createScriptHmrPayload(
|
|
|
968
1076
|
timestamp,
|
|
969
1077
|
type: 'browser:update',
|
|
970
1078
|
updates: acceptedUpdates.map((update) => ({
|
|
971
|
-
...(update.
|
|
1079
|
+
...(update.acceptedUrlPathname === update.path
|
|
1080
|
+
? {}
|
|
1081
|
+
: { acceptedPath: update.acceptedUrlPathname }),
|
|
972
1082
|
path: update.path,
|
|
973
1083
|
type: 'js',
|
|
974
1084
|
})),
|
|
@@ -1032,15 +1142,15 @@ function resolveAssetServerOptions<transforms extends AssetRequestTransformMap>(
|
|
|
1032
1142
|
let rootDir = normalizeFilePath(fs.realpathSync(path.resolve(options.rootDir ?? process.cwd())))
|
|
1033
1143
|
let basePath = normalizeBasePath(options.basePath)
|
|
1034
1144
|
let scriptOptions = options.scripts ?? {}
|
|
1035
|
-
let
|
|
1145
|
+
let fingerprintAssets = normalizeFingerprintOptions({
|
|
1036
1146
|
fingerprint: options.fingerprint,
|
|
1037
1147
|
watch: options.watch,
|
|
1038
1148
|
})
|
|
1039
1149
|
let watchOptions = normalizeWatchOptions(options.watch)
|
|
1040
|
-
let
|
|
1150
|
+
let hmr = normalizeHmrOptions(options.hmr)
|
|
1041
1151
|
let mounts = options.mounts ?? defaultMounts
|
|
1042
1152
|
|
|
1043
|
-
if (
|
|
1153
|
+
if (hmr.channel && watchOptions === null) {
|
|
1044
1154
|
throw new TypeError('hmr requires watch mode')
|
|
1045
1155
|
}
|
|
1046
1156
|
if (Object.keys(mounts).length === 0) {
|
|
@@ -1050,13 +1160,13 @@ function resolveAssetServerOptions<transforms extends AssetRequestTransformMap>(
|
|
|
1050
1160
|
allowFiles: options.allowFiles,
|
|
1051
1161
|
allowPackages: options.allowPackages,
|
|
1052
1162
|
basePath,
|
|
1053
|
-
buildId: fingerprintOptions.buildId,
|
|
1054
1163
|
define: scriptOptions.define,
|
|
1055
1164
|
denyFiles: options.denyFiles,
|
|
1056
1165
|
external: scriptOptions.external ?? [],
|
|
1057
1166
|
files: normalizeFilesOptions(options.files),
|
|
1058
|
-
fingerprintAssets
|
|
1059
|
-
hmr:
|
|
1167
|
+
fingerprintAssets,
|
|
1168
|
+
hmr: hmr.channel,
|
|
1169
|
+
hmrModuleImporter: hmr.moduleImporter,
|
|
1060
1170
|
minify: options.minify ?? false,
|
|
1061
1171
|
mounts,
|
|
1062
1172
|
loaders: scriptOptions.loaders ?? [],
|
|
@@ -1068,6 +1178,7 @@ function resolveAssetServerOptions<transforms extends AssetRequestTransformMap>(
|
|
|
1068
1178
|
rootDir,
|
|
1069
1179
|
},
|
|
1070
1180
|
...getInjectedPackageMountConfigs(),
|
|
1181
|
+
...getVirtualStoreMountConfigs({ mounts, rootDir }),
|
|
1071
1182
|
]),
|
|
1072
1183
|
sourceMapSourcePaths: options.sourceMapSourcePaths ?? 'url',
|
|
1073
1184
|
sourceMaps: options.sourceMaps,
|
|
@@ -1077,14 +1188,22 @@ function resolveAssetServerOptions<transforms extends AssetRequestTransformMap>(
|
|
|
1077
1188
|
}
|
|
1078
1189
|
}
|
|
1079
1190
|
|
|
1080
|
-
function
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1191
|
+
function normalizeHmrOptions(options: AssetServerOptions['hmr']): {
|
|
1192
|
+
channel: BrowserHmrChannelFactory | null
|
|
1193
|
+
moduleImporter: string | null
|
|
1194
|
+
} {
|
|
1195
|
+
if (options === undefined) return { channel: null, moduleImporter: null }
|
|
1196
|
+
if (typeof options === 'function') return { channel: options, moduleImporter: null }
|
|
1197
|
+
if (!options || typeof options !== 'object' || typeof options.channel !== 'function') {
|
|
1198
|
+
throw new TypeError('hmr must be a function or an object with a channel function')
|
|
1085
1199
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1200
|
+
if (
|
|
1201
|
+
options.moduleImporter !== undefined &&
|
|
1202
|
+
(typeof options.moduleImporter !== 'string' || options.moduleImporter.trim().length === 0)
|
|
1203
|
+
) {
|
|
1204
|
+
throw new TypeError('hmr.moduleImporter must be a non-empty string')
|
|
1205
|
+
}
|
|
1206
|
+
return { channel: options.channel, moduleImporter: options.moduleImporter ?? null }
|
|
1088
1207
|
}
|
|
1089
1208
|
|
|
1090
1209
|
function createBrowserHmrChannel(
|
|
@@ -1145,37 +1264,20 @@ function normalizeBasePath(basePath: string): string {
|
|
|
1145
1264
|
function normalizeFingerprintOptions(options: {
|
|
1146
1265
|
fingerprint: AssetServerOptions['fingerprint']
|
|
1147
1266
|
watch: AssetServerOptions['watch']
|
|
1148
|
-
}):
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
buildId?: string
|
|
1152
|
-
}
|
|
1153
|
-
| {
|
|
1154
|
-
enabled: true
|
|
1155
|
-
buildId: string
|
|
1156
|
-
} {
|
|
1157
|
-
if (!options.fingerprint) {
|
|
1158
|
-
return {
|
|
1159
|
-
enabled: false,
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
if (typeof options.fingerprint.buildId !== 'string') {
|
|
1164
|
-
throw new TypeError('fingerprint.buildId must be a string')
|
|
1267
|
+
}): boolean {
|
|
1268
|
+
if (options.fingerprint !== undefined && typeof options.fingerprint !== 'boolean') {
|
|
1269
|
+
throw new TypeError('fingerprint must be a boolean')
|
|
1165
1270
|
}
|
|
1166
1271
|
|
|
1167
|
-
if (options.fingerprint
|
|
1168
|
-
|
|
1272
|
+
if (!options.fingerprint) {
|
|
1273
|
+
return false
|
|
1169
1274
|
}
|
|
1170
1275
|
|
|
1171
1276
|
if (options.watch !== false) {
|
|
1172
1277
|
throw new TypeError('fingerprint cannot be used with watch mode')
|
|
1173
1278
|
}
|
|
1174
1279
|
|
|
1175
|
-
return
|
|
1176
|
-
enabled: true,
|
|
1177
|
-
buildId: options.fingerprint.buildId,
|
|
1178
|
-
}
|
|
1280
|
+
return true
|
|
1179
1281
|
}
|
|
1180
1282
|
|
|
1181
1283
|
function normalizeWatchOptions(
|