Skip to content

feat: add enhanced middleware support #1479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Jul 30, 2022
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5d67f5f
fix: update patch syntax
ascorbic Jul 22, 2022
efdb03d
feat: add support for rewriting middleware responses
ascorbic Jul 22, 2022
e1c41e9
chore: format
ascorbic Jul 22, 2022
d9011d0
chore: add extra content
ascorbic Jul 23, 2022
a2c88b7
chore: use city in demo
ascorbic Jul 23, 2022
ba284d9
feat: add html rewriting
ascorbic Jul 23, 2022
d66e08e
feat: add request header support
ascorbic Jul 23, 2022
55b5282
feat: add rewriting
ascorbic Jul 23, 2022
426a116
chore: move NetlifyReponse into a subpackage
ascorbic Jul 24, 2022
733e352
feat: allow returning `NetlifyReponse` directly
ascorbic Jul 24, 2022
138c225
chore: remove inlined types from middleware demo
ascorbic Jul 24, 2022
0256f25
chore: remove modified toml
ascorbic Jul 24, 2022
f35a285
chore: add demo links
ascorbic Jul 24, 2022
e5df385
chore: add comments to example
ascorbic Jul 25, 2022
2e1a4c6
chore: don't lint generated types
ascorbic Jul 25, 2022
5f5e17d
Merge branch 'main' into mk/rewrite-props-middleware
ascorbic Jul 25, 2022
d2d16df
chore: rename class
ascorbic Jul 25, 2022
e0861cb
chore: add comment about source of htmlrewriter types
ascorbic Jul 26, 2022
9d0f004
refactor: use type guards
ascorbic Jul 26, 2022
8deaba4
chore: rename classes
ascorbic Jul 26, 2022
5215688
chore: rename again
ascorbic Jul 26, 2022
3854370
chore: rename again
ascorbic Jul 26, 2022
e54fec6
chore: update example
ascorbic Jul 26, 2022
468a0d3
chore: make req a subclass of Request
ascorbic Jul 26, 2022
d4c0dc0
chore: switch from hidden fields to global map
ascorbic Jul 27, 2022
d5f2b95
Merge branch 'main' into mk/rewrite-props-middleware
ascorbic Jul 27, 2022
71fa122
Merge branch 'main' into mk/rewrite-props-middleware
ascorbic Jul 29, 2022
0fd6c33
ci: add cypress middleware tests
ascorbic Jul 29, 2022
328a584
ci: add tests for middleware headers
ascorbic Jul 29, 2022
4f6a2aa
ci: add tests for enhanced middleware
ascorbic Jul 29, 2022
1cf3e1f
chore: fix test
ascorbic Jul 29, 2022
33ade90
fix: handle other HTTP verbs
ascorbic Jul 29, 2022
9f4044c
feat: add helper methods
ascorbic Jul 29, 2022
78c8225
fix: less flaky test
ascorbic Jul 29, 2022
6c5664e
Merge branch 'main' into mk/rewrite-props-middleware
nickytonline Jul 29, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ node_modules
test
lib
demos
plugin/src/templates/edge
plugin/src/templates/edge
plugin/lib
plugin/dist-types
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Temporary Items
demos/default/.next
.parcel-cache
plugin/lib
plugin/dist-types

# Cypress
cypress/screenshots
5 changes: 3 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ node_modules
lib
tsconfig.json
demos/nx-next-monorepo-demo
plugin/src/templates/edge

plugin/CHANGELOG.md
plugin/CHANGELOG.md
plugin/lib
plugin/dist-types
52 changes: 47 additions & 5 deletions demos/middleware/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,53 @@
import { NextResponse } from 'next/server'
import { NextFetchEvent, NextRequest } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest, ev: NextFetchEvent) {
import { MiddlewareRequest } from '@netlify/plugin-nextjs/middleware'

export async function middleware(req: NextRequest) {
let response
const {
nextUrl: { pathname },
} = request
} = req

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[dust] Use the full name request and response for variable names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request and response are already used for the MiddlewareRequest and MiddlewareResponse. I considered changing them to nextRequest and nextResponse but thought it made the code examples a bit verbose. Hard to say which is better tbh

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realise I've mixed the different styles, so yeah this should be tidied up in a follow-up.


const request = new MiddlewareRequest(req)

if (pathname.startsWith('/static')) {
// Unlike NextResponse.next(), this actually sends the request to the origin
const res = await request.next()
const message = `This was static but has been transformed in ${req.geo.city}`

// Transform the response page data
res.transformData((data) => {
data.pageProps.message = message
data.pageProps.showAd = true
return data
})

// Transform the response HTML
res.rewriteHTML('p[id=message]', {
text(textChunk) {
if (textChunk.lastInTextNode) {
textChunk.replace(message)
} else {
textChunk.remove()
}
},
})

return res
}

if (pathname.startsWith('/api/hello')) {
// Add a header to the request
req.headers.set('x-hello', 'world')
return request.next()
}

if (pathname.startsWith('/headers')) {
// Add a header to the rewritten request
req.headers.set('x-hello', 'world')
return request.rewrite('/api/hello')
}

if (pathname.startsWith('/cookies')) {
response = NextResponse.next()
Expand All @@ -15,15 +57,15 @@ export function middleware(request: NextRequest, ev: NextFetchEvent) {

if (pathname.startsWith('/shows')) {
if (pathname.startsWith('/shows/rewrite-absolute')) {
response = NextResponse.rewrite(new URL('/shows/100', request.url))
response = NextResponse.rewrite(new URL('/shows/100', req.url))
response.headers.set('x-modified-in-rewrite', 'true')
}
if (pathname.startsWith('/shows/rewrite-external')) {
response = NextResponse.rewrite('http://example.com/')
response.headers.set('x-modified-in-rewrite', 'true')
}
if (pathname.startsWith('/shows/rewriteme')) {
const url = request.nextUrl.clone()
const url = req.nextUrl.clone()
url.pathname = '/shows/100'
response = NextResponse.rewrite(url)
response.headers.set('x-modified-in-rewrite', 'true')
Expand Down
1 change: 1 addition & 0 deletions demos/middleware/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const nextConfig = {
// your project has ESLint errors.
ignoreDuringBuilds: true,
},
generateBuildId: () => 'build-id',
Copy link

@nickytonline nickytonline Jul 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

module.exports = nextConfig
4 changes: 2 additions & 2 deletions demos/middleware/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
"ntl": "ntl-internal"
},
"dependencies": {
"@netlify/plugin-nextjs": "*",
"next": "^12.2.0",
"react": "18.0.0",
"react-dom": "18.0.0"
},
"devDependencies": {
"@netlify/plugin-nextjs": "*",
"@types/fs-extra": "^9.0.13",
"@types/jest": "^27.4.1",
"@types/node": "^17.0.25",
Expand All @@ -23,4 +23,4 @@
"npm-run-all": "^4.1.5",
"typescript": "^4.6.3"
}
}
}
2 changes: 1 addition & 1 deletion demos/middleware/pages/api/hello.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction

export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
res.status(200).json({ name: 'John Doe', headers: req.headers })
}
9 changes: 9 additions & 0 deletions demos/middleware/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ export default function Home() {
Cookie API
</Link>
</p>
<p>
<Link href="/api/hello">Adds `x-hello` request header</Link>
</p>
<p>
<Link href="/static">Rewrite static page content</Link>
</p>
<p>
<Link href="/headers">Adds `x-hello` request header to a rewrite</Link>
</p>
</main>
</div>
)
Expand Down
24 changes: 24 additions & 0 deletions demos/middleware/pages/static.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const Page = ({ message, showAd }) => (
<div>
<p id="message">{message}</p>
{showAd ? (
<div>
<p>This is an ad that isn't shown by default</p>
<img src="http://placekitten.com/400/300" />
</div>
) : (
<p>No ads for me</p>
)}
</div>
)

export async function getStaticProps(context) {
return {
props: {
message: 'This is a static page',
showAd: false,
},
}
}

export default Page
53 changes: 22 additions & 31 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading