Skip to content
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

fix(switchable-runtime): Make it possible to switch between edge and server runtime in dev #39327

Merged
merged 22 commits into from Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions packages/next/build/webpack/plugins/middleware-plugin.ts
Expand Up @@ -46,12 +46,6 @@ interface EntryMetadata {
}

const NAME = 'MiddlewarePlugin'
const middlewareManifest: MiddlewareManifest = {
sortedMiddleware: [],
middleware: {},
functions: {},
version: 2,
}

/**
* Checks the value of usingIndirectEval and when it is a set of modules it
Expand Down Expand Up @@ -121,6 +115,12 @@ function getCreateAssets(params: {
}) {
const { compilation, metadataByEntry } = params
return (assets: any) => {
const middlewareManifest: MiddlewareManifest = {
sortedMiddleware: [],
middleware: {},
functions: {},
version: 2,
}
for (const entrypoint of compilation.entrypoints.values()) {
if (!entrypoint.name) {
continue
Expand Down
10 changes: 10 additions & 0 deletions packages/next/server/dev/on-demand-entry-handler.ts
Expand Up @@ -648,12 +648,22 @@ export function onDemandEntryHandler({
},
onServer: () => {
added.set(COMPILER_NAMES.server, addEntry(COMPILER_NAMES.server))
const edgeServerEntry = `${COMPILER_NAMES.edgeServer}${pagePathData.page}`
if (entries[edgeServerEntry]) {
// Runtime switched from edge to server
delete entries[edgeServerEntry]
}
},
onEdgeServer: () => {
added.set(
COMPILER_NAMES.edgeServer,
addEntry(COMPILER_NAMES.edgeServer)
)
const serverEntry = `${COMPILER_NAMES.server}${pagePathData.page}`
if (entries[serverEntry]) {
// Runtime switched from server to edge
delete entries[serverEntry]
}
},
})

Expand Down
184 changes: 184 additions & 0 deletions test/e2e/switchable-runtime/index.test.ts
Expand Up @@ -202,6 +202,190 @@ describe('Switchable runtime', () => {
})
}
})

it('should be possible to switch between runtimes in API routes', async () => {
await check(
() => renderViaHTTP(next.url, '/api/switch-in-dev'),
'server response'
)

// Edge
await next.patchFile(
'pages/api/switch-in-dev.js',
`
export const config = {
runtime: 'experimental-edge',
}

export default () => new Response('edge response')
`
)
await check(
() => renderViaHTTP(next.url, '/api/switch-in-dev'),
'edge response'
)

// Server
await next.patchFile(
'pages/api/switch-in-dev.js',
`
export default function (req, res) {
res.send('server response again')
}
`
)
await check(
() => renderViaHTTP(next.url, '/api/switch-in-dev'),
'server response again'
)

// Edge
await next.patchFile(
'pages/api/switch-in-dev.js',
`
export const config = {
runtime: 'experimental-edge',
}

export default () => new Response('edge response again')
`
)
await check(
() => renderViaHTTP(next.url, '/api/switch-in-dev'),
'edge response again'
)
})

it('should be possible to switch between runtimes in pages', async () => {
await check(
() => renderViaHTTP(next.url, '/switch-in-dev'),
/Hello from edge page/
)

// Server
await next.patchFile(
'pages/switch-in-dev.js',
`
export default function Page() {
return <p>Hello from server page</p>
}
`
)
await check(
() => renderViaHTTP(next.url, '/switch-in-dev'),
/Hello from server page/
)

// Edge
await next.patchFile(
'pages/switch-in-dev.js',
`
export default function Page() {
return <p>Hello from edge page again</p>
}

export const config = {
runtime: 'experimental-edge',
}
`
)
await check(
() => renderViaHTTP(next.url, '/switch-in-dev'),
/Hello from edge page again/
)

// Server
await next.patchFile(
'pages/switch-in-dev.js',
`
export default function Page() {
return <p>Hello from server page again</p>
}
`
)
await check(
() => renderViaHTTP(next.url, '/switch-in-dev'),
/Hello from server page again/
)
})

// Doesn't work, see https://github.com/vercel/next.js/pull/39327
it.skip('should be possible to switch between runtimes with same content', async () => {
const fileContent = await next.readFile(
'pages/api/switch-in-dev-same-content.js'
)
console.log({ fileContent })
await check(
() => renderViaHTTP(next.url, '/api/switch-in-dev-same-content'),
'server response'
)

// Edge
await next.patchFile(
'pages/api/switch-in-dev-same-content.js',
`
export const config = {
runtime: 'experimental-edge',
}

export default () => new Response('edge response')
`
)
await check(
() => renderViaHTTP(next.url, '/api/switch-in-dev-same-content'),
'edge response'
)

// Server - same content as first compilation of the server runtime version
await next.patchFile(
'pages/api/switch-in-dev-same-content.js',
fileContent
)
await check(
() => renderViaHTTP(next.url, '/api/switch-in-dev-same-content'),
'server response'
)
})

it('should recover from syntax error when using edge runtime', async () => {
await check(
() => renderViaHTTP(next.url, '/api/syntax-error-in-dev'),
'edge response'
)

// Syntax error
await next.patchFile(
'pages/api/syntax-error-in-dev.js',
`
export const config = {
runtime: 'experimental-edge',
}

export default => new Response('edge response')
`
)
await check(
() => renderViaHTTP(next.url, '/api/syntax-error-in-dev'),
/Unexpected token/
)

// Fix syntax error
await next.patchFile(
'pages/api/syntax-error-in-dev.js',
`
export default () => new Response('edge response again')

export const config = {
runtime: 'experimental-edge',
}

`
)
await check(
() => renderViaHTTP(next.url, '/api/syntax-error-in-dev'),
'edge response again'
)
})
})
} else {
describe('Switchable runtime (prod)', () => {
Expand Down
@@ -0,0 +1,3 @@
export default (req, res) => {
res.send('server response')
}
3 changes: 3 additions & 0 deletions test/e2e/switchable-runtime/pages/api/switch-in-dev.js
@@ -0,0 +1,3 @@
export default (req, res) => {
res.send('server response')
}
@@ -0,0 +1,5 @@
export default () => new Response('edge response')

export const config = {
runtime: `experimental-edge`,
}
7 changes: 7 additions & 0 deletions test/e2e/switchable-runtime/pages/switch-in-dev.js
@@ -0,0 +1,7 @@
export default function Page() {
return <p>Hello from edge page</p>
}

export const config = {
runtime: 'experimental-edge',
}