Skip to content

Commit

Permalink
Merge branch 'canary' into rfc17141-next-image-api
Browse files Browse the repository at this point in the history
  • Loading branch information
styfle committed Oct 15, 2020
2 parents 6e0c905 + 2a94ae0 commit c53aec6
Show file tree
Hide file tree
Showing 27 changed files with 344 additions and 53 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Expand Up @@ -17,5 +17,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "9.5.6-canary.1"
"version": "9.5.6-canary.2"
}
2 changes: 1 addition & 1 deletion packages/create-next-app/package.json
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-next/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/eslint-plugin-next",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"description": "ESLint plugin for NextJS.",
"main": "lib/index.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-bundle-analyzer/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-codemod/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/codemod",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"license": "MIT",
"dependencies": {
"chalk": "4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-env/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/env",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-mdx/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/mdx",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-google-analytics/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-google-analytics",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-google-analytics"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-sentry/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-sentry",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-sentry"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-storybook/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-storybook",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-storybook"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-module/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-module",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)",
"main": "dist/polyfill-module.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-nomodule/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-nomodule",
"version": "9.5.6-canary.1",
"version": "9.5.6-canary.2",
"description": "A polyfill for non-dead, nomodule browsers.",
"main": "dist/polyfill-nomodule.js",
"license": "MIT",
Expand Down
28 changes: 24 additions & 4 deletions packages/next/build/index.ts
Expand Up @@ -97,6 +97,7 @@ export type PrerenderManifest = {
version: 2
routes: { [route: string]: SsgRoute }
dynamicRoutes: { [route: string]: DynamicSsgRoute }
notFoundRoutes: string[]
preview: __ApiPreviewProps
}

Expand Down Expand Up @@ -307,6 +308,15 @@ export default async function build(
dataRouteRegex: string
namedDataRouteRegex?: string
}>
i18n?: {
locales: string[]
defaultLocale: string[]
domains: Array<{
domain: string
defaultLocale: string
locales: string[]
}>
}
} = {
version: 3,
pages404: true,
Expand All @@ -326,6 +336,7 @@ export default async function build(
}
}),
dataRoutes: [],
i18n: config.experimental.i18n || undefined,
}

await promises.mkdir(distDir, { recursive: true })
Expand Down Expand Up @@ -704,6 +715,7 @@ export default async function build(

const finalPrerenderRoutes: { [route: string]: SsgRoute } = {}
const tbdPrerenderRoutes: string[] = []
let ssgNotFoundPaths: string[] = []

if (postCompileSpinner) postCompileSpinner.stopAndPersist()

Expand All @@ -721,6 +733,7 @@ export default async function build(
const exportConfig: any = {
...config,
initialPageRevalidationMap: {},
ssgNotFoundPaths: [] as string[],
// Default map will be the collection of automatic statically exported
// pages and incremental pages.
// n.b. we cannot handle this above in combinedPages because the dynamic
Expand Down Expand Up @@ -812,6 +825,7 @@ export default async function build(
const postBuildSpinner = createSpinner({
prefixText: `${Log.prefixes.info} Finalizing page optimization`,
})
ssgNotFoundPaths = exportConfig.ssgNotFoundPaths

// remove server bundles that were exported
for (const page of staticPages) {
Expand Down Expand Up @@ -865,11 +879,12 @@ export default async function build(
}

const { i18n } = config.experimental
const isNotFound = ssgNotFoundPaths.includes(page)

// for SSG files with i18n the non-prerendered variants are
// output with the locale prefixed so don't attempt moving
// without the prefix
if (!i18n || additionalSsgFile) {
if ((!i18n || additionalSsgFile) && !isNotFound) {
await promises.mkdir(path.dirname(dest), { recursive: true })
await promises.rename(orig, dest)
} else if (i18n && !isSsg) {
Expand All @@ -882,9 +897,14 @@ export default async function build(
if (additionalSsgFile) return

for (const locale of i18n.locales) {
const curPath = `/${locale}${page === '/' ? '' : page}`
const localeExt = page === '/' ? path.extname(file) : ''
const relativeDestNoPages = relativeDest.substr('pages/'.length)

if (isSsg && ssgNotFoundPaths.includes(curPath)) {
continue
}

const updatedRelativeDest = path.join(
'pages',
locale + localeExt,
Expand All @@ -904,9 +924,7 @@ export default async function build(
)

if (!isSsg) {
pagesManifest[
`/${locale}${page === '/' ? '' : page}`
] = updatedRelativeDest
pagesManifest[curPath] = updatedRelativeDest
}
await promises.mkdir(path.dirname(updatedDest), { recursive: true })
await promises.rename(updatedOrig, updatedDest)
Expand Down Expand Up @@ -1057,6 +1075,7 @@ export default async function build(
version: 2,
routes: finalPrerenderRoutes,
dynamicRoutes: finalDynamicRoutes,
notFoundRoutes: ssgNotFoundPaths,
preview: previewProps,
}

Expand All @@ -1076,6 +1095,7 @@ export default async function build(
routes: {},
dynamicRoutes: {},
preview: previewProps,
notFoundRoutes: [],
}
await promises.writeFile(
path.join(distDir, PRERENDER_MANIFEST),
Expand Down
22 changes: 16 additions & 6 deletions packages/next/export/index.ts
Expand Up @@ -285,6 +285,12 @@ export default async function exportApp(

const { i18n } = nextConfig.experimental

if (i18n && !options.buildExport) {
throw new Error(
`i18n support is not compatible with next export. See here for more info on deploying: https://nextjs.org/docs/deployment`
)
}

// Start the rendering process
const renderOpts = {
dir,
Expand Down Expand Up @@ -467,13 +473,17 @@ export default async function exportApp(
renderError = renderError || !!result.error
if (!!result.error) errorPaths.push(path)

if (
options.buildExport &&
typeof result.fromBuildExportRevalidate !== 'undefined'
) {
configuration.initialPageRevalidationMap[path] =
result.fromBuildExportRevalidate
if (options.buildExport) {
if (typeof result.fromBuildExportRevalidate !== 'undefined') {
configuration.initialPageRevalidationMap[path] =
result.fromBuildExportRevalidate
}

if (result.ssgNotFound === true) {
configuration.ssgNotFoundPaths.push(path)
}
}

if (progress) progress()
})
)
Expand Down
16 changes: 12 additions & 4 deletions packages/next/export/worker.ts
Expand Up @@ -55,6 +55,7 @@ interface ExportPageResults {
ampValidations: AmpValidation[]
fromBuildExportRevalidate?: number
error?: boolean
ssgNotFound?: boolean
}

interface RenderOpts {
Expand Down Expand Up @@ -252,11 +253,11 @@ export default async function exportPage({
// @ts-ignore
params
)
curRenderOpts = result.renderOpts || {}
html = result.html
curRenderOpts = (result as any).renderOpts || {}
html = (result as any).html
}

if (!html) {
if (!html && !(curRenderOpts as any).ssgNotFound) {
throw new Error(`Failed to render serverless page`)
}
} else {
Expand Down Expand Up @@ -311,6 +312,7 @@ export default async function exportPage({
html = await renderMethod(req, res, page, query, curRenderOpts)
}
}
results.ssgNotFound = (curRenderOpts as any).ssgNotFound

const validateAmp = async (
rawAmpHtml: string,
Expand All @@ -334,7 +336,9 @@ export default async function exportPage({
}

if (curRenderOpts.inAmpMode && !curRenderOpts.ampSkipValidation) {
await validateAmp(html, path, curRenderOpts.ampValidatorPath)
if (!results.ssgNotFound) {
await validateAmp(html, path, curRenderOpts.ampValidatorPath)
}
} else if (curRenderOpts.hybridAmp) {
// we need to render the AMP version
let ampHtmlFilename = `${ampPath}${sep}index.html`
Expand Down Expand Up @@ -396,6 +400,10 @@ export default async function exportPage({
}
results.fromBuildExportRevalidate = (curRenderOpts as any).revalidate

if (results.ssgNotFound) {
// don't attempt writing to disk if getStaticProps returned not found
return results
}
await promises.writeFile(htmlFilepath, html, 'utf8')
return results
} catch (error) {
Expand Down
18 changes: 16 additions & 2 deletions packages/next/next-server/lib/router/router.ts
Expand Up @@ -299,6 +299,8 @@ const manualScrollRestoration =
typeof window !== 'undefined' &&
'scrollRestoration' in window.history

const SSG_DATA_NOT_FOUND_ERROR = 'SSG Data NOT_FOUND'

function fetchRetry(url: string, attempts: number): Promise<any> {
return fetch(url, {
// Cookies are required to be present for Next.js' SSG "Preview Mode".
Expand All @@ -318,9 +320,13 @@ function fetchRetry(url: string, attempts: number): Promise<any> {
if (attempts > 1 && res.status >= 500) {
return fetchRetry(url, attempts - 1)
}
if (res.status === 404) {
// TODO: handle reloading in development from fallback returning 200
// to on-demand-entry-handler causing it to reload periodically
throw new Error(SSG_DATA_NOT_FOUND_ERROR)
}
throw new Error(`Failed to load static props`)
}

return res.json()
})
}
Expand All @@ -330,7 +336,8 @@ function fetchNextData(dataHref: string, isServerRender: boolean) {
// We should only trigger a server-side transition if this was caused
// on a client-side transition. Otherwise, we'd get into an infinite
// loop.
if (!isServerRender) {

if (!isServerRender || err.message === 'SSG Data NOT_FOUND') {
markLoadingError(err)
}
throw err
Expand Down Expand Up @@ -900,6 +907,13 @@ export default class Router implements BaseRouter {
// 3. Internal error while loading the page

// So, doing a hard reload is the proper way to deal with this.
if (process.env.NODE_ENV === 'development') {
// append __next404 query to prevent fallback from being re-served
// on reload in development
if (err.message === SSG_DATA_NOT_FOUND_ERROR && this.isSsr) {
as += `${as.indexOf('?') > -1 ? '&' : '?'}__next404=1`
}
}
window.location.href = as

// Changing the URL doesn't block executing the current code path.
Expand Down

0 comments on commit c53aec6

Please sign in to comment.