Skip to content

Commit 0eb9eb1

Browse files
committed
fix: watch middleware in src folder
1 parent e915f1f commit 0eb9eb1

File tree

3 files changed

+98
-68
lines changed

3 files changed

+98
-68
lines changed

package-lock.json

Lines changed: 26 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/runtime/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@netlify/ipx": "^1.3.1",
1717
"@vercel/node-bridge": "^2.1.0",
1818
"chalk": "^4.1.2",
19+
"chokidar": "^3.5.3",
1920
"destr": "^1.1.1",
2021
"execa": "^5.1.1",
2122
"follow-redirects": "^1.15.2",

packages/runtime/src/helpers/dev.ts

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,92 @@
1-
import type { Buffer } from 'buffer'
2-
import { resolve } from 'path'
3-
import { Transform } from 'stream'
1+
import { promises } from 'fs'
2+
import { join } from 'path'
43

54
import { OnPreBuild } from '@netlify/build'
6-
import execa from 'execa'
7-
import { unlink } from 'fs-extra'
8-
import mergeStream from 'merge-stream'
5+
import { build } from '@netlify/esbuild'
6+
import { watch } from 'chokidar'
97

108
import { writeDevEdgeFunction } from './edge'
119
import { patchNextFiles } from './files'
1210

11+
const fileList = (watched: Record<string, Array<string>>) =>
12+
Object.entries(watched).flatMap(([dir, files]) => files.map((file) => `${dir}/${file}`))
13+
14+
let watcher
15+
1316
// The types haven't been updated yet
1417
export const onPreDev: OnPreBuild = async ({ constants, netlifyConfig }) => {
1518
const base = netlifyConfig.build.base ?? process.cwd()
1619

1720
// Need to patch the files, because build might not have been run
1821
await patchNextFiles(base)
1922

20-
// Clean up old functions
21-
await unlink(resolve('.netlify', 'middleware.js')).catch(() => {
22-
// Ignore if it doesn't exist
23-
})
2423
await writeDevEdgeFunction(constants)
2524

26-
// Eventually we might want to do this via esbuild's API, but for now the CLI works fine
27-
const common = [`--bundle`, `--outdir=${resolve('.netlify')}`, `--format=esm`, `--target=esnext`, '--watch']
28-
const opts = {
29-
all: true,
30-
env: { ...process.env, FORCE_COLOR: '1' },
31-
}
32-
// TypeScript
33-
const tsout = execa(`esbuild`, [...common, resolve(base, 'middleware.ts')], opts).all
34-
35-
// JavaScript
36-
const jsout = execa(`esbuild`, [...common, resolve(base, 'middleware.js')], opts).all
25+
watcher = watch(['middleware.js', 'middleware.ts', 'src/middleware.js', 'src/middleware.ts'], {
26+
persistent: true,
27+
atomic: true,
28+
ignoreInitial: true,
29+
cwd: base,
30+
})
3731

38-
const filter = new Transform({
39-
transform(chunk: Buffer, encoding, callback) {
40-
const str = chunk.toString(encoding)
32+
const update = async (initial = false) => {
33+
try {
34+
await promises.unlink(join(base, '.netlify', 'middleware.js'))
35+
} catch {}
4136

42-
// Skip if message includes this, because we run even when the files are missing
43-
if (!str.includes('[ERROR] Could not resolve')) {
44-
this.push(chunk)
37+
const watchedFiles = fileList(watcher.getWatched())
38+
if (watchedFiles.length === 0) {
39+
if (!initial) {
40+
console.log('No middleware found')
4541
}
46-
callback()
47-
},
48-
})
42+
return
43+
}
44+
if (watchedFiles.length > 1) {
45+
console.log('Multiple middleware files found:')
46+
console.log(watchedFiles.join('\n'))
47+
console.log('This is not supported.')
48+
49+
return
50+
}
51+
console.log(`${initial ? 'Building' : 'Rebuilding'} middleware ${watchedFiles[0]}...`)
52+
try {
53+
await build({
54+
entryPoints: watchedFiles,
55+
outfile: '.next/middleware.js',
56+
bundle: true,
57+
format: 'esm',
58+
target: 'esnext',
59+
})
60+
} catch (error) {
61+
console.error(error)
62+
return
63+
}
4964

50-
mergeStream(tsout, jsout).pipe(filter).pipe(process.stdout)
65+
console.log('...done')
66+
}
5167

52-
// Don't return the promise because we don't want to wait for the child process to finish
68+
watcher
69+
.on('change', (path) => {
70+
console.log(`File ${path} has been changed`)
71+
update()
72+
})
73+
.on('add', (path) => {
74+
console.log(`File ${path} has been added`)
75+
update()
76+
})
77+
.on('unlink', (path) => {
78+
console.log(`File ${path} has been removed`)
79+
update()
80+
})
81+
.on('ready', () => {
82+
console.log('Initial scan complete. Ready for changes')
83+
update(true)
84+
})
85+
86+
const promise = new Promise<void>((resolve) => {
87+
process.on('SIGINT', () => {
88+
watcher.close()
89+
resolve()
90+
})
91+
})
5392
}

0 commit comments

Comments
 (0)