1
- import { mkdir , readdir , readFile , stat , writeFile } from "node:fs/promises" ;
2
- import { dirname , join , relative , resolve , sep } from "node:path" ;
1
+ import { mkdir , readFile , writeFile } from "node:fs/promises" ;
2
+ import { dirname } from "node:path" ;
3
3
import { render , Text } from "ink" ;
4
4
import Spinner from "ink-spinner" ;
5
- import { getType } from "mime" ;
6
- import { Minimatch } from "minimatch" ;
7
5
import PQueue from "p-queue" ;
8
- import prettyBytes from "pretty-bytes" ;
9
6
import React from "react" ;
10
7
import { fetchResult } from "../cfetch" ;
11
8
import { FatalError } from "../errors" ;
12
9
import isInteractive from "../is-interactive" ;
13
10
import { logger } from "../logger" ;
14
11
import {
15
- MAX_ASSET_COUNT ,
16
- MAX_ASSET_SIZE ,
17
12
BULK_UPLOAD_CONCURRENCY ,
18
13
MAX_BUCKET_FILE_COUNT ,
19
14
MAX_BUCKET_SIZE ,
20
15
MAX_CHECK_MISSING_ATTEMPTS ,
21
16
MAX_UPLOAD_ATTEMPTS ,
22
17
} from "./constants" ;
23
- import { hashFile } from "./hash" ;
24
18
19
+ import { validate } from "./validate" ;
25
20
import type {
26
21
CommonYargsArgv ,
27
22
StrictYargsOptionsToInterface ,
28
23
} from "../yargs-types" ;
29
24
import type { UploadPayloadFile } from "./types" ;
25
+ import type { FileContainer } from "./validate" ;
30
26
31
27
type UploadArgs = StrictYargsOptionsToInterface < typeof Options > ;
32
28
@@ -62,8 +58,10 @@ export const Handler = async ({
62
58
throw new FatalError ( "No JWT given." , 1 ) ;
63
59
}
64
60
61
+ const fileMap = await validate ( { directory } ) ;
62
+
65
63
const manifest = await upload ( {
66
- directory ,
64
+ fileMap ,
67
65
jwt : process . env . CF_PAGES_UPLOAD_JWT ,
68
66
skipCaching : skipCaching ?? false ,
69
67
} ) ;
@@ -79,12 +77,12 @@ export const Handler = async ({
79
77
export const upload = async (
80
78
args :
81
79
| {
82
- directory : string ;
80
+ fileMap : Map < string , FileContainer > ;
83
81
jwt : string ;
84
82
skipCaching : boolean ;
85
83
}
86
84
| {
87
- directory : string ;
85
+ fileMap : Map < string , FileContainer > ;
88
86
accountId : string ;
89
87
projectName : string ;
90
88
skipCaching : boolean ;
@@ -102,95 +100,7 @@ export const upload = async (
102
100
}
103
101
}
104
102
105
- type FileContainer = {
106
- path : string ;
107
- contentType : string ;
108
- sizeInBytes : number ;
109
- hash : string ;
110
- } ;
111
-
112
- const IGNORE_LIST = [
113
- "_worker.js" ,
114
- "_redirects" ,
115
- "_headers" ,
116
- "_routes.json" ,
117
- "functions" ,
118
- "**/.DS_Store" ,
119
- "**/node_modules" ,
120
- "**/.git" ,
121
- ] . map ( ( pattern ) => new Minimatch ( pattern ) ) ;
122
-
123
- const directory = resolve ( args . directory ) ;
124
-
125
- // TODO(future): Use this to more efficiently load files in and speed up uploading
126
- // Limit memory to 1 GB unless more is specified
127
- // let maxMemory = 1_000_000_000;
128
- // if (process.env.NODE_OPTIONS && (process.env.NODE_OPTIONS.includes('--max-old-space-size=') || process.env.NODE_OPTIONS.includes('--max_old_space_size='))) {
129
- // const parsed = parser(process.env.NODE_OPTIONS);
130
- // maxMemory = (parsed['max-old-space-size'] ? parsed['max-old-space-size'] : parsed['max_old_space_size']) * 1000 * 1000; // Turn MB into bytes
131
- // }
132
-
133
- const walk = async (
134
- dir : string ,
135
- fileMap : Map < string , FileContainer > = new Map ( ) ,
136
- startingDir : string = dir
137
- ) => {
138
- const files = await readdir ( dir ) ;
139
-
140
- await Promise . all (
141
- files . map ( async ( file ) => {
142
- const filepath = join ( dir , file ) ;
143
- const relativeFilepath = relative ( startingDir , filepath ) ;
144
- const filestat = await stat ( filepath ) ;
145
-
146
- for ( const minimatch of IGNORE_LIST ) {
147
- if ( minimatch . match ( relativeFilepath ) ) {
148
- return ;
149
- }
150
- }
151
-
152
- if ( filestat . isSymbolicLink ( ) ) {
153
- return ;
154
- }
155
-
156
- if ( filestat . isDirectory ( ) ) {
157
- fileMap = await walk ( filepath , fileMap , startingDir ) ;
158
- } else {
159
- const name = relativeFilepath . split ( sep ) . join ( "/" ) ;
160
-
161
- if ( filestat . size > MAX_ASSET_SIZE ) {
162
- throw new FatalError (
163
- `Error: Pages only supports files up to ${ prettyBytes (
164
- MAX_ASSET_SIZE
165
- ) } in size\n${ name } is ${ prettyBytes ( filestat . size ) } in size`,
166
- 1
167
- ) ;
168
- }
169
-
170
- // We don't want to hold the content in memory. We instead only want to read it when it's needed
171
- fileMap . set ( name , {
172
- path : filepath ,
173
- contentType : getType ( name ) || "application/octet-stream" ,
174
- sizeInBytes : filestat . size ,
175
- hash : hashFile ( filepath ) ,
176
- } ) ;
177
- }
178
- } )
179
- ) ;
180
-
181
- return fileMap ;
182
- } ;
183
-
184
- const fileMap = await walk ( directory ) ;
185
-
186
- if ( fileMap . size > MAX_ASSET_COUNT ) {
187
- throw new FatalError (
188
- `Error: Pages only supports up to ${ MAX_ASSET_COUNT . toLocaleString ( ) } files in a deployment. Ensure you have specified your build output directory correctly.` ,
189
- 1
190
- ) ;
191
- }
192
-
193
- const files = [ ...fileMap . values ( ) ] ;
103
+ const files = [ ...args . fileMap . values ( ) ] ;
194
104
195
105
let jwt = await fetchJwt ( ) ;
196
106
@@ -274,8 +184,8 @@ export const upload = async (
274
184
bucketOffset ++ ;
275
185
}
276
186
277
- let counter = fileMap . size - sortedFiles . length ;
278
- const { rerender, unmount } = renderProgress ( counter , fileMap . size ) ;
187
+ let counter = args . fileMap . size - sortedFiles . length ;
188
+ const { rerender, unmount } = renderProgress ( counter , args . fileMap . size ) ;
279
189
280
190
const queue = new PQueue ( { concurrency : BULK_UPLOAD_CONCURRENCY } ) ;
281
191
@@ -333,7 +243,7 @@ export const upload = async (
333
243
doUpload ( ) . then (
334
244
( ) => {
335
245
counter += bucket . files . length ;
336
- rerender ( counter , fileMap . size ) ;
246
+ rerender ( counter , args . fileMap . size ) ;
337
247
} ,
338
248
( error ) => {
339
249
return Promise . reject (
@@ -355,7 +265,7 @@ export const upload = async (
355
265
356
266
const uploadMs = Date . now ( ) - start ;
357
267
358
- const skipped = fileMap . size - missingHashes . length ;
268
+ const skipped = args . fileMap . size - missingHashes . length ;
359
269
const skippedMessage = skipped > 0 ? `(${ skipped } already uploaded) ` : "" ;
360
270
361
271
logger . log (
@@ -406,7 +316,7 @@ export const upload = async (
406
316
}
407
317
408
318
return Object . fromEntries (
409
- [ ...fileMap . entries ( ) ] . map ( ( [ fileName , file ] ) => [
319
+ [ ...args . fileMap . entries ( ) ] . map ( ( [ fileName , file ] ) => [
410
320
`/${ fileName } ` ,
411
321
file . hash ,
412
322
] )
0 commit comments