@@ -2,11 +2,69 @@ import { promises } from 'fs'
2
2
import { join } from 'path'
3
3
4
4
import { build } from '@netlify/esbuild'
5
- import { watch } from 'chokidar'
5
+ import { FSWatcher , watch } from 'chokidar'
6
6
7
- const fileList = ( watched : Record < string , Array < string > > ) =>
7
+ const toFileList = ( watched : Record < string , Array < string > > ) =>
8
8
Object . entries ( watched ) . flatMap ( ( [ dir , files ] ) => files . map ( ( file ) => join ( dir , file ) ) )
9
9
10
+ /**
11
+ * Compile the middleware file using esbuild
12
+ */
13
+
14
+ const buildMiddlewareFile = async ( entryPoints : Array < string > , base : string ) => {
15
+ try {
16
+ await build ( {
17
+ entryPoints,
18
+ outfile : join ( base , '.netlify' , 'middleware.js' ) ,
19
+ bundle : true ,
20
+ format : 'esm' ,
21
+ target : 'esnext' ,
22
+ } )
23
+ } catch ( error ) {
24
+ console . error ( error )
25
+ }
26
+ }
27
+
28
+ /**
29
+ * We only compile middleware if there's exactly one file. If there's more than one, we log a warning and don't compile.
30
+ */
31
+ const shouldFilesBeCompiled = ( watchedFiles : Array < string > , isFirstRun : boolean ) => {
32
+ if ( watchedFiles . length === 0 ) {
33
+ if ( ! isFirstRun ) {
34
+ // Only log on subsequent builds, because having it on first build makes it seem like a warning, when it's a normal state
35
+ console . log ( 'No middleware found' )
36
+ }
37
+ return false
38
+ }
39
+ if ( watchedFiles . length > 1 ) {
40
+ console . log ( 'Multiple middleware files found:' )
41
+ console . log ( watchedFiles . join ( '\n' ) )
42
+ console . log ( 'This is not supported.' )
43
+ return false
44
+ }
45
+ return true
46
+ }
47
+
48
+ const updateWatchedFiles = async ( watcher : FSWatcher , base : string , isFirstRun = false ) => {
49
+ try {
50
+ // Start by deleting the old file. If we error out, we don't want to leave the old file around
51
+ await promises . unlink ( join ( base , '.netlify' , 'middleware.js' ) )
52
+ } catch {
53
+ // Ignore, because it's fine if it didn't exist
54
+ }
55
+ // The list of watched files is an object with the directory as the key and an array of files as the value.
56
+ // We need to flatten this into a list of files
57
+ const watchedFiles = toFileList ( watcher . getWatched ( ) )
58
+
59
+ if ( ! shouldFilesBeCompiled ( watchedFiles , isFirstRun ) ) {
60
+ return
61
+ }
62
+
63
+ console . log ( `${ isFirstRun ? 'Building' : 'Rebuilding' } middleware ${ watchedFiles [ 0 ] } ...` )
64
+ await buildMiddlewareFile ( watchedFiles , base )
65
+ console . log ( '...done' )
66
+ }
67
+
10
68
const start = async ( base : string ) => {
11
69
const watcher = watch ( [ 'middleware.js' , 'middleware.ts' , 'src/middleware.js' , 'src/middleware.ts' ] , {
12
70
// Try and ensure renames just emit one event
@@ -16,65 +74,24 @@ const start = async (base: string) => {
16
74
cwd : base ,
17
75
} )
18
76
19
- const update = async ( initial = false ) => {
20
- try {
21
- // Start by deleting the old file. If we error out, we don't want to leave the old file around
22
- await promises . unlink ( join ( base , '.netlify' , 'middleware.js' ) )
23
- } catch {
24
- // Ignore, because it's fine if it didn't exist
25
- }
26
- // The list of watched files is an object with the directory as the key and an array of files as the value.
27
- // We need to flatten this into a list of files
28
- const watchedFiles = fileList ( watcher . getWatched ( ) )
29
- if ( watchedFiles . length === 0 ) {
30
- if ( ! initial ) {
31
- // Only log on subsequent builds, because having it on first build makes it seem like a warning, when it's a normal state
32
- console . log ( 'No middleware found' )
33
- }
34
- return
35
- }
36
- if ( watchedFiles . length > 1 ) {
37
- console . log ( 'Multiple middleware files found:' )
38
- console . log ( watchedFiles . join ( '\n' ) )
39
- console . log ( 'This is not supported.' )
40
- // Return without compiling anything
41
- return
42
- }
43
- console . log ( `${ initial ? 'Building' : 'Rebuilding' } middleware ${ watchedFiles [ 0 ] } ...` )
44
- try {
45
- await build ( {
46
- entryPoints : watchedFiles ,
47
- outfile : join ( base , '.netlify' , 'middleware.js' ) ,
48
- bundle : true ,
49
- format : 'esm' ,
50
- target : 'esnext' ,
51
- } )
52
- } catch ( error ) {
53
- console . error ( error )
54
- return
55
- }
56
-
57
- console . log ( '...done' )
58
- }
59
-
60
77
try {
61
78
watcher
62
79
. on ( 'change' , ( path ) => {
63
80
console . log ( `File ${ path } has been changed` )
64
- update ( )
81
+ updateWatchedFiles ( watcher , base )
65
82
} )
66
83
. on ( 'add' , ( path ) => {
67
84
console . log ( `File ${ path } has been added` )
68
- update ( )
85
+ updateWatchedFiles ( watcher , base )
69
86
} )
70
87
. on ( 'unlink' , ( path ) => {
71
88
console . log ( `File ${ path } has been removed` )
72
- update ( )
89
+ updateWatchedFiles ( watcher , base )
73
90
} )
74
91
. on ( 'ready' , ( ) => {
75
92
console . log ( 'Initial scan complete. Ready for changes' )
76
93
// This only happens on the first scan
77
- update ( true )
94
+ updateWatchedFiles ( watcher , base , true )
78
95
} )
79
96
await new Promise ( ( resolve ) => {
80
97
watcher . on ( 'close' , resolve )
0 commit comments