Skip to content

Commit 6fcb623

Browse files
ijjkTimer
authored andcommitted
Add support for exporting from serverless build (vercel#9744)
* Add support for exporting from serverless build * Add more tests * Update syntax * Dont add dynamic params in worker * Update amphtml rel for serverless tests * Update tests again * Update dynamic params populating * Fix params parsing * Pass params separately
1 parent fafb466 commit 6fcb623

File tree

46 files changed

+1040
-31
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1040
-31
lines changed

packages/next/build/webpack/loaders/next-serverless-loader.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ const nextServerlessLoader: loader.Loader = function() {
104104
105105
export const config = ComponentInfo['confi' + 'g'] || {}
106106
export const _app = App
107-
export async function renderReqToHTML(req, res, fromExport) {
107+
export async function renderReqToHTML(req, res, fromExport, _renderOpts, _params) {
108108
const options = {
109109
App,
110110
Document,
@@ -117,6 +117,7 @@ const nextServerlessLoader: loader.Loader = function() {
117117
assetPrefix: "${assetPrefix}",
118118
ampBindInitData: ${ampBindInitData === true ||
119119
ampBindInitData === 'true'},
120+
..._renderOpts
120121
}
121122
let sprData = false
122123
@@ -176,7 +177,7 @@ const nextServerlessLoader: loader.Loader = function() {
176177
`
177178
: `const nowParams = null;`
178179
}
179-
let result = await renderToHTML(req, res, "${page}", Object.assign({}, unstable_getStaticProps ? {} : parsedUrl.query, nowParams ? nowParams : params), renderOpts)
180+
let result = await renderToHTML(req, res, "${page}", Object.assign({}, unstable_getStaticProps ? {} : parsedUrl.query, nowParams ? nowParams : params, _params), renderOpts)
180181
181182
if (sprData && !fromExport) {
182183
const payload = JSON.stringify(renderOpts.sprData)

packages/next/export/index.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,6 @@ export default async function(
116116
const subFolders = nextConfig.exportTrailingSlash
117117
const isLikeServerless = nextConfig.target !== 'server'
118118

119-
if (!options.buildExport && isLikeServerless) {
120-
throw new Error(
121-
'Cannot export when target is not server. https://err.sh/zeit/next.js/next-export-serverless'
122-
)
123-
}
124-
125119
log(`> using build directory: ${distDir}`)
126120

127121
if (!existsSync(distDir)) {
@@ -132,7 +126,12 @@ export default async function(
132126

133127
const buildId = readFileSync(join(distDir, BUILD_ID_FILE), 'utf8')
134128
const pagesManifest =
135-
!options.pages && require(join(distDir, SERVER_DIRECTORY, PAGES_MANIFEST))
129+
!options.pages &&
130+
require(join(
131+
distDir,
132+
isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY,
133+
PAGES_MANIFEST
134+
))
136135

137136
let prerenderManifest
138137
try {

packages/next/export/worker.js

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import mkdirpModule from 'mkdirp'
22
import { promisify } from 'util'
3+
import url from 'url'
34
import { extname, join, dirname, sep } from 'path'
45
import { renderToHTML } from '../next-server/server/render'
56
import { writeFile, access } from 'fs'
@@ -40,14 +41,18 @@ export default async function({
4041
const { page } = pathMap
4142
const filePath = path === '/' ? '/index' : path
4243
const ampPath = `${filePath}.amp`
44+
let params
4345

4446
// Check if the page is a specified dynamic route
4547
if (isDynamicRoute(page) && page !== path) {
46-
const params = getRouteMatcher(getRouteRegex(page))(path)
48+
params = getRouteMatcher(getRouteRegex(page))(path)
4749
if (params) {
48-
query = {
49-
...query,
50-
...params,
50+
// we have to pass these separately for serverless
51+
if (!serverless) {
52+
query = {
53+
...query,
54+
...params,
55+
}
5156
}
5257
} else {
5358
throw new Error(
@@ -107,26 +112,40 @@ export default async function({
107112
}
108113

109114
if (serverless) {
110-
const mod = require(join(
115+
const curUrl = url.parse(req.url, true)
116+
req.url = url.format({
117+
...curUrl,
118+
query: {
119+
...curUrl.query,
120+
...query,
121+
},
122+
})
123+
const { Component: mod } = await loadComponents(
111124
distDir,
112-
'serverless/pages',
113-
(page === '/' ? 'index' : page) + '.js'
114-
))
125+
buildId,
126+
page,
127+
serverless
128+
)
115129

116-
// for non-dynamic SPR pages we should have already
117-
// prerendered the file
118-
if (renderedDuringBuild(mod.unstable_getStaticProps)) return results
130+
// if it was auto-exported the HTML is loaded here
131+
if (typeof mod === 'string') {
132+
html = mod
133+
} else {
134+
// for non-dynamic SPR pages we should have already
135+
// prerendered the file
136+
if (renderedDuringBuild(mod.unstable_getStaticProps)) return results
119137

120-
if (mod.unstable_getStaticProps && !htmlFilepath.endsWith('.html')) {
121-
// make sure it ends with .html if the name contains a dot
122-
htmlFilename += '.html'
123-
htmlFilepath += '.html'
124-
}
138+
if (mod.unstable_getStaticProps && !htmlFilepath.endsWith('.html')) {
139+
// make sure it ends with .html if the name contains a dot
140+
htmlFilename += '.html'
141+
htmlFilepath += '.html'
142+
}
125143

126-
renderMethod = mod.renderReqToHTML
127-
const result = await renderMethod(req, res, true)
128-
curRenderOpts = result.renderOpts || {}
129-
html = result.html
144+
renderMethod = mod.renderReqToHTML
145+
const result = await renderMethod(req, res, true, { ampPath }, params)
146+
curRenderOpts = result.renderOpts || {}
147+
html = result.html
148+
}
130149

131150
if (!html) {
132151
throw new Error(`Failed to render serverless page`)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
target: 'serverless',
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { useAmp } from 'next/amp'
2+
3+
export const config = { amp: 'hybrid' }
4+
5+
export default () => <p>I'm an {useAmp() ? 'AMP' : 'normal'} page</p>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export default () => <p>Simple hybrid amp/non-amp page</p>
2+
export const config = { amp: 'hybrid' }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { useAmp } from 'next/amp'
2+
3+
export const config = { amp: 'hybrid' }
4+
5+
export default () => <p>I'm an {useAmp() ? 'AMP' : 'normal'} page</p>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export default () => <p>I am an AMP only page</p>
2+
export const config = { amp: true }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const config = { amp: 'hybrid' }
2+
3+
export default () => <p>I'm an AMP page</p>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Docs(props) {
2+
return <div>Hello again 👋</div>
3+
}

0 commit comments

Comments
 (0)