提交 24034ec9 编写于 作者: J JJ Kasper 提交者: Joe Haddad

Add amp.canonicalBase option to set absolute URL (#7262)

* Add canonicalBase config to allow setting
absolute path for canonical link

* Make sure canonicalBase is set for
export and serverless

* Move canonicalBase to amp.canonicalBase

* Update tests with canonicalBase config

* Update tests

* run lint-fix

* Fix canonicalBase config parsing

* Fix canonicalBase during export

* Update amphtml tests
上级 c7276bcb
...@@ -134,6 +134,7 @@ export type DocumentProps = DocumentInitialProps & { ...@@ -134,6 +134,7 @@ export type DocumentProps = DocumentInitialProps & {
files: string[] files: string[]
dynamicImports: ManifestItem[] dynamicImports: ManifestItem[]
assetPrefix?: string, assetPrefix?: string,
canonicalBase: string,
} }
/** /**
......
...@@ -21,6 +21,9 @@ const defaultConfig: {[key: string]: any} = { ...@@ -21,6 +21,9 @@ const defaultConfig: {[key: string]: any} = {
maxInactiveAge: 60 * 1000, maxInactiveAge: 60 * 1000,
pagesBufferLength: 2, pagesBufferLength: 2,
}, },
amp: {
canonicalBase: '',
},
experimental: { experimental: {
cpus: Math.max( cpus: Math.max(
1, 1,
...@@ -80,6 +83,14 @@ export default function loadConfig(phase: string, dir: string, customConfig: any ...@@ -80,6 +83,14 @@ export default function loadConfig(phase: string, dir: string, customConfig: any
if (userConfig.target && !targets.includes(userConfig.target)) { if (userConfig.target && !targets.includes(userConfig.target)) {
throw new Error(`Specified target is invalid. Provided: "${userConfig.target}" should be one of ${targets.join(', ')}`) throw new Error(`Specified target is invalid. Provided: "${userConfig.target}" should be one of ${targets.join(', ')}`)
} }
if (userConfig.amp && userConfig.amp.canonicalBase) {
const { canonicalBase } = userConfig.amp || {} as any
userConfig.amp = userConfig.amp || {}
userConfig.amp.canonicalBase = (canonicalBase.endsWith('/')
? canonicalBase.slice(0, -1) : canonicalBase) || ''
}
return assignDefaults({ configOrigin: CONFIG_FILE, ...userConfig }) return assignDefaults({ configOrigin: CONFIG_FILE, ...userConfig })
} }
......
...@@ -55,7 +55,8 @@ export default class Server { ...@@ -55,7 +55,8 @@ export default class Server {
buildId: string buildId: string
generateEtags: boolean generateEtags: boolean
runtimeConfig?: { [key: string]: any } runtimeConfig?: { [key: string]: any }
assetPrefix?: string assetPrefix?: string,
canonicalBase: string,
autoExport: boolean autoExport: boolean
dev?: boolean, dev?: boolean,
} }
...@@ -87,9 +88,11 @@ export default class Server { ...@@ -87,9 +88,11 @@ export default class Server {
} = this.nextConfig } = this.nextConfig
this.buildId = this.readBuildId() this.buildId = this.readBuildId()
this.renderOpts = { this.renderOpts = {
ampBindInitData: this.nextConfig.experimental.ampBindInitData, ampBindInitData: this.nextConfig.experimental.ampBindInitData,
poweredByHeader: this.nextConfig.poweredByHeader, poweredByHeader: this.nextConfig.poweredByHeader,
canonicalBase: this.nextConfig.amp.canonicalBase,
autoExport: this.nextConfig.experimental.autoExport, autoExport: this.nextConfig.experimental.autoExport,
staticMarkup, staticMarkup,
buildId: this.buildId, buildId: this.buildId,
......
...@@ -113,6 +113,7 @@ type RenderOpts = { ...@@ -113,6 +113,7 @@ type RenderOpts = {
ampBindInitData: boolean ampBindInitData: boolean
staticMarkup: boolean staticMarkup: boolean
buildId: string buildId: string
canonicalBase: string
dynamicBuildId?: boolean dynamicBuildId?: boolean
runtimeConfig?: { [key: string]: any } runtimeConfig?: { [key: string]: any }
dangerousAsPath: string dangerousAsPath: string
...@@ -144,6 +145,7 @@ function renderDocument( ...@@ -144,6 +145,7 @@ function renderDocument(
pathname, pathname,
query, query,
buildId, buildId,
canonicalBase,
dynamicBuildId = false, dynamicBuildId = false,
assetPrefix, assetPrefix,
runtimeConfig, runtimeConfig,
...@@ -196,6 +198,7 @@ function renderDocument( ...@@ -196,6 +198,7 @@ function renderDocument(
err: err ? serializeError(dev, err) : undefined, // Error if one happened, otherwise don't sent in the resulting HTML err: err ? serializeError(dev, err) : undefined, // Error if one happened, otherwise don't sent in the resulting HTML
}} }}
dangerousAsPath={dangerousAsPath} dangerousAsPath={dangerousAsPath}
canonicalBase={canonicalBase}
ampPath={ampPath} ampPath={ampPath}
amphtml={amphtml} amphtml={amphtml}
hasAmp={hasAmp} hasAmp={hasAmp}
......
...@@ -44,7 +44,8 @@ export function createEntrypoints(pages: PagesMapping, target: 'server'|'serverl ...@@ -44,7 +44,8 @@ export function createEntrypoints(pages: PagesMapping, target: 'server'|'serverl
assetPrefix: config.assetPrefix, assetPrefix: config.assetPrefix,
generateEtags: config.generateEtags, generateEtags: config.generateEtags,
ampBindInitData: config.experimental.ampBindInitData, ampBindInitData: config.experimental.ampBindInitData,
dynamicBuildId canonicalBase: config.canonicalBase,
dynamicBuildId,
} }
Object.keys(pages).forEach((page) => { Object.keys(pages).forEach((page) => {
......
...@@ -13,7 +13,8 @@ export type ServerlessLoaderQuery = { ...@@ -13,7 +13,8 @@ export type ServerlessLoaderQuery = {
assetPrefix: string, assetPrefix: string,
ampBindInitData: boolean | string, ampBindInitData: boolean | string,
generateEtags: string generateEtags: string
dynamicBuildId?: string | boolean dynamicBuildId?: string | boolean,
canonicalBase: string
} }
const nextServerlessLoader: loader.Loader = function () { const nextServerlessLoader: loader.Loader = function () {
...@@ -21,6 +22,7 @@ const nextServerlessLoader: loader.Loader = function () { ...@@ -21,6 +22,7 @@ const nextServerlessLoader: loader.Loader = function () {
distDir, distDir,
absolutePagePath, absolutePagePath,
page, page,
canonicalBase,
assetPrefix, assetPrefix,
ampBindInitData, ampBindInitData,
absoluteAppPath, absoluteAppPath,
...@@ -54,6 +56,7 @@ const nextServerlessLoader: loader.Loader = function () { ...@@ -54,6 +56,7 @@ const nextServerlessLoader: loader.Loader = function () {
Document, Document,
buildManifest, buildManifest,
reactLoadableManifest, reactLoadableManifest,
canonicalBase: "${canonicalBase}",
buildId: "__NEXT_REPLACE__BUILD_ID__", buildId: "__NEXT_REPLACE__BUILD_ID__",
dynamicBuildId: ${dynamicBuildId === true || dynamicBuildId === 'true'}, dynamicBuildId: ${dynamicBuildId === true || dynamicBuildId === 'true'},
assetPrefix: "${assetPrefix}", assetPrefix: "${assetPrefix}",
......
...@@ -91,7 +91,8 @@ export default async function (dir, options, configuration) { ...@@ -91,7 +91,8 @@ export default async function (dir, options, configuration) {
distDir, distDir,
dev: false, dev: false,
staticMarkup: false, staticMarkup: false,
hotReloader: null hotReloader: null,
canonicalBase: (nextConfig.amp && nextConfig.amp.canonicalBase) || ''
} }
const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig
......
...@@ -191,6 +191,7 @@ export class Head extends Component<OriginProps> { ...@@ -191,6 +191,7 @@ export class Head extends Component<OriginProps> {
hasAmp, hasAmp,
ampPath, ampPath,
assetPrefix, assetPrefix,
canonicalBase,
__NEXT_DATA__, __NEXT_DATA__,
dangerousAsPath, dangerousAsPath,
} = this.context._documentProps } = this.context._documentProps
...@@ -280,8 +281,8 @@ export class Head extends Component<OriginProps> { ...@@ -280,8 +281,8 @@ export class Head extends Component<OriginProps> {
name="viewport" name="viewport"
content="width=device-width,minimum-scale=1,initial-scale=1" content="width=device-width,minimum-scale=1,initial-scale=1"
/> />
<link rel="canonical" href={cleanAmpPath(dangerousAsPath)} /> <link rel="canonical" href={canonicalBase + cleanAmpPath(dangerousAsPath)} />
{isDirtyAmp && <link rel="amphtml" href={getAmpPath(ampPath, dangerousAsPath)} />} {isDirtyAmp && <link rel="amphtml" href={canonicalBase + getAmpPath(ampPath, dangerousAsPath)} />}
{/* https://www.ampproject.org/docs/fundamentals/optimize_amp#optimize-the-amp-runtime-loading */} {/* https://www.ampproject.org/docs/fundamentals/optimize_amp#optimize-the-amp-runtime-loading */}
<link <link
rel="preload" rel="preload"
...@@ -320,7 +321,7 @@ export class Head extends Component<OriginProps> { ...@@ -320,7 +321,7 @@ export class Head extends Component<OriginProps> {
)} )}
{!amphtml && ( {!amphtml && (
<> <>
{hasAmp && <link rel="amphtml" href={getAmpPath(ampPath, dangerousAsPath)} />} {hasAmp && <link rel="amphtml" href={canonicalBase + getAmpPath(ampPath, dangerousAsPath)} />}
{page !== '/_error' && ( {page !== '/_error' && (
<link <link
rel="preload" rel="preload"
......
...@@ -3,6 +3,9 @@ module.exports = { ...@@ -3,6 +3,9 @@ module.exports = {
// Make sure entries are not getting disposed. // Make sure entries are not getting disposed.
maxInactiveAge: 1000 * 60 * 60 maxInactiveAge: 1000 * 60 * 60
}, },
amp: {
canonicalBase: 'http://localhost:1234'
},
experimental: { experimental: {
autoExport: true autoExport: true
} }
......
...@@ -68,6 +68,9 @@ describe('AMP Usage', () => { ...@@ -68,6 +68,9 @@ describe('AMP Usage', () => {
expect( expect(
() => accessSync(join(appDir, '.next/server/static', buildId, 'pages', pg + '.html')) () => accessSync(join(appDir, '.next/server/static', buildId, 'pages', pg + '.html'))
).not.toThrow() ).not.toThrow()
expect(
() => accessSync(join(appDir, '.next/server/static', buildId, 'pages', pg + '.js'))
).toThrow()
} }
}) })
...@@ -163,7 +166,7 @@ describe('AMP Usage', () => { ...@@ -163,7 +166,7 @@ describe('AMP Usage', () => {
$('link[rel=amphtml]') $('link[rel=amphtml]')
.first() .first()
.attr('href') .attr('href')
).toBe('/use-amp-hook.amp') ).toBe('http://localhost:1234/use-amp-hook.amp')
}) })
it('should render link rel amphtml with existing query', async () => { it('should render link rel amphtml with existing query', async () => {
...@@ -179,7 +182,7 @@ describe('AMP Usage', () => { ...@@ -179,7 +182,7 @@ describe('AMP Usage', () => {
$('link[rel=canonical]') $('link[rel=canonical]')
.first() .first()
.attr('href') .attr('href')
).toBe('/use-amp-hook') ).toBe('http://localhost:1234/use-amp-hook')
}) })
it('should render a canonical regardless of amp-only status (implicit)', async () => { it('should render a canonical regardless of amp-only status (implicit)', async () => {
...@@ -189,7 +192,7 @@ describe('AMP Usage', () => { ...@@ -189,7 +192,7 @@ describe('AMP Usage', () => {
$('link[rel=canonical]') $('link[rel=canonical]')
.first() .first()
.attr('href') .attr('href')
).toBe('/only-amp') ).toBe('http://localhost:1234/only-amp')
}) })
it('should render a canonical regardless of amp-only status (explicit)', async () => { it('should render a canonical regardless of amp-only status (explicit)', async () => {
...@@ -200,7 +203,7 @@ describe('AMP Usage', () => { ...@@ -200,7 +203,7 @@ describe('AMP Usage', () => {
$('link[rel=canonical]') $('link[rel=canonical]')
.first() .first()
.attr('href') .attr('href')
).toBe('/only-amp') ).toBe('http://localhost:1234/only-amp')
}) })
it('should not render amphtml link tag with no AMP page', async () => { it('should not render amphtml link tag with no AMP page', async () => {
...@@ -220,7 +223,7 @@ describe('AMP Usage', () => { ...@@ -220,7 +223,7 @@ describe('AMP Usage', () => {
$('link[rel=amphtml]') $('link[rel=amphtml]')
.first() .first()
.attr('href') .attr('href')
).toBe('/only-amp.amp') ).toBe('http://localhost:1234/only-amp.amp')
}) })
it('should remove conflicting amp tags', async () => { it('should remove conflicting amp tags', async () => {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册