@remix-run/assets 0.3.0 → 0.4.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 +206 -8
- package/dist/assets.d.ts +1 -0
- package/dist/assets.d.ts.map +1 -1
- package/dist/assets.js +1 -0
- package/dist/lib/access.d.ts +1 -0
- package/dist/lib/access.d.ts.map +1 -1
- package/dist/lib/access.js +7 -1
- package/dist/lib/asset-server.d.ts +29 -6
- package/dist/lib/asset-server.d.ts.map +1 -1
- package/dist/lib/asset-server.js +176 -17
- 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 +71 -0
- package/dist/lib/files/compiler.d.ts.map +1 -0
- package/dist/lib/files/compiler.js +552 -0
- package/dist/lib/files/config.d.ts +101 -0
- package/dist/lib/files/config.d.ts.map +1 -0
- package/dist/lib/files/config.js +219 -0
- package/dist/lib/files/store.d.ts +31 -0
- package/dist/lib/files/store.d.ts.map +1 -0
- package/dist/lib/files/store.js +63 -0
- package/dist/lib/fingerprint.d.ts +3 -3
- package/dist/lib/fingerprint.d.ts.map +1 -1
- package/dist/lib/fingerprint.js +5 -5
- package/dist/lib/routes.d.ts.map +1 -1
- package/dist/lib/routes.js +28 -20
- package/dist/lib/scripts/compiler.d.ts +1 -0
- package/dist/lib/scripts/compiler.d.ts.map +1 -1
- package/dist/lib/scripts/compiler.js +30 -5
- package/dist/lib/scripts/resolve.d.ts.map +1 -1
- package/dist/lib/scripts/resolve.js +22 -2
- package/dist/lib/scripts/transform.js +1 -1
- package/dist/lib/styles/compiler.d.ts +4 -0
- package/dist/lib/styles/compiler.d.ts.map +1 -1
- package/dist/lib/styles/compiler.js +2 -0
- package/dist/lib/styles/emit.d.ts +3 -0
- package/dist/lib/styles/emit.d.ts.map +1 -1
- package/dist/lib/styles/emit.js +36 -1
- package/dist/lib/styles/resolve.d.ts +8 -1
- package/dist/lib/styles/resolve.d.ts.map +1 -1
- package/dist/lib/styles/resolve.js +85 -32
- package/dist/lib/watch.d.ts +2 -0
- package/dist/lib/watch.d.ts.map +1 -1
- package/dist/lib/watch.js +25 -8
- package/package.json +6 -4
- package/src/assets.ts +1 -0
- package/src/lib/access.ts +8 -1
- package/src/lib/asset-server.ts +273 -28
- package/src/lib/compilation-error.ts +9 -0
- package/src/lib/files/compiler.ts +885 -0
- package/src/lib/files/config.ts +479 -0
- package/src/lib/files/store.ts +109 -0
- package/src/lib/fingerprint.ts +8 -7
- package/src/lib/routes.ts +36 -33
- package/src/lib/scripts/compiler.ts +43 -5
- package/src/lib/scripts/resolve.ts +35 -3
- package/src/lib/scripts/transform.ts +1 -1
- package/src/lib/styles/compiler.ts +9 -0
- package/src/lib/styles/emit.ts +75 -1
- package/src/lib/styles/resolve.ts +132 -35
- package/src/lib/watch.ts +34 -12
package/src/lib/routes.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { RoutePattern } from '@remix-run/route-pattern'
|
|
2
|
+
import { createHref } from '@remix-run/route-pattern/href'
|
|
3
|
+
import { createMatcher, type Matcher } from '@remix-run/route-pattern/match'
|
|
2
4
|
|
|
3
5
|
import {
|
|
4
6
|
getRelativeFilePath,
|
|
@@ -21,7 +23,9 @@ interface RouteConfig {
|
|
|
21
23
|
interface CompiledRoute {
|
|
22
24
|
rootDir: string
|
|
23
25
|
urlPattern: RoutePattern
|
|
26
|
+
urlMatcher: Matcher
|
|
24
27
|
filePattern: RoutePattern
|
|
28
|
+
fileMatcher: Matcher
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
export interface CompiledRoutes {
|
|
@@ -67,9 +71,9 @@ export function compileRoutes(
|
|
|
67
71
|
let normalizedPathname = normalizePathname(pathname)
|
|
68
72
|
|
|
69
73
|
for (let route of compiledRoutes) {
|
|
70
|
-
let match = route.
|
|
74
|
+
let match = route.urlMatcher.match(`http://remix.run${normalizedPathname}`)
|
|
71
75
|
if (!match) continue
|
|
72
|
-
let relativeFilePath = route.filePattern
|
|
76
|
+
let relativeFilePath = createHref(route.filePattern, match.params).replace(/^\/+/, '')
|
|
73
77
|
return resolveFilePath(route.rootDir, relativeFilePath)
|
|
74
78
|
}
|
|
75
79
|
|
|
@@ -80,9 +84,9 @@ export function compileRoutes(
|
|
|
80
84
|
|
|
81
85
|
for (let route of compiledRoutes) {
|
|
82
86
|
let relativeFilePath = getRelativeFilePath(route.rootDir, normalizedFilePath)
|
|
83
|
-
let match = route.
|
|
87
|
+
let match = route.fileMatcher.match(`http://remix.run/${relativeFilePath}`)
|
|
84
88
|
if (!match) continue
|
|
85
|
-
return normalizePathname(route.urlPattern
|
|
89
|
+
return normalizePathname(createHref(route.urlPattern, match.params))
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
return null
|
|
@@ -104,8 +108,8 @@ function compileRoute(
|
|
|
104
108
|
)
|
|
105
109
|
let filePatternSource = normalizeFilePattern(route.filePattern)
|
|
106
110
|
|
|
107
|
-
let urlPattern =
|
|
108
|
-
let filePattern =
|
|
111
|
+
let urlPattern = RoutePattern.parse(urlPatternSource)
|
|
112
|
+
let filePattern = RoutePattern.parse(filePatternSource)
|
|
109
113
|
|
|
110
114
|
validateNoUnnamedWildcards(urlPattern, 'URL')
|
|
111
115
|
validateNoUnnamedWildcards(filePattern, 'File')
|
|
@@ -114,37 +118,30 @@ function compileRoute(
|
|
|
114
118
|
return {
|
|
115
119
|
rootDir: normalizeFilePath(options.rootDir).replace(/\/+$/, ''),
|
|
116
120
|
urlPattern,
|
|
121
|
+
urlMatcher: createMatcher(urlPattern),
|
|
117
122
|
filePattern,
|
|
123
|
+
fileMatcher: createMatcher(stripDotSegments(filePatternSource)),
|
|
118
124
|
}
|
|
119
125
|
}
|
|
120
126
|
|
|
121
|
-
function
|
|
122
|
-
|
|
123
|
-
match: Array<{ name: string; type: ':' | '*'; value: string }>,
|
|
124
|
-
): Record<string, string | undefined> {
|
|
125
|
-
let params: Record<string, string | undefined> = {}
|
|
127
|
+
function stripDotSegments(pattern: string): string {
|
|
128
|
+
let segments: string[] = []
|
|
126
129
|
|
|
127
|
-
for (let
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
params[param.name] = param.value
|
|
130
|
+
for (let segment of pattern.split('/')) {
|
|
131
|
+
if (segment === '' || segment === '.') continue
|
|
132
|
+
if (segment === '..') {
|
|
133
|
+
segments.pop()
|
|
134
|
+
continue
|
|
135
|
+
}
|
|
136
|
+
segments.push(segment)
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
return
|
|
139
|
+
return segments.join('/')
|
|
138
140
|
}
|
|
139
141
|
|
|
140
142
|
function validateRoutePatterns(urlPattern: RoutePattern, filePattern: RoutePattern): void {
|
|
141
|
-
let urlParams = urlPattern
|
|
142
|
-
|
|
143
|
-
)
|
|
144
|
-
let fileParams = filePattern.ast.pathname.params.map(
|
|
145
|
-
(param: { name: string; type: ':' | '*' }) => `${param.type}:${param.name}`,
|
|
146
|
-
)
|
|
147
|
-
|
|
143
|
+
let urlParams = getPathnameParams(urlPattern)
|
|
144
|
+
let fileParams = getPathnameParams(filePattern)
|
|
148
145
|
if (urlParams.length !== fileParams.length) {
|
|
149
146
|
throw new Error(
|
|
150
147
|
`Route patterns must have matching capture structure.\nURL: ${urlPattern}\nFile: ${filePattern}`,
|
|
@@ -152,7 +149,9 @@ function validateRoutePatterns(urlPattern: RoutePattern, filePattern: RoutePatte
|
|
|
152
149
|
}
|
|
153
150
|
|
|
154
151
|
for (let i = 0; i < urlParams.length; i++) {
|
|
155
|
-
|
|
152
|
+
let urlParam = urlParams[i]
|
|
153
|
+
let fileParam = fileParams[i]
|
|
154
|
+
if (urlParam.type !== fileParam.type || urlParam.name !== fileParam.name) {
|
|
156
155
|
throw new Error(
|
|
157
156
|
`Route patterns must have matching capture structure.\nURL: ${urlPattern}\nFile: ${filePattern}`,
|
|
158
157
|
)
|
|
@@ -161,13 +160,17 @@ function validateRoutePatterns(urlPattern: RoutePattern, filePattern: RoutePatte
|
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
function validateNoUnnamedWildcards(pattern: RoutePattern, label: string): void {
|
|
164
|
-
if (
|
|
165
|
-
pattern.ast.pathname.params.some(
|
|
166
|
-
(param: { name: string; type: ':' | '*' }) => param.type === '*' && param.name === '*',
|
|
167
|
-
)
|
|
168
|
-
) {
|
|
163
|
+
if (pattern.pathname.tokens.some((token) => token.type === '*' && token.name === '*')) {
|
|
169
164
|
throw new Error(
|
|
170
165
|
`${label} route patterns must use named wildcards for reversible mapping.\nPattern: ${pattern}`,
|
|
171
166
|
)
|
|
172
167
|
}
|
|
173
168
|
}
|
|
169
|
+
|
|
170
|
+
type PathnameParam = Extract<RoutePattern['pathname']['tokens'][number], { type: ':' | '*' }>
|
|
171
|
+
|
|
172
|
+
function getPathnameParams(pattern: RoutePattern): Array<PathnameParam> {
|
|
173
|
+
return pattern.pathname.tokens.filter(
|
|
174
|
+
(token): token is PathnameParam => token.type === ':' || token.type === '*',
|
|
175
|
+
)
|
|
176
|
+
}
|
|
@@ -66,6 +66,7 @@ type ScriptCompilerOptions = {
|
|
|
66
66
|
external: string[]
|
|
67
67
|
fingerprintAssets: boolean
|
|
68
68
|
isAllowed(absolutePath: string): boolean
|
|
69
|
+
isDenied(absolutePath: string): boolean
|
|
69
70
|
minify: boolean
|
|
70
71
|
onWatchDirectoriesChange?: (delta: { add: string[]; remove: string[] }) => void
|
|
71
72
|
rootDir: string
|
|
@@ -117,8 +118,14 @@ export function createScriptCompiler(options: ScriptCompilerOptions): ScriptComp
|
|
|
117
118
|
extensionAlias: resolverExtensionAlias,
|
|
118
119
|
extensions: resolverExtensions,
|
|
119
120
|
mainFields: ['browser', 'module', 'main'],
|
|
121
|
+
symlinks: false,
|
|
120
122
|
tsconfig: 'auto',
|
|
121
123
|
})
|
|
124
|
+
let resolveModulePathOptions = {
|
|
125
|
+
isAllowed: resolvedOptions.isAllowed,
|
|
126
|
+
isDenied: resolvedOptions.isDenied,
|
|
127
|
+
routes: resolvedOptions.routes,
|
|
128
|
+
}
|
|
122
129
|
let resolveInFlightByCacheKey = new Map<string, Promise<ResolvedModule>>()
|
|
123
130
|
let emitInFlightByCacheKey = new Map<string, Promise<EmittedModule>>()
|
|
124
131
|
|
|
@@ -138,7 +145,9 @@ export function createScriptCompiler(options: ScriptCompilerOptions): ScriptComp
|
|
|
138
145
|
let resolveArgs: ResolveArgs = {
|
|
139
146
|
isAllowed: resolvedOptions.isAllowed,
|
|
140
147
|
isWatchIgnored,
|
|
141
|
-
resolveModulePath
|
|
148
|
+
resolveModulePath(absolutePath) {
|
|
149
|
+
return resolveModulePath(absolutePath, resolveModulePathOptions)
|
|
150
|
+
},
|
|
142
151
|
resolverFactory,
|
|
143
152
|
routes: resolvedOptions.routes,
|
|
144
153
|
}
|
|
@@ -253,7 +262,7 @@ export function createScriptCompiler(options: ScriptCompilerOptions): ScriptComp
|
|
|
253
262
|
}
|
|
254
263
|
|
|
255
264
|
function resolveServedScriptOrThrow(absolutePath: string): ResolveModuleResult {
|
|
256
|
-
let resolvedModule = resolveModulePath(absolutePath)
|
|
265
|
+
let resolvedModule = resolveModulePath(absolutePath, resolveModulePathOptions)
|
|
257
266
|
if (!resolvedModule) {
|
|
258
267
|
throw createAssetServerCompilationError(`File not found: ${absolutePath}`, {
|
|
259
268
|
code: 'FILE_NOT_FOUND',
|
|
@@ -548,11 +557,19 @@ function shouldClearResolverCacheForFileEvent(filePath: string, event: ModuleWat
|
|
|
548
557
|
return event !== 'change' || isPackageJsonPath(filePath) || isTsconfigPath(filePath)
|
|
549
558
|
}
|
|
550
559
|
|
|
551
|
-
function resolveModulePath(
|
|
560
|
+
function resolveModulePath(
|
|
561
|
+
absolutePath: string,
|
|
562
|
+
options: {
|
|
563
|
+
isAllowed(absolutePath: string): boolean
|
|
564
|
+
isDenied(absolutePath: string): boolean
|
|
565
|
+
routes: CompiledRoutes
|
|
566
|
+
},
|
|
567
|
+
): ResolveModuleResult | null {
|
|
568
|
+
let candidateIdentityPath = normalizeFilePath(absolutePath)
|
|
552
569
|
let resolvedPath: string
|
|
553
570
|
|
|
554
571
|
try {
|
|
555
|
-
resolvedPath = normalizeFilePath(fs.realpathSync(
|
|
572
|
+
resolvedPath = normalizeFilePath(fs.realpathSync(candidateIdentityPath))
|
|
556
573
|
} catch (error) {
|
|
557
574
|
if (isNoEntityError(error)) return null
|
|
558
575
|
throw error
|
|
@@ -563,11 +580,32 @@ function resolveModulePath(absolutePath: string): ResolveModuleResult | null {
|
|
|
563
580
|
}
|
|
564
581
|
|
|
565
582
|
return {
|
|
566
|
-
identityPath: resolvedPath,
|
|
583
|
+
identityPath: getModuleIdentityPath(candidateIdentityPath, resolvedPath, options),
|
|
567
584
|
resolvedPath,
|
|
568
585
|
}
|
|
569
586
|
}
|
|
570
587
|
|
|
588
|
+
function getModuleIdentityPath(
|
|
589
|
+
candidateIdentityPath: string,
|
|
590
|
+
resolvedPath: string,
|
|
591
|
+
options: {
|
|
592
|
+
isAllowed(absolutePath: string): boolean
|
|
593
|
+
isDenied(absolutePath: string): boolean
|
|
594
|
+
routes: CompiledRoutes
|
|
595
|
+
},
|
|
596
|
+
): string {
|
|
597
|
+
if (candidateIdentityPath === resolvedPath) return resolvedPath
|
|
598
|
+
if (!containsNodeModulesPathSegment(candidateIdentityPath)) return resolvedPath
|
|
599
|
+
if (!options.routes.toUrlPathname(candidateIdentityPath)) return resolvedPath
|
|
600
|
+
if (!options.isAllowed(candidateIdentityPath)) return resolvedPath
|
|
601
|
+
if (options.isDenied(resolvedPath)) return resolvedPath
|
|
602
|
+
return candidateIdentityPath
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
function containsNodeModulesPathSegment(filePath: string): boolean {
|
|
606
|
+
return filePath.split('/').includes('node_modules')
|
|
607
|
+
}
|
|
608
|
+
|
|
571
609
|
function resolveActualPath(identityPath: string): string | null {
|
|
572
610
|
try {
|
|
573
611
|
return normalizeFilePath(fs.realpathSync(identityPath))
|
|
@@ -105,7 +105,7 @@ export async function resolveModule(
|
|
|
105
105
|
transformed.unresolvedImports.length > 0
|
|
106
106
|
? await batchResolveSpecifiers(
|
|
107
107
|
getUniqueSpecifiers(transformed.unresolvedImports),
|
|
108
|
-
transformed.
|
|
108
|
+
transformed.identityPath,
|
|
109
109
|
args.resolverFactory,
|
|
110
110
|
)
|
|
111
111
|
: new Map<string, ResolvedSpec>()
|
|
@@ -196,8 +196,10 @@ export async function resolveModule(
|
|
|
196
196
|
deps.add(resolvedImport.identityPath)
|
|
197
197
|
|
|
198
198
|
if (transformed.packageSpecifiers.includes(unresolved.specifier)) {
|
|
199
|
-
let packageJsonPath =
|
|
200
|
-
resolvedSpec.packageJsonPath
|
|
199
|
+
let packageJsonPath = resolvePackageJsonPath(
|
|
200
|
+
resolvedSpec.packageJsonPath,
|
|
201
|
+
resolvedImport.resolvedPath,
|
|
202
|
+
)
|
|
201
203
|
if (packageJsonPath && !args.isWatchIgnored(packageJsonPath)) {
|
|
202
204
|
trackedFiles.add(packageJsonPath)
|
|
203
205
|
}
|
|
@@ -235,6 +237,25 @@ export async function resolveModule(
|
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
|
|
240
|
+
function resolvePackageJsonPath(
|
|
241
|
+
packageJsonPath: string | null,
|
|
242
|
+
resolvedPath: string,
|
|
243
|
+
): string | null {
|
|
244
|
+
return (
|
|
245
|
+
(packageJsonPath ? resolveExistingPath(packageJsonPath) : null) ??
|
|
246
|
+
findNearestPackageJsonPath(resolvedPath)
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function resolveExistingPath(filePath: string): string | null {
|
|
251
|
+
try {
|
|
252
|
+
return normalizeFilePath(fs.realpathSync(filePath))
|
|
253
|
+
} catch (error) {
|
|
254
|
+
if (isNoEntityError(error)) return null
|
|
255
|
+
throw error
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
238
259
|
function findNearestPackageJsonPath(filePath: string): string | null {
|
|
239
260
|
let directory = path.dirname(filePath)
|
|
240
261
|
|
|
@@ -250,6 +271,17 @@ function findNearestPackageJsonPath(filePath: string): string | null {
|
|
|
250
271
|
}
|
|
251
272
|
}
|
|
252
273
|
|
|
274
|
+
function isNoEntityError(
|
|
275
|
+
error: unknown,
|
|
276
|
+
): error is NodeJS.ErrnoException & { code: 'ENOENT' | 'ENOTDIR' } {
|
|
277
|
+
return (
|
|
278
|
+
error instanceof Error &&
|
|
279
|
+
'code' in error &&
|
|
280
|
+
((error as NodeJS.ErrnoException).code === 'ENOENT' ||
|
|
281
|
+
(error as NodeJS.ErrnoException).code === 'ENOTDIR')
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
|
|
253
285
|
function isRelativeImportSpecifier(specifier: string): boolean {
|
|
254
286
|
return specifier.startsWith('./') || specifier.startsWith('../')
|
|
255
287
|
}
|
|
@@ -261,7 +261,7 @@ export async function transformModule(
|
|
|
261
261
|
content: sourceText,
|
|
262
262
|
}),
|
|
263
263
|
identityPath: record.identityPath,
|
|
264
|
-
importerDir: path.dirname(
|
|
264
|
+
importerDir: path.dirname(record.identityPath),
|
|
265
265
|
packageSpecifiers: analysis.unresolvedImports
|
|
266
266
|
.filter((unresolved) => isPackageImportSpecifier(unresolved.specifier))
|
|
267
267
|
.map((unresolved) => unresolved.specifier),
|
|
@@ -44,7 +44,14 @@ type StyleGetOptions = {
|
|
|
44
44
|
type StyleCompilerOptions = {
|
|
45
45
|
buildId?: string
|
|
46
46
|
fingerprintAssets: boolean
|
|
47
|
+
getServedFileUrl?(
|
|
48
|
+
identityPath: string,
|
|
49
|
+
options: {
|
|
50
|
+
transform: readonly string[] | null
|
|
51
|
+
},
|
|
52
|
+
): Promise<string>
|
|
47
53
|
isAllowed(absolutePath: string): boolean
|
|
54
|
+
isServedFilePath(filePath: string): boolean
|
|
48
55
|
minify: boolean
|
|
49
56
|
onWatchDirectoriesChange?: (delta: { add: string[]; remove: string[] }) => void
|
|
50
57
|
rootDir: string
|
|
@@ -79,6 +86,7 @@ export function createStyleCompiler(options: StyleCompilerOptions): StyleCompile
|
|
|
79
86
|
let emitInFlightByCacheKey = new Map<string, Promise<EmittedStyle>>()
|
|
80
87
|
let resolveArgs: ResolveArgs = {
|
|
81
88
|
isAllowed: resolvedOptions.isAllowed,
|
|
89
|
+
isServedFilePath: resolvedOptions.isServedFilePath,
|
|
82
90
|
isWatchIgnored,
|
|
83
91
|
routes: resolvedOptions.routes,
|
|
84
92
|
}
|
|
@@ -248,6 +256,7 @@ export function createStyleCompiler(options: StyleCompilerOptions): StyleCompile
|
|
|
248
256
|
let startedVersion = record.invalidationVersion
|
|
249
257
|
let resolvedStyle = await getOrCreateResolvedStyle(record)
|
|
250
258
|
let emitResolvedStyleResult = await emitResolvedStyle(resolvedStyle, {
|
|
259
|
+
getServedFileUrl: resolvedOptions.getServedFileUrl,
|
|
251
260
|
getServedUrl,
|
|
252
261
|
sourceMaps: resolvedOptions.sourceMaps,
|
|
253
262
|
})
|
package/src/lib/styles/emit.ts
CHANGED
|
@@ -34,6 +34,12 @@ type EmitResult =
|
|
|
34
34
|
export async function emitResolvedStyle(
|
|
35
35
|
resolvedStyle: ResolvedStyle,
|
|
36
36
|
options: {
|
|
37
|
+
getServedFileUrl?(
|
|
38
|
+
identityPath: string,
|
|
39
|
+
options: {
|
|
40
|
+
transform: readonly string[] | null
|
|
41
|
+
},
|
|
42
|
+
): Promise<string>
|
|
37
43
|
getServedUrl(identityPath: string): Promise<string>
|
|
38
44
|
sourceMaps?: 'external' | 'inline'
|
|
39
45
|
},
|
|
@@ -77,6 +83,12 @@ async function rewriteDependencies(
|
|
|
77
83
|
resolvedStyle: ResolvedStyle,
|
|
78
84
|
options: {
|
|
79
85
|
getServedUrl(identityPath: string): Promise<string>
|
|
86
|
+
getServedFileUrl?(
|
|
87
|
+
identityPath: string,
|
|
88
|
+
options: {
|
|
89
|
+
transform: readonly string[] | null
|
|
90
|
+
},
|
|
91
|
+
): Promise<string>
|
|
80
92
|
},
|
|
81
93
|
): Promise<{ code: string; sourceMap: string | null }> {
|
|
82
94
|
if (resolvedStyle.dependencies.length === 0) {
|
|
@@ -92,7 +104,14 @@ async function rewriteDependencies(
|
|
|
92
104
|
let replacement =
|
|
93
105
|
dependency.kind === 'external'
|
|
94
106
|
? dependency.replacement
|
|
95
|
-
:
|
|
107
|
+
: dependency.kind === 'style'
|
|
108
|
+
? `${await options.getServedUrl(dependency.depPath)}${dependency.suffix}`
|
|
109
|
+
: appendUrlSuffix(
|
|
110
|
+
await getServedFileUrl(options, resolvedStyle.identityPath, dependency.depPath, {
|
|
111
|
+
transform: dependency.requestTransform,
|
|
112
|
+
}),
|
|
113
|
+
dependency.suffix,
|
|
114
|
+
)
|
|
96
115
|
let start = resolvedStyle.rawCode.indexOf(dependency.placeholder)
|
|
97
116
|
if (start < 0) {
|
|
98
117
|
throw createAssetServerCompilationError(
|
|
@@ -117,6 +136,61 @@ async function rewriteDependencies(
|
|
|
117
136
|
}
|
|
118
137
|
}
|
|
119
138
|
|
|
139
|
+
function appendUrlSuffix(url: string, suffix: string): string {
|
|
140
|
+
if (!suffix.startsWith('?') || !url.includes('?')) {
|
|
141
|
+
return `${url}${suffix}`
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return `${url}&${suffix.slice(1)}`
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function getServedFileUrl(
|
|
148
|
+
options: {
|
|
149
|
+
getServedFileUrl?(
|
|
150
|
+
identityPath: string,
|
|
151
|
+
options: {
|
|
152
|
+
transform: readonly string[] | null
|
|
153
|
+
},
|
|
154
|
+
): Promise<string>
|
|
155
|
+
getServedUrl(identityPath: string): Promise<string>
|
|
156
|
+
},
|
|
157
|
+
importerPath: string,
|
|
158
|
+
identityPath: string,
|
|
159
|
+
request: {
|
|
160
|
+
transform: readonly string[] | null
|
|
161
|
+
},
|
|
162
|
+
): Promise<string> {
|
|
163
|
+
if (!options.getServedFileUrl) {
|
|
164
|
+
throw createAssetServerCompilationError(`Missing file URL resolver for ${identityPath}.`, {
|
|
165
|
+
code: 'EMIT_FAILED',
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
return await options.getServedFileUrl(identityPath, request)
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (
|
|
173
|
+
request.transform !== null &&
|
|
174
|
+
isAssetServerCompilationError(error) &&
|
|
175
|
+
error.code === 'FILE_TRANSFORM_QUERY_INVALID'
|
|
176
|
+
) {
|
|
177
|
+
console.warn(
|
|
178
|
+
`Invalid file transform request "${request.transform.join(',')}" in CSS asset ${importerPath} for ${identityPath}: ${error.message}`,
|
|
179
|
+
)
|
|
180
|
+
let href = await options.getServedFileUrl(identityPath, { transform: null })
|
|
181
|
+
let searchParams = new URLSearchParams()
|
|
182
|
+
for (let transform of request.transform) {
|
|
183
|
+
searchParams.append('transform', transform)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let search = searchParams.toString()
|
|
187
|
+
return search.length > 0 ? `${href}?${search}` : href
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
throw error
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
120
194
|
async function createEmittedAsset(content: string): Promise<EmittedAsset> {
|
|
121
195
|
return {
|
|
122
196
|
content,
|