diff --git a/packages/next-server/server/render.tsx b/packages/next-server/server/render.tsx
index d37a29a523b227954a56e2112b4b74019c926a3f..bf499dfc28227a2ea3035d39aac8f69a67e7ea26 100644
--- a/packages/next-server/server/render.tsx
+++ b/packages/next-server/server/render.tsx
@@ -115,6 +115,7 @@ type RenderOpts = {
err?: Error | null
nextExport?: boolean
dev?: boolean
+ ampPath?: string
amphtml?: boolean
hasAmp?: boolean
buildManifest: BuildManifest
@@ -140,6 +141,7 @@ function renderDocument(
dynamicImportsIds,
err,
dev,
+ ampPath,
amphtml,
hasAmp,
staticMarkup,
@@ -151,6 +153,7 @@ function renderDocument(
docProps: any
pathname: string
query: ParsedUrlQuery
+ ampPath: string,
amphtml: boolean
hasAmp: boolean,
dynamicImportsIds: string[]
@@ -177,6 +180,7 @@ function renderDocument(
err: err ? serializeError(dev, err) : undefined, // Error if one happened, otherwise don't sent in the resulting HTML
}}
ampEnabled={ampEnabled}
+ ampPath={ampPath}
amphtml={amphtml}
hasAmp={hasAmp}
staticMarkup={staticMarkup}
@@ -205,6 +209,7 @@ export async function renderToHTML(
staticMarkup = false,
amphtml = false,
hasAmp = false,
+ ampPath = '',
App,
Document,
Component,
@@ -314,6 +319,7 @@ export async function renderToHTML(
props,
docProps,
pathname,
+ ampPath,
amphtml,
hasAmp,
query,
diff --git a/packages/next-server/server/require.ts b/packages/next-server/server/require.ts
index 01685e381ad9073cecbcdf9f45f0412488367136..061ce5adab9f2ec2658fb19ffc301556f4ed0326 100644
--- a/packages/next-server/server/require.ts
+++ b/packages/next-server/server/require.ts
@@ -1,4 +1,5 @@
import {join} from 'path'
+import { isAmpFile } from './utils'
import {PAGES_MANIFEST, SERVER_DIRECTORY} from 'next-server/constants'
import { normalizePagePath } from './normalize-page-path'
@@ -53,13 +54,12 @@ export function getPagePath(page: string, distDir: string, opts: PagePathOptions
export function requirePage(page: string, distDir: string, opts: PagePathOptions = {}): any {
const pagePath = getPagePath(page, distDir, opts)
- const isAmp = pagePath.indexOf('.amp.') > -1
+ const isAmp = isAmpFile(pagePath)
let hasAmp = false
if (!isAmp) {
try {
- const ampPage = getPagePath(page, distDir, { amphtml: true })
- hasAmp = Boolean(ampPage && ampPage.indexOf('.amp') > -1)
+ hasAmp = isAmpFile(getPagePath(page, distDir, { amphtml: true }))
} catch (_) {}
}
opts.amphtml = opts.amphtml || isAmp
diff --git a/packages/next-server/server/utils.ts b/packages/next-server/server/utils.ts
index a1bdb4fa1b42d0fae5fc5ab4238cc17d4bb54afb..25b6c6097aadb20353497cf41d4b05db55488aab 100644
--- a/packages/next-server/server/utils.ts
+++ b/packages/next-server/server/utils.ts
@@ -18,3 +18,21 @@ export function isInternalUrl(url: string): boolean {
export function isBlockedPage(pathname: string): boolean {
return (BLOCKED_PAGES.indexOf(pathname) !== -1)
}
+
+export function cleanAmpPath(pathname: string): string {
+ return (pathname || '')
+ .replace(/\.amp$/, '')
+ .replace(/\index$/, '')
+}
+
+export function isAmpPath(pathname: string): boolean {
+ return (pathname || '').endsWith('.amp')
+}
+
+export function isAmpFile(pathname: string): boolean {
+ if (isAmpPath(pathname)) return true
+ pathname = pathname || ''
+ const parts = pathname.split('.')
+ parts.pop() // remove extension
+ return isAmpPath(parts.join('.'))
+}
diff --git a/packages/next/export/index.js b/packages/next/export/index.js
index 797b4ab4b29b7848c45e0a98f735534503b083c1..623eadeec8cc6661c88b81e881859e780124aa6f 100644
--- a/packages/next/export/index.js
+++ b/packages/next/export/index.js
@@ -5,6 +5,7 @@ import mkdirpModule from 'mkdirp'
import { resolve, join } from 'path'
import { existsSync, readFileSync } from 'fs'
import loadConfig from 'next-server/next-config'
+import { tryAmp } from 'next-server/dist/server/require'
import { PHASE_EXPORT, SERVER_DIRECTORY, PAGES_MANIFEST, CONFIG_FILE, BUILD_ID_FILE, CLIENT_STATIC_FILES_PATH } from 'next-server/constants'
import createProgress from 'tty-aware-progress'
import { promisify } from 'util'
@@ -52,6 +53,22 @@ export default async function (dir, options, configuration) {
defaultPathMap[page] = { page }
}
+ Object.keys(defaultPathMap).forEach(path => {
+ const isAmp = path.indexOf('.amp') > -1
+
+ if (isAmp) {
+ defaultPathMap[path].query = { amp: 1 }
+ if (!defaultPathMap[path.split('.amp')[0]]) {
+ defaultPathMap[path].query.ampOnly = true
+ }
+ } else {
+ const ampPath = tryAmp(defaultPathMap, path)
+ if (ampPath !== path) {
+ defaultPathMap[path].query = { hasAmp: true, ampPath }
+ }
+ }
+ })
+
// Initialize the output directory
const outDir = options.outdir
await recursiveDelete(join(outDir))
@@ -93,7 +110,8 @@ export default async function (dir, options, configuration) {
distDir,
dev: false,
staticMarkup: false,
- hotReloader: null
+ hotReloader: null,
+ ampEnabled: nextConfig.experimental.amp
}
const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig
diff --git a/packages/next/export/worker.js b/packages/next/export/worker.js
index 0f260ab6882df7918e2f2e8a2e46178dbd379c8e..463cb0edfa22a0c15b3dd134ffd9d47dcb9b591e 100644
--- a/packages/next/export/worker.js
+++ b/packages/next/export/worker.js
@@ -1,5 +1,6 @@
import mkdirpModule from 'mkdirp'
import { promisify } from 'util'
+import { cleanAmpPath } from 'next/dist/server/lib/utils'
import { extname, join, dirname, sep } from 'path'
import { renderToHTML } from 'next-server/dist/server/render'
import { writeFile } from 'fs'
@@ -30,6 +31,10 @@ process.on(
const work = async path => {
await sema.acquire()
const { page, query = {} } = exportPathMap[path]
+ const ampOpts = { amphtml: Boolean(query.amp), hasAmp: query.hasAmp, ampPath: query.ampPath }
+ delete query.hasAmp
+ delete query.ampPath
+
const req = { url: path }
const res = {}
envConfig.setConfig({
@@ -37,6 +42,11 @@ process.on(
publicRuntimeConfig: renderOpts.runtimeConfig
})
+ if (query.ampOnly) {
+ delete query.ampOnly
+ path = cleanAmpPath(path)
+ }
+
let htmlFilename = `${path}${sep}index.html`
const pageExt = extname(page)
const pathExt = extname(path)
@@ -53,7 +63,7 @@ process.on(
await mkdirp(baseDir)
const components = await loadComponents(distDir, buildId, page)
- const html = await renderToHTML(req, res, page, query, { ...components, ...renderOpts })
+ const html = await renderToHTML(req, res, page, query, { ...components, ...renderOpts, ...ampOpts })
await new Promise((resolve, reject) =>
writeFile(
htmlFilepath,
diff --git a/packages/next/pages/_document.js b/packages/next/pages/_document.js
index c087ae3923c4815c129817fe046634a56c3c4f85..5a5482ba899ce4e40965e1b5a7a04c96cbeb3693 100644
--- a/packages/next/pages/_document.js
+++ b/packages/next/pages/_document.js
@@ -1,6 +1,7 @@
/* eslint-disable */
import React, { Component } from 'react'
import PropTypes from 'prop-types'
+import { cleanAmpPath } from 'next-server/dist/server/utils'
import { htmlEscapeJsonString } from '../server/htmlescape'
import flush from 'styled-jsx/server'
import {
@@ -151,6 +152,7 @@ export class Head extends Component {
styles,
amphtml,
hasAmp,
+ ampPath,
assetPrefix,
__NEXT_DATA__,
} = this.context._documentProps
@@ -202,7 +204,7 @@ export class Head extends Component {
name="viewport"
content="width=device-width,minimum-scale=1,initial-scale=1"
/>
-
+
{/* https://www.ampproject.org/docs/fundamentals/optimize_amp#optimize-the-amp-runtime-loading */}
- {ampEnabled && hasAmp && }
+ {ampEnabled && hasAmp && }
{page !== '/_error' && (