1
- import type { NetlifyPluginOptions } from '@netlify/build'
2
- import glob from 'fast-glob'
3
- import { Buffer } from 'node:buffer'
4
1
import { existsSync } from 'node:fs'
5
- import { mkdir , readFile , writeFile } from 'node:fs/promises'
6
- import { dirname , resolve } from 'node:path'
7
- import { getPrerenderManifest } from '../config.js'
8
- import { BLOB_DIR } from '../constants.js'
9
-
10
- export type CacheEntry = {
11
- lastModified : number
12
- value : CacheValue
13
- }
14
-
15
- type CacheValue = PageCacheValue | RouteCacheValue | FetchCacheValue
16
-
17
- export type PageCacheValue = {
18
- kind : 'PAGE'
19
- html : string
20
- pageData : string
21
- headers ?: { [ k : string ] : string }
22
- status ?: number
23
- }
24
-
25
- type RouteCacheValue = {
26
- kind : 'ROUTE'
27
- body : string
28
- headers : { [ k : string ] : string }
29
- status : number
30
- }
2
+ import { readFile } from 'node:fs/promises'
3
+ import { join } from 'node:path'
31
4
32
- type FetchCacheValue = {
33
- kind : 'FETCH'
34
- data : {
35
- headers : { [ k : string ] : string }
36
- body : string
37
- url : string
38
- status ?: number
39
- tags ?: string [ ]
40
- }
41
- }
42
-
43
- /**
44
- * Write a cache entry to the blob upload directory using
45
- * base64 keys to avoid collisions with directories
46
- */
47
- const writeCacheEntry = async ( key : string , value : CacheValue ) => {
48
- const path = resolve ( BLOB_DIR , Buffer . from ( key ) . toString ( 'base64' ) )
49
- const entry = JSON . stringify ( {
50
- lastModified : Date . now ( ) ,
51
- value,
52
- } satisfies CacheEntry )
5
+ import glob from 'fast-glob'
53
6
54
- await mkdir ( dirname ( path ) , { recursive : true } )
55
- await writeFile ( path , entry , 'utf-8' )
56
- }
7
+ import type {
8
+ CacheValue ,
9
+ FetchCacheValue ,
10
+ PageCacheValue ,
11
+ PluginContext ,
12
+ RouteCacheValue ,
13
+ } from '../plugin-context.js'
57
14
58
15
/**
59
16
* Normalize routes by stripping leading slashes and ensuring root path is index
@@ -87,15 +44,10 @@ const buildFetchCacheValue = async (path: string): Promise<FetchCacheValue> => (
87
44
/**
88
45
* Upload prerendered content to the blob store
89
46
*/
90
- export const copyPrerenderedContent = async ( {
91
- constants : { PUBLISH_DIR } ,
92
- utils : {
93
- build : { failBuild } ,
94
- } ,
95
- } : Pick < NetlifyPluginOptions , 'constants' | 'utils' > ) => {
47
+ export const copyPrerenderedContent = async ( ctx : PluginContext ) : Promise < void > => {
96
48
try {
97
49
// read prerendered content and build JSON key/values for the blob store
98
- const manifest = await getPrerenderManifest ( { PUBLISH_DIR } )
50
+ const manifest = await ctx . getPrerenderManifest ( )
99
51
100
52
await Promise . all (
101
53
Object . entries ( manifest . routes ) . map ( async ( [ route , meta ] ) => {
@@ -104,62 +56,51 @@ export const copyPrerenderedContent = async ({
104
56
105
57
switch ( true ) {
106
58
case meta . dataRoute ?. endsWith ( '.json' ) :
107
- value = await buildPagesCacheValue ( resolve ( PUBLISH_DIR , 'server/pages' , key ) )
59
+ value = await buildPagesCacheValue ( join ( ctx . publishDir , 'server/pages' , key ) )
108
60
break
109
-
110
61
case meta . dataRoute ?. endsWith ( '.rsc' ) :
111
- value = await buildAppCacheValue ( resolve ( PUBLISH_DIR , 'server/app' , key ) )
62
+ value = await buildAppCacheValue ( join ( ctx . publishDir , 'server/app' , key ) )
112
63
break
113
-
114
64
case meta . dataRoute === null :
115
- value = await buildRouteCacheValue ( resolve ( PUBLISH_DIR , 'server/app' , key ) )
65
+ value = await buildRouteCacheValue ( join ( ctx . publishDir , 'server/app' , key ) )
116
66
break
117
-
118
67
default :
119
68
throw new Error ( `Unrecognized content: ${ route } ` )
120
69
}
121
70
122
- await writeCacheEntry ( key , value )
71
+ await ctx . writeCacheEntry ( key , value )
123
72
} ) ,
124
73
)
125
74
126
75
// app router 404 pages are not in the prerender manifest
127
76
// so we need to check for them manually
128
- if ( existsSync ( resolve ( PUBLISH_DIR , `server/app/_not-found.html` ) ) ) {
77
+ if ( existsSync ( join ( ctx . publishDir , `server/app/_not-found.html` ) ) ) {
129
78
const key = '404'
130
- const value = await buildAppCacheValue ( resolve ( PUBLISH_DIR , 'server/app/_not-found' ) )
131
- await writeCacheEntry ( key , value )
79
+ const value = await buildAppCacheValue ( join ( ctx . publishDir , 'server/app/_not-found' ) )
80
+ await ctx . writeCacheEntry ( key , value )
132
81
}
133
82
} catch ( error ) {
134
- failBuild (
135
- 'Failed assembling prerendered content for upload' ,
136
- error instanceof Error ? { error } : { } ,
137
- )
83
+ ctx . failBuild ( 'Failed assembling prerendered content for upload' , error )
138
84
}
139
85
}
140
86
141
87
/**
142
88
* Upload fetch content to the blob store
143
89
*/
144
- export const copyFetchContent = async ( {
145
- constants : { PUBLISH_DIR } ,
146
- utils : {
147
- build : { failBuild } ,
148
- } ,
149
- } : Pick < NetlifyPluginOptions , 'constants' | 'utils' > ) => {
90
+ export const copyFetchContent = async ( ctx : PluginContext ) : Promise < void > => {
150
91
try {
151
92
const paths = await glob ( [ '!(*.*)' ] , {
152
- cwd : resolve ( PUBLISH_DIR , 'cache/fetch-cache' ) ,
93
+ cwd : join ( ctx . publishDir , 'cache/fetch-cache' ) ,
153
94
extglob : true ,
154
95
} )
155
96
156
97
await Promise . all (
157
- paths . map ( async ( key ) => {
158
- const value = await buildFetchCacheValue ( resolve ( PUBLISH_DIR , 'cache/fetch-cache' , key ) )
159
- await writeCacheEntry ( key , value )
98
+ paths . map ( async ( key ) : Promise < void > => {
99
+ const value = await buildFetchCacheValue ( join ( ctx . publishDir , 'cache/fetch-cache' , key ) )
100
+ await ctx . writeCacheEntry ( key , value )
160
101
} ) ,
161
102
)
162
103
} catch ( error ) {
163
- failBuild ( 'Failed assembling fetch content for upload' , error instanceof Error ? { error } : { } )
104
+ ctx . failBuild ( 'Failed assembling fetch content for upload' , error )
164
105
}
165
106
}
0 commit comments