@tanstack/start-server-core 1.168.0 → 1.168.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.
@@ -10,20 +10,32 @@ import type {
10
10
 
11
11
  export type { AssetCrossOrigin }
12
12
 
13
- export type TransformAssetKind = 'modulepreload' | 'stylesheet' | 'clientEntry'
13
+ export type TransformAssetsContext =
14
+ | {
15
+ url: string
16
+ kind: 'modulepreload'
17
+ }
18
+ | {
19
+ url: string
20
+ kind: 'stylesheet'
21
+ }
22
+ | {
23
+ url: string
24
+ kind: 'clientEntry'
25
+ }
26
+ | {
27
+ url: string
28
+ kind: 'css-url'
29
+ stylesheetHref: string
30
+ }
31
+
32
+ export type TransformAssetKind = TransformAssetsContext['kind']
14
33
 
15
34
  type TransformAssetsShorthandCrossOriginKind = Exclude<
16
35
  TransformAssetKind,
17
- 'clientEntry'
36
+ 'clientEntry' | 'css-url'
18
37
  >
19
38
 
20
- export type AssetUrlType = TransformAssetKind
21
-
22
- export interface TransformAssetsContext {
23
- url: string
24
- kind: TransformAssetKind
25
- }
26
-
27
39
  export type TransformAssetResult =
28
40
  | string
29
41
  | {
@@ -35,16 +47,7 @@ export type TransformAssetsFn = (
35
47
  context: TransformAssetsContext,
36
48
  ) => Awaitable<TransformAssetResult>
37
49
 
38
- export interface TransformAssetUrlsContext {
39
- url: string
40
- type: AssetUrlType
41
- }
42
-
43
- export type TransformAssetUrlsFn = (
44
- context: TransformAssetUrlsContext,
45
- ) => Awaitable<string>
46
-
47
- export type CreateTransformAssetUrlsContext =
50
+ export type CreateTransformAssetsContext =
48
51
  | {
49
52
  /** True when the server is computing the cached manifest during startup warmup. */
50
53
  warmup: true
@@ -60,19 +63,11 @@ export type CreateTransformAssetUrlsContext =
60
63
  warmup: false
61
64
  }
62
65
 
63
- /**
64
- * Async factory that runs once per manifest computation and returns the
65
- * per-asset transform.
66
- */
67
- export type CreateTransformAssetUrlsFn = (
68
- ctx: CreateTransformAssetUrlsContext,
69
- ) => Awaitable<TransformAssetUrlsFn>
70
-
71
66
  export type CreateTransformAssetsFn = (
72
- ctx: CreateTransformAssetUrlsContext,
67
+ ctx: CreateTransformAssetsContext,
73
68
  ) => Awaitable<TransformAssetsFn>
74
69
 
75
- type TransformAssetUrlsOptionsBase = {
70
+ type TransformAssetsOptionsBase = {
76
71
  /**
77
72
  * Whether to cache the transformed manifest after the first request.
78
73
  *
@@ -98,45 +93,16 @@ type TransformAssetUrlsOptionsBase = {
98
93
  warmup?: boolean
99
94
  }
100
95
 
101
- export type TransformAssetUrlsOptions =
102
- | (TransformAssetUrlsOptionsBase & {
103
- /**
104
- * The transform to apply to asset URLs. Can be a string prefix or a callback.
105
- *
106
- * **String** — prepended to every asset URL.
107
- * **Callback** — receives `{ url, type }` and returns a new URL.
108
- */
109
- transform: string | TransformAssetUrlsFn
110
- createTransform?: never
111
- })
112
- | (TransformAssetUrlsOptionsBase & {
113
- /**
114
- * Create a per-asset transform function.
115
- *
116
- * This factory runs once per manifest computation (per request when
117
- * `cache: false`, or once per server when `cache: true`). It can do async
118
- * setup work (fetch config, read from a KV, etc.) and return a fast
119
- * per-asset transformer.
120
- */
121
- createTransform: CreateTransformAssetUrlsFn
122
- transform?: never
123
- })
124
-
125
96
  export type TransformAssetsOptions =
126
- | (TransformAssetUrlsOptionsBase & {
97
+ | (TransformAssetsOptionsBase & {
127
98
  transform: string | TransformAssetsFn
128
99
  createTransform?: never
129
100
  })
130
- | (TransformAssetUrlsOptionsBase & {
101
+ | (TransformAssetsOptionsBase & {
131
102
  createTransform: CreateTransformAssetsFn
132
103
  transform?: never
133
104
  })
134
105
 
135
- export type TransformAssetUrls =
136
- | string
137
- | TransformAssetUrlsFn
138
- | TransformAssetUrlsOptions
139
-
140
106
  /**
141
107
  * Per-kind crossOrigin configuration for the object shorthand.
142
108
  *
@@ -195,21 +161,6 @@ export type ResolvedTransformAssetsConfig =
195
161
  cache: boolean
196
162
  }
197
163
 
198
- let hasWarnedAboutDeprecatedTransformAssetUrls = false
199
-
200
- export function warnDeprecatedTransformAssetUrls() {
201
- if (
202
- (process.env.NODE_ENV === 'development' ||
203
- process.env.TSS_DEV_SERVER === 'true') &&
204
- !hasWarnedAboutDeprecatedTransformAssetUrls
205
- ) {
206
- hasWarnedAboutDeprecatedTransformAssetUrls = true
207
- console.warn(
208
- '[TanStack Start] `transformAssetUrls` is deprecated. Use `transformAssets` instead.',
209
- )
210
- }
211
- }
212
-
213
164
  function normalizeTransformAssetResult(
214
165
  result: TransformAssetResult,
215
166
  ): Exclude<TransformAssetResult, string> {
@@ -220,6 +171,77 @@ function normalizeTransformAssetResult(
220
171
  return result
221
172
  }
222
173
 
174
+ function escapeCssString(value: string) {
175
+ return value
176
+ .replace(/\\/g, '\\\\')
177
+ .replace(/"/g, '\\"')
178
+ .replace(/\n/g, '\\a ')
179
+ .replace(/\r/g, '\\d ')
180
+ .replace(/\f/g, '\\c ')
181
+ }
182
+
183
+ async function transformInlineCssTemplate(options: {
184
+ stylesheetHref: string
185
+ template: { strings: Array<string>; urls: Array<string> }
186
+ transformFn: TransformAssetsFn
187
+ }) {
188
+ const { strings, urls } = options.template
189
+
190
+ if (strings.length !== urls.length + 1) {
191
+ throw new Error(
192
+ `TanStack Start inlineCss template for ${options.stylesheetHref} is invalid`,
193
+ )
194
+ }
195
+
196
+ let css = strings[0]!
197
+
198
+ for (let index = 0; index < urls.length; index++) {
199
+ const transformed = normalizeTransformAssetResult(
200
+ await options.transformFn({
201
+ kind: 'css-url',
202
+ url: urls[index]!,
203
+ stylesheetHref: options.stylesheetHref,
204
+ }),
205
+ )
206
+
207
+ css += escapeCssString(transformed.href) + strings[index + 1]!
208
+ }
209
+
210
+ return css
211
+ }
212
+
213
+ async function transformInlineCssStyles(
214
+ inlineCss: NonNullable<Manifest['inlineCss']>,
215
+ transformFn: TransformAssetsFn,
216
+ ) {
217
+ const transformedStyles: Record<string, string> = {}
218
+
219
+ const transformedEntries = await Promise.all(
220
+ Object.entries(inlineCss.styles).map(async ([stylesheetHref, css]) => {
221
+ const template = inlineCss.templates?.[stylesheetHref]
222
+ return [
223
+ stylesheetHref,
224
+ template
225
+ ? await transformInlineCssTemplate({
226
+ stylesheetHref,
227
+ template,
228
+ transformFn,
229
+ })
230
+ : css,
231
+ ] as const
232
+ }),
233
+ )
234
+
235
+ for (const [stylesheetHref, css] of transformedEntries) {
236
+ transformedStyles[stylesheetHref] = css
237
+ }
238
+
239
+ return {
240
+ styles: transformedStyles,
241
+ ...(inlineCss.templates ? { templates: inlineCss.templates } : {}),
242
+ }
243
+ }
244
+
223
245
  function resolveTransformAssetsCrossOrigin(
224
246
  config: TransformAssetsCrossOriginConfig | undefined,
225
247
  kind: TransformAssetsShorthandCrossOriginKind,
@@ -265,7 +287,7 @@ export function resolveTransformAssetsConfig(
265
287
  transformFn: ({ url, kind }) => {
266
288
  const href = `${prefix}${url}`
267
289
 
268
- if (kind === 'clientEntry') {
290
+ if (kind === 'clientEntry' || kind === 'css-url') {
269
291
  return { href }
270
292
  }
271
293
 
@@ -298,48 +320,6 @@ export function resolveTransformAssetsConfig(
298
320
  }
299
321
  }
300
322
 
301
- export function adaptTransformAssetUrlsToTransformAssets(
302
- transformFn: TransformAssetUrlsFn,
303
- ): TransformAssetsFn {
304
- return async ({ url, kind }) => ({
305
- href: await transformFn({ url, type: kind }),
306
- })
307
- }
308
-
309
- export function adaptTransformAssetUrlsConfigToTransformAssets(
310
- transform: TransformAssetUrls,
311
- ): TransformAssets {
312
- warnDeprecatedTransformAssetUrls()
313
-
314
- if (typeof transform === 'string') {
315
- return transform
316
- }
317
-
318
- if (typeof transform === 'function') {
319
- return adaptTransformAssetUrlsToTransformAssets(transform)
320
- }
321
-
322
- if ('createTransform' in transform && transform.createTransform) {
323
- return {
324
- createTransform: async (ctx: CreateTransformAssetUrlsContext) =>
325
- adaptTransformAssetUrlsToTransformAssets(
326
- await transform.createTransform(ctx),
327
- ),
328
- cache: transform.cache,
329
- warmup: transform.warmup,
330
- }
331
- }
332
-
333
- return {
334
- transform:
335
- typeof transform.transform === 'string'
336
- ? transform.transform
337
- : adaptTransformAssetUrlsToTransformAssets(transform.transform),
338
- cache: transform.cache,
339
- warmup: transform.warmup,
340
- }
341
- }
342
-
343
323
  export interface StartManifestWithClientEntry {
344
324
  manifest: Manifest
345
325
  clientEntry: string
@@ -386,9 +366,20 @@ export async function transformManifestAssets(
386
366
  transformFn: TransformAssetsFn,
387
367
  _opts?: {
388
368
  clone?: boolean
369
+ inlineCss?: boolean
389
370
  },
390
371
  ): Promise<Manifest> {
391
372
  const manifest = structuredClone(source.manifest)
373
+ const inlineCssEnabled = _opts?.inlineCss !== false
374
+
375
+ if (!inlineCssEnabled) {
376
+ delete manifest.inlineCss
377
+ } else if (manifest.inlineCss) {
378
+ manifest.inlineCss = await transformInlineCssStyles(
379
+ manifest.inlineCss,
380
+ transformFn,
381
+ )
382
+ }
392
383
 
393
384
  for (const route of Object.values(manifest.routes)) {
394
385
  if (route.preloads) {
@@ -410,7 +401,7 @@ export async function transformManifestAssets(
410
401
  )
411
402
  }
412
403
 
413
- if (route.assets && !source.manifest.inlineCss) {
404
+ if (route.assets && !manifest.inlineCss) {
414
405
  for (const asset of route.assets) {
415
406
  if (asset.tag === 'link' && asset.attrs?.href) {
416
407
  const rel = asset.attrs.rel
@@ -460,12 +451,13 @@ export async function transformManifestAssets(
460
451
 
461
452
  /**
462
453
  * Builds a final Manifest from a StartManifestWithClientEntry without any
463
- * URL transforms. Used when no transformAssetUrls option is provided.
454
+ * URL transforms. Used when no transformAssets option is provided.
464
455
  *
465
456
  * Returns a new manifest object so the cached base manifest is never mutated.
466
457
  */
467
458
  export function buildManifestWithClientEntry(
468
459
  source: StartManifestWithClientEntry,
460
+ opts?: { inlineCss?: boolean },
469
461
  ): Manifest {
470
462
  const scriptTag = buildClientEntryScriptTag(
471
463
  source.clientEntry,
@@ -481,5 +473,10 @@ export function buildManifestWithClientEntry(
481
473
  },
482
474
  }
483
475
 
484
- return { inlineCss: source.manifest.inlineCss, routes }
476
+ return {
477
+ ...(opts?.inlineCss === false
478
+ ? {}
479
+ : { inlineCss: structuredClone(source.manifest.inlineCss) }),
480
+ routes,
481
+ }
485
482
  }