Skip to content

Commit b9e87d1

Browse files
piehkodiakhq[bot]
andauthored
fix: don't ever execute middleware in lambda (#2249)
* test: add test for preview mode when using middleware * fix: skip ever trying to run middleware in lambda --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
1 parent 85ac3e8 commit b9e87d1

File tree

7 files changed

+102
-11
lines changed

7 files changed

+102
-11
lines changed

cypress/e2e/middleware/preview.cy.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
describe('Preview Mode', () => {
2+
it('enters and exits preview mode', () => {
3+
Cypress.Cookies.debug(true)
4+
cy.getCookies().then((cookie) => cy.log('cookies', cookie))
5+
6+
cy.intercept('/previewTest', (req) => {
7+
req.continue((res) => {
8+
expect(res.headers?.['x-middleware-executed']).to.equal('true')
9+
})
10+
}).as('previewTestVisit')
11+
12+
// preview mode is off by default
13+
cy.visit('/previewTest')
14+
cy.findByText('Is preview? No', { selector: 'h1' })
15+
16+
// enter preview mode
17+
cy.request('/api/enterPreview').then((response) => {
18+
expect(response.body).to.have.property('name', 'preview mode')
19+
})
20+
21+
// exptected content is rendered
22+
cy.visit('/previewTest')
23+
cy.findByText('Is preview? Yes!', { selector: 'h1' })
24+
25+
// exit preview mode
26+
cy.request('/api/exitPreview')
27+
cy.visit('/previewTest')
28+
cy.findByText('Is preview? No', { selector: 'h1' })
29+
30+
// we should hit /previewTest 3 times (before entering preview, after entering preview, after exiting preview)
31+
// this assertion is mainly to ensure interception works and assertion on response header is made
32+
cy.get('@previewTestVisit.all').should('have.length', 3)
33+
})
34+
})

demos/middleware/middleware.ts

+18-11
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ export async function middleware(req: NextRequest) {
1515
headers.set('x-hello', 'world')
1616
return NextResponse.next({
1717
request: {
18-
headers
19-
}
18+
headers,
19+
},
2020
})
2121
}
22-
22+
2323
const request = new MiddlewareRequest(req)
2424

2525
// skipMiddlewareUrlNormalize next config option is used so we have to try to match both html path and data blob path
@@ -41,12 +41,11 @@ export async function middleware(req: NextRequest) {
4141
// skipMiddlewareUrlNormalize next config option is used so we have to try to match both html path and data blob path
4242
if (pathname.startsWith('/request-rewrite') || pathname.endsWith('/request-rewrite.json')) {
4343
// request.rewrite() should return the MiddlewareResponse object instead of the Response object.
44-
const res = await request.rewrite('/static-rewrite',
45-
{
44+
const res = await request.rewrite('/static-rewrite', {
4645
headers: {
4746
'x-rewrite-test': 'hello',
48-
'x-rewrite-test-2': 'hello-2'
49-
}
47+
'x-rewrite-test-2': 'hello-2',
48+
},
5049
})
5150
const message = `This was static (& escaping test &amp;) but has been transformed in ${req.geo?.city}`
5251

@@ -90,7 +89,7 @@ export async function middleware(req: NextRequest) {
9089
return response
9190
}
9291

93-
if(pathname.startsWith('/matcher-cookie')) {
92+
if (pathname.startsWith('/matcher-cookie')) {
9493
response = NextResponse.next()
9594
response.cookies.set('missingCookie', 'true')
9695
return response
@@ -109,6 +108,13 @@ export async function middleware(req: NextRequest) {
109108
return response
110109
}
111110

111+
if (pathname.startsWith('/previewTest')) {
112+
response = NextResponse.next()
113+
114+
response.headers.set('x-middleware-executed', 'true')
115+
return response
116+
}
117+
112118
if (pathname.includes('locale-preserving-rewrite')) {
113119
return NextResponse.rewrite(new URL('/locale-test', req.url))
114120
}
@@ -167,8 +173,8 @@ export const config = {
167173
'/:all*/locale-preserving-rewrite',
168174
'/cookies/:path*',
169175
{ source: '/static' },
170-
{source: '/request-rewrite' },
171-
{ source: '/matcher-cookie'},
176+
{ source: '/request-rewrite' },
177+
{ source: '/matcher-cookie' },
172178
{ source: '/shows/((?!99|88).*)' },
173179
{
174180
source: '/conditional',
@@ -186,8 +192,9 @@ export const config = {
186192
{
187193
type: 'cookie',
188194
key: 'missingCookie',
189-
}
195+
},
190196
],
191197
},
198+
'/previewTest',
192199
],
193200
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default async function preview(req, res) {
2+
// Enable Preview Mode by setting the cookies
3+
res.setPreviewData({})
4+
5+
res.status(200).json({ name: 'preview mode' })
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default async function exit(_, res) {
2+
// Exit the current user from "Preview Mode". This function accepts no args.
3+
res.clearPreviewData()
4+
5+
// Redirect the user back to the index page.
6+
res.writeHead(307, { Location: '/' })
7+
res.end()
8+
}

demos/middleware/pages/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ export default function Home() {
4848
<p>
4949
<Link href="/headers">Adds `x-hello` request header to a rewrite</Link>
5050
</p>
51+
<p>
52+
<Link href="/previewTest">Preview mode</Link>
53+
</p>
5154
</main>
5255
</div>
5356
)

demos/middleware/pages/previewTest.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import Link from 'next/link'
2+
3+
const StaticTest = ({ isPreview }) => {
4+
return (
5+
<div>
6+
<h1>Is preview? {isPreview ? 'Yes!' : 'No'}</h1>
7+
<p>
8+
<a href={isPreview ? '/api/exitPreview' : '/api/enterPreview'}>
9+
{isPreview ? 'Exit Preview' : 'Enter Preview'}
10+
</a>
11+
</p>
12+
<Link href="/">Go back home</Link>
13+
</div>
14+
)
15+
}
16+
17+
export const getStaticProps = async ({ preview }) => {
18+
return {
19+
props: {
20+
isPreview: Boolean(preview),
21+
},
22+
}
23+
}
24+
25+
export default StaticTest

packages/runtime/src/templates/server.ts

+8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface NetlifyConfig {
1818
revalidateToken?: string
1919
}
2020

21+
// eslint-disable-next-line max-lines-per-function
2122
const getNetlifyNextServer = (NextServer: NextServerType) => {
2223
class NetlifyNextServer extends NextServer {
2324
private netlifyConfig: NetlifyConfig
@@ -118,6 +119,13 @@ const getNetlifyNextServer = (NextServer: NextServerType) => {
118119
}
119120
}
120121

122+
// eslint-disable-next-line class-methods-use-this, require-await
123+
async runMiddleware(): Promise<{ finished: boolean }> {
124+
return {
125+
finished: false,
126+
}
127+
}
128+
121129
private getNetlifyPathsForRoute(route: string): string[] {
122130
const { i18n } = this.nextConfig
123131
const { routes, dynamicRoutes } = this.netlifyPrerenderManifest

0 commit comments

Comments
 (0)