Skip to content

Commit

Permalink
Add custom amp optimizer and skip validation mode
Browse files Browse the repository at this point in the history
  • Loading branch information
yosuke-furukawa committed Feb 26, 2020
1 parent fb72982 commit 75f33e4
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 35 deletions.
2 changes: 2 additions & 0 deletions packages/next/export/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ export default async function(
canonicalBase: nextConfig.amp?.canonicalBase || '',
isModern: nextConfig.experimental.modern,
ampValidatorPath: nextConfig.experimental.amp?.validator || undefined,
ampSkipValidation: nextConfig.experimental.amp?.skipValidation || false,
ampOptimizerConfig: nextConfig.experimental.amp?.optimizer || undefined,
}

const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig
Expand Down
62 changes: 32 additions & 30 deletions packages/next/export/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,38 +214,40 @@ export default async function({
}
}

if (curRenderOpts.inAmpMode) {
await validateAmp(html, path, curRenderOpts.ampValidatorPath)
} else if (curRenderOpts.hybridAmp) {
// we need to render the AMP version
let ampHtmlFilename = `${ampPath}${sep}index.html`
if (!subFolders) {
ampHtmlFilename = `${ampPath}.html`
}
const ampBaseDir = join(outDir, dirname(ampHtmlFilename))
const ampHtmlFilepath = join(outDir, ampHtmlFilename)

try {
await accessP(ampHtmlFilepath)
} catch (_) {
// make sure it doesn't exist from manual mapping
let ampHtml
if (serverless) {
req.url += (req.url.includes('?') ? '&' : '?') + 'amp=1'
ampHtml = (await renderMethod(req, res, true)).html
} else {
ampHtml = await renderMethod(
req,
res,
page,
{ ...query, amp: 1 },
curRenderOpts
)
if (!curRenderOpts.ampSkipValidation) {
if (curRenderOpts.inAmpMode) {
await validateAmp(html, path, curRenderOpts.ampValidatorPath)
} else if (curRenderOpts.hybridAmp) {
// we need to render the AMP version
let ampHtmlFilename = `${ampPath}${sep}index.html`
if (!subFolders) {
ampHtmlFilename = `${ampPath}.html`
}
const ampBaseDir = join(outDir, dirname(ampHtmlFilename))
const ampHtmlFilepath = join(outDir, ampHtmlFilename)

await validateAmp(ampHtml, page + '?amp=1')
await mkdirp(ampBaseDir)
await writeFileP(ampHtmlFilepath, ampHtml, 'utf8')
try {
await accessP(ampHtmlFilepath)
} catch (_) {
// make sure it doesn't exist from manual mapping
let ampHtml
if (serverless) {
req.url += (req.url.includes('?') ? '&' : '?') + 'amp=1'
ampHtml = (await renderMethod(req, res, true)).html
} else {
ampHtml = await renderMethod(
req,
res,
page,
{ ...query, amp: 1 },
curRenderOpts
)
}

await validateAmp(ampHtml, page + '?amp=1')
await mkdirp(ampBaseDir)
await writeFileP(ampHtmlFilepath, ampHtml, 'utf8')
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/next/next-server/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export default class Server {
documentMiddlewareEnabled: boolean
hasCssMode: boolean
dev?: boolean
ampOptimizerConfig?: { [key: string]: any }
}
private compression?: Middleware
private onErrorMiddleware?: ({ err }: { err: Error }) => Promise<void>
Expand Down Expand Up @@ -161,6 +162,7 @@ export default class Server {
staticMarkup,
buildId: this.buildId,
generateEtags,
ampOptimizerConfig: this.nextConfig.experimental.amp?.optimizer,
}

// Only the `publicRuntimeConfig` key is exposed to the client side
Expand Down
9 changes: 6 additions & 3 deletions packages/next/next-server/server/optimize-amp.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
export default async function optimize(html: string): Promise<string> {
export default async function optimize(
html: string,
config: any
): Promise<string> {
let AmpOptimizer
try {
AmpOptimizer = require('@ampproject/toolbox-optimizer')
} catch (_) {
return html
}
const optimizer = AmpOptimizer.create()
return optimizer.transformHtml(html)
const optimizer = AmpOptimizer.create(config)
return optimizer.transformHtml(html, config)
}
6 changes: 4 additions & 2 deletions packages/next/next-server/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ type RenderOpts = LoadComponentsReturnType & {
hybridAmp?: boolean
ErrorDebug?: React.ComponentType<{ error: Error }>
ampValidator?: (html: string, pathname: string) => Promise<void>
ampSkipValidation: boolean
ampOptimizerConfig?: { [key: string]: any }
documentMiddlewareEnabled?: boolean
isDataReq?: boolean
params?: ParsedUrlQuery
Expand Down Expand Up @@ -673,9 +675,9 @@ export async function renderToHTML(
html.substring(0, ampRenderIndex) +
`<!-- __NEXT_DATA__ -->${docProps.html}` +
html.substring(ampRenderIndex + AMP_RENDER_TARGET.length)
html = await optimizeAmp(html)
html = await optimizeAmp(html, renderOpts.ampOptimizerConfig)

if (renderOpts.ampValidator) {
if (!renderOpts.ampSkipValidation && renderOpts.ampValidator) {
await renderOpts.ampValidator(html, pathname)
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/next/server/next-dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export default class DevServer extends Server {
this.devReady = new Promise(resolve => {
this.setDevReady = resolve
})
;(this.renderOpts as any).ampSkipValidation =
this.nextConfig.experimental?.amp?.skipValidation ?? false
;(this.renderOpts as any).ampValidator = (
html: string,
pathname: string
Expand Down
12 changes: 12 additions & 0 deletions test/integration/amphtml-custom-optimizer/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
experimental: {
amp: {
optimizer: {
ampRuntimeVersion: '001515617716922',
ampUrlPrefix: '/amp',
verbose: true,
},
skipValidation: true,
},
},
}
20 changes: 20 additions & 0 deletions test/integration/amphtml-custom-optimizer/pages/dynamic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const config = {
amp: true,
}

const Dynamic = props => (
<amp-img
width="500"
height="500"
layout="responsive"
src={props.src}
></amp-img>
)

Dynamic.getInitialProps = () => {
return {
src: 'https://amp.dev/static/samples/img/story_dog2_portrait.jpg',
}
}

export default Dynamic
12 changes: 12 additions & 0 deletions test/integration/amphtml-custom-optimizer/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const config = {
amp: true,
}

export default () => (
<amp-twitter
width="500"
height="500"
layout="responsive"
data-tweetid="1159145442896166912"
></amp-twitter>
)
52 changes: 52 additions & 0 deletions test/integration/amphtml-custom-optimizer/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-env jest */
/* global jasmine */
import { join } from 'path'
import {
nextBuild,
findPort,
nextStart,
killApp,
renderViaHTTP,
} from 'next-test-utils'

jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 1

let app
let appPort
const appDir = join(__dirname, '../')

describe('AMP Custom Optimizer', () => {
it('should build and start for static page', async () => {
const { code } = await nextBuild(appDir, undefined)
expect(code).toBe(0)

appPort = await findPort()
app = await nextStart(appDir, appPort)

const html = await renderViaHTTP(appPort, '/')
await killApp(app)

expect(html).toContain(
'amp-twitter width="500" height="500" layout="responsive" data-tweetid="1159145442896166912"'
)
expect(html).toContain('i-amphtml-version="001515617716922"')
expect(html).toContain('script async src="/amp/rtv/001515617716922/v0.js"')
})

it('should build and start for dynamic page', async () => {
const { code } = await nextBuild(appDir, undefined)
expect(code).toBe(0)

appPort = await findPort()
app = await nextStart(appDir, appPort)

const html = await renderViaHTTP(appPort, '/dynamic')
await killApp(app)

expect(html).toContain(
'amp-img width="500" height="500" layout="responsive" src="https://amp.dev/static/samples/img/story_dog2_portrait.jpg"'
)
expect(html).toContain('i-amphtml-version="001515617716922"')
expect(html).toContain('script async src="/amp/rtv/001515617716922/v0.js"')
})
})

0 comments on commit 75f33e4

Please sign in to comment.