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