From 8ff00f26bfd6ed04ff4e7976ba7757efe807a378 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Fri, 12 Jun 2020 17:09:20 +0200 Subject: [PATCH 1/8] Clean up AMP bundle removal --- .../build/babel/plugins/next-page-config.ts | 11 +-- .../plugins/next-drop-client-page-plugin.ts | 73 +++++++++++++++---- packages/next/next-server/lib/constants.ts | 1 + 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/packages/next/build/babel/plugins/next-page-config.ts b/packages/next/build/babel/plugins/next-page-config.ts index 3fc49aac412d7..adf724d854913 100644 --- a/packages/next/build/babel/plugins/next-page-config.ts +++ b/packages/next/build/babel/plugins/next-page-config.ts @@ -1,7 +1,6 @@ import { NodePath, PluginObj, types as BabelTypes } from '@babel/core' import { PageConfig } from 'next/types' - -const STRING_LITERAL_DROP_BUNDLE = '__NEXT_DROP_CLIENT_FILE__' +import { STRING_LITERAL_DROP_BUNDLE } from '../../../next-server/lib/constants' // replace program path with just a variable with the drop identifier function replaceBundle(path: any, t: typeof BabelTypes): void { @@ -10,12 +9,8 @@ function replaceBundle(path: any, t: typeof BabelTypes): void { [ t.variableDeclaration('const', [ t.variableDeclarator( - t.identifier('config'), - t.assignmentExpression( - '=', - t.identifier(STRING_LITERAL_DROP_BUNDLE), - t.stringLiteral(`${STRING_LITERAL_DROP_BUNDLE} ${Date.now()}`) - ) + t.identifier(STRING_LITERAL_DROP_BUNDLE), + t.stringLiteral(`${STRING_LITERAL_DROP_BUNDLE} ${Date.now()}`) ), ]), ], diff --git a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts index ba14992c80d0f..1e9cf41e56813 100644 --- a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts +++ b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts @@ -1,29 +1,70 @@ import { Compiler, Plugin } from 'webpack' -import { extname } from 'path' +import { STRING_LITERAL_DROP_BUNDLE } from '../../../next-server/lib/constants' +import Entrypoint from 'webpack/lib/Entrypoint' + +const PLUGIN_NAME = 'DropAmpFirstPagesPlugin' + +// Recursively look up the issuer till it ends up at the root +function findEntryModule(issuer: any): any { + if (issuer.issuer) { + return findEntryModule(issuer.issuer) + } + + return issuer +} + +function handler(parser: any) { + function markAsAmpFirst() { + const entryModule = findEntryModule(parser.state.module) + + entryModule.buildMeta.NEXT_ampFirst = true + } + + parser.hooks.varDeclarationConst + .for(STRING_LITERAL_DROP_BUNDLE) + .tap(PLUGIN_NAME, markAsAmpFirst) + + parser.hooks.varDeclarationLet + .for(STRING_LITERAL_DROP_BUNDLE) + .tap(PLUGIN_NAME, markAsAmpFirst) + + parser.hooks.varDeclaration + .for(STRING_LITERAL_DROP_BUNDLE) + .tap(PLUGIN_NAME, markAsAmpFirst) +} // Prevents outputting client pages when they are not needed export class DropClientPage implements Plugin { ampPages = new Set() apply(compiler: Compiler) { - compiler.hooks.emit.tap('DropClientPage', (compilation) => { - Object.keys(compilation.assets).forEach((assetKey) => { - const asset = compilation.assets[assetKey] + compiler.hooks.compilation.tap( + PLUGIN_NAME, + (compilation, { normalModuleFactory }) => { + normalModuleFactory.hooks.parser + .for('javascript/auto') + .tap(PLUGIN_NAME, handler) + + compilation.hooks.optimizeChunksBasic.tap(PLUGIN_NAME, (chunks) => { + for (let i = chunks.length - 1; i >= 0; i--) { + const chunk = chunks[i] + if (!chunk.entryModule.buildMeta.NEXT_ampFirst) { + continue + } - if (asset?._value?.includes?.('__NEXT_DROP_CLIENT_FILE__')) { - const cleanAssetKey = assetKey.replace(/\\/g, '/') - const page = '/' + cleanAssetKey.split('pages/')[1] - const pageNoExt = page.split(extname(page))[0] + for (const group of chunk.groupsIterable) { + if (!(group instanceof Entrypoint)) { + continue + } - delete compilation.assets[assetKey] + group.NEXT_ampFirst = true + } - // Detect being re-ran through a child compiler and don't re-mark the - // page as AMP - if (!pageNoExt.endsWith('.module')) { - this.ampPages.add(pageNoExt.replace(/\/index$/, '') || '/') + chunk.remove('AMP First page') + chunks.splice(i, 1) } - } - }) - }) + }) + } + ) } } diff --git a/packages/next/next-server/lib/constants.ts b/packages/next/next-server/lib/constants.ts index 159efa0c30902..51e1ddd60ddc0 100644 --- a/packages/next/next-server/lib/constants.ts +++ b/packages/next/next-server/lib/constants.ts @@ -18,6 +18,7 @@ export const CLIENT_PUBLIC_FILES_PATH = 'public' export const CLIENT_STATIC_FILES_PATH = 'static' export const CLIENT_STATIC_FILES_RUNTIME = 'runtime' export const AMP_RENDER_TARGET = '__NEXT_AMP_RENDER_TARGET__' +export const STRING_LITERAL_DROP_BUNDLE = '__NEXT_DROP_CLIENT_FILE__' export const CLIENT_STATIC_FILES_RUNTIME_PATH = `${CLIENT_STATIC_FILES_PATH}/${CLIENT_STATIC_FILES_RUNTIME}` // static/runtime/main.js export const CLIENT_STATIC_FILES_RUNTIME_MAIN = `${CLIENT_STATIC_FILES_RUNTIME_PATH}/main.js` From cc195851c897b6b501adb867067fbd2dae2a26fd Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Fri, 12 Jun 2020 17:39:44 +0200 Subject: [PATCH 2/8] Add declaration --- packages/next/types/misc.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next/types/misc.d.ts b/packages/next/types/misc.d.ts index 9b586d3d634fb..619333e923d32 100644 --- a/packages/next/types/misc.d.ts +++ b/packages/next/types/misc.d.ts @@ -11,6 +11,7 @@ declare module 'styled-jsx/server' declare module 'unfetch' declare module 'webpack/lib/GraphHelpers' declare module 'webpack/lib/DynamicEntryPlugin' +declare module 'webpack/lib/Entrypoint' declare module 'next/dist/compiled/amphtml-validator' { import m from 'amphtml-validator' From fc41b16a7f86abf3fda6e6e3bc30f20b79af8872 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Fri, 12 Jun 2020 18:01:28 +0200 Subject: [PATCH 3/8] Check entryModule --- .../next/build/webpack/plugins/next-drop-client-page-plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts index 1e9cf41e56813..86443d3336caa 100644 --- a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts +++ b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts @@ -48,7 +48,7 @@ export class DropClientPage implements Plugin { compilation.hooks.optimizeChunksBasic.tap(PLUGIN_NAME, (chunks) => { for (let i = chunks.length - 1; i >= 0; i--) { const chunk = chunks[i] - if (!chunk.entryModule.buildMeta.NEXT_ampFirst) { + if (!chunk?.entryModule?.buildMeta?.NEXT_ampFirst) { continue } From d3780ae58a5d9d56391bb847fa14bc899492d0c9 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Sat, 13 Jun 2020 12:04:14 +0200 Subject: [PATCH 4/8] Update to use seal instead based on recommendation from Tobias --- .../plugins/next-drop-client-page-plugin.ts | 33 ++++++++++--------- packages/next/next-server/server/render.tsx | 17 ++++++---- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts index 86443d3336caa..bdd735be314eb 100644 --- a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts +++ b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts @@ -1,6 +1,5 @@ import { Compiler, Plugin } from 'webpack' import { STRING_LITERAL_DROP_BUNDLE } from '../../../next-server/lib/constants' -import Entrypoint from 'webpack/lib/Entrypoint' const PLUGIN_NAME = 'DropAmpFirstPagesPlugin' @@ -17,7 +16,7 @@ function handler(parser: any) { function markAsAmpFirst() { const entryModule = findEntryModule(parser.state.module) - entryModule.buildMeta.NEXT_ampFirst = true + entryModule.buildInfo.NEXT_ampFirst = true } parser.hooks.varDeclarationConst @@ -45,23 +44,25 @@ export class DropClientPage implements Plugin { .for('javascript/auto') .tap(PLUGIN_NAME, handler) - compilation.hooks.optimizeChunksBasic.tap(PLUGIN_NAME, (chunks) => { - for (let i = chunks.length - 1; i >= 0; i--) { - const chunk = chunks[i] - if (!chunk?.entryModule?.buildMeta?.NEXT_ampFirst) { - continue + compilation.hooks.seal.tap(PLUGIN_NAME, () => { + // Remove preparedEntrypoint that has bundle drop marker + // This will ensure webpack does not create chunks/bundles for this particular entrypoint + for ( + let i = compilation._preparedEntrypoints.length - 1; + i >= 0; + i-- + ) { + const entrypoint = compilation._preparedEntrypoints[i] + if (entrypoint?.module?.buildInfo?.NEXT_ampFirst) { + compilation._preparedEntrypoints.splice(i, 1) } + } - for (const group of chunk.groupsIterable) { - if (!(group instanceof Entrypoint)) { - continue - } - - group.NEXT_ampFirst = true + for (let i = compilation.entries.length - 1; i >= 0; i--) { + const entryModule = compilation.entries[i] + if (entryModule?.buildInfo?.NEXT_ampFirst) { + compilation.entries.splice(i, 1) } - - chunk.remove('AMP First page') - chunks.splice(i, 1) } }) } diff --git a/packages/next/next-server/server/render.tsx b/packages/next/next-server/server/render.tsx index 9b62796327a36..63d3f61f1e4fd 100644 --- a/packages/next/next-server/server/render.tsx +++ b/packages/next/next-server/server/render.tsx @@ -652,12 +652,17 @@ export async function renderToHTML( // the response might be finished on the getInitialProps call if (isResSent(res) && !isSSG) return null - const files = [ - ...new Set([ - ...getPageFiles(buildManifest, '/_app'), - ...(pathname !== '/_error' ? getPageFiles(buildManifest, pathname) : []), - ]), - ] + // AMP First pages do not have client-side JavaScript files + const files = ampState.ampFirst + ? [] + : [ + ...new Set([ + ...getPageFiles(buildManifest, '/_app'), + ...(pathname !== '/_error' + ? getPageFiles(buildManifest, pathname) + : []), + ]), + ] const renderPage: RenderPage = ( options: ComponentsEnhancer = {} From 5a06d061b8cd5c84c56f2ea09dbfd43aca7541bd Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Sat, 13 Jun 2020 13:27:28 +0200 Subject: [PATCH 5/8] Show AMP in the build output --- packages/next/build/index.ts | 37 ------------------- packages/next/build/utils.ts | 19 +++++----- .../webpack/plugins/build-manifest-plugin.ts | 11 ++++++ .../plugins/next-drop-client-page-plugin.ts | 7 ++++ .../next/next-server/server/get-page-files.ts | 1 + 5 files changed, 29 insertions(+), 46 deletions(-) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index a584ac3f80c10..de9c09aabb875 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -572,30 +572,6 @@ export default async function build(dir: string, conf = null): Promise { hybridAmpPages.add(page) } - if (workerResult.isAmpOnly) { - // ensure all AMP only bundles got removed - try { - const clientBundle = path.join( - distDir, - 'static', - buildId, - 'pages', - actualPage + '.js' - ) - await promises.unlink(clientBundle) - - if (config.experimental.modern) { - await promises.unlink( - clientBundle.replace(/\.js$/, '.module.js') - ) - } - } catch (err) { - if (err.code !== 'ENOENT') { - throw err - } - } - } - if (workerResult.hasStaticProps) { ssgPages.add(page) isSsg = true @@ -719,19 +695,6 @@ export default async function build(dir: string, conf = null): Promise { ) } - if (Array.isArray(configs[0].plugins)) { - configs[0].plugins.some((plugin: any) => { - if (!plugin.ampPages) { - return false - } - - plugin.ampPages.forEach((pg: any) => { - pageInfos.get(pg)!.isAmp = true - }) - return true - }) - } - await writeBuildId(distDir, buildId) const finalPrerenderRoutes: { [route: string]: SsgRoute } = {} diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index bf53ba32f72b7..1fd16bd1a5bec 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -23,6 +23,7 @@ import { isDynamicRoute } from '../next-server/lib/router/utils/is-dynamic' import { findPageFile } from '../server/lib/find-page-file' import { GetStaticPaths } from 'next/types' import { denormalizePagePath } from '../next-server/server/normalize-page-path' +import { BuildManifest } from '../next-server/server/get-page-files' const fileGzipStats: { [k: string]: Promise } = {} const fsStatGzip = (file: string) => { @@ -42,7 +43,6 @@ export function collectPages( } export interface PageInfo { - isAmp?: boolean isHybridAmp?: boolean size: number totalSize: number @@ -70,7 +70,7 @@ export async function printTreeView( buildId: string pagesDir: string pageExtensions: string[] - buildManifest: BuildManifestShape + buildManifest: BuildManifest isModern: boolean useStatic404: boolean } @@ -141,6 +141,7 @@ export async function printTreeView( : '├' const pageInfo = pageInfos.get(item) + const ampFirst = buildManifest.ampFirstPages.includes(item) messages.push([ `${symbol} ${ @@ -153,14 +154,14 @@ export async function printTreeView( : 'λ' } ${item}`, pageInfo - ? pageInfo.isAmp + ? ampFirst ? chalk.cyan('AMP') : pageInfo.size >= 0 ? prettyBytes(pageInfo.size) : '' : '', pageInfo - ? pageInfo.isAmp + ? ampFirst ? chalk.cyan('AMP') : pageInfo.size >= 0 ? getPrettySize(pageInfo.totalSize) @@ -348,7 +349,6 @@ export function printCustomRoutes({ } } -type BuildManifestShape = { pages: { [k: string]: string[] } } type ComputeManifestShape = { commonFiles: string[] uniqueFiles: string[] @@ -357,14 +357,14 @@ type ComputeManifestShape = { sizeCommonFiles: number } -let cachedBuildManifest: BuildManifestShape | undefined +let cachedBuildManifest: BuildManifest | undefined let lastCompute: ComputeManifestShape | undefined let lastComputeModern: boolean | undefined let lastComputePageInfo: boolean | undefined async function computeFromManifest( - manifest: BuildManifestShape, + manifest: BuildManifest, distPath: string, isModern: boolean, pageInfos?: Map @@ -383,7 +383,8 @@ async function computeFromManifest( if (pageInfos) { const pageInfo = pageInfos.get(key) // don't include AMP pages since they don't rely on shared bundles - if (pageInfo?.isHybridAmp || pageInfo?.isAmp) { + // AMP First pages are not under the pageInfos key + if (pageInfo?.isHybridAmp) { return } } @@ -480,7 +481,7 @@ function sum(a: number[]): number { export async function getJsPageSizeInKb( page: string, distPath: string, - buildManifest: BuildManifestShape, + buildManifest: BuildManifest, isModern: boolean ): Promise<[number, number]> { const data = await computeFromManifest(buildManifest, distPath, isModern) diff --git a/packages/next/build/webpack/plugins/build-manifest-plugin.ts b/packages/next/build/webpack/plugins/build-manifest-plugin.ts index d20eecea210f6..536a88c39d427 100644 --- a/packages/next/build/webpack/plugins/build-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/build-manifest-plugin.ts @@ -63,6 +63,17 @@ export default class BuildManifestPlugin { devFiles: [], lowPriorityFiles: [], pages: { '/_app': [] }, + ampFirstPages: [], + } + + // @ts-ignore Additional property just for Next.js + for (const entryName of compilation.__NEXTJS._ampFirstEntryNames) { + const pagePath = getRouteFromEntrypoint(entryName) + if (!pagePath) { + continue + } + + assetMap.ampFirstPages.push(pagePath) } const mainJsChunk = chunks.find( diff --git a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts index bdd735be314eb..c89cb8f82edcb 100644 --- a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts +++ b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts @@ -44,6 +44,11 @@ export class DropClientPage implements Plugin { .for('javascript/auto') .tap(PLUGIN_NAME, handler) + // @ts-ignore Additional property just for Next.js + compilation.__NEXTJS = {} + // @ts-ignore Additional property just for Next.js + compilation.__NEXTJS._ampFirstEntryNames = [] + compilation.hooks.seal.tap(PLUGIN_NAME, () => { // Remove preparedEntrypoint that has bundle drop marker // This will ensure webpack does not create chunks/bundles for this particular entrypoint @@ -54,6 +59,8 @@ export class DropClientPage implements Plugin { ) { const entrypoint = compilation._preparedEntrypoints[i] if (entrypoint?.module?.buildInfo?.NEXT_ampFirst) { + // @ts-ignore Additional property just for Next.js + compilation.__NEXTJS._ampFirstEntryNames.push(entrypoint.name) compilation._preparedEntrypoints.splice(i, 1) } } diff --git a/packages/next/next-server/server/get-page-files.ts b/packages/next/next-server/server/get-page-files.ts index 0933b97cb6d52..0597d5a92c6ce 100644 --- a/packages/next/next-server/server/get-page-files.ts +++ b/packages/next/next-server/server/get-page-files.ts @@ -8,6 +8,7 @@ export type BuildManifest = { '/_app': string[] [page: string]: string[] } + ampFirstPages: string[] } export function getPageFiles( From e43622c88445b98a1cd52650bb23310c8035ee52 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Sat, 13 Jun 2020 18:18:41 +0200 Subject: [PATCH 6/8] Use weakmap instead of editing variables --- .../webpack/plugins/build-manifest-plugin.ts | 17 ++++++++------- .../plugins/next-drop-client-page-plugin.ts | 21 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/packages/next/build/webpack/plugins/build-manifest-plugin.ts b/packages/next/build/webpack/plugins/build-manifest-plugin.ts index 536a88c39d427..a5251c4d10228 100644 --- a/packages/next/build/webpack/plugins/build-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/build-manifest-plugin.ts @@ -10,6 +10,7 @@ import { } from '../../../next-server/lib/constants' import { BuildManifest } from '../../../next-server/server/get-page-files' import getRouteFromEntrypoint from '../../../next-server/server/get-route-from-entrypoint' +import { ampFirstEntryNamesMap } from './next-drop-client-page-plugin' // This function takes the asset map generated in BuildManifestPlugin and creates a // reduced version to send to the client. @@ -66,14 +67,16 @@ export default class BuildManifestPlugin { ampFirstPages: [], } - // @ts-ignore Additional property just for Next.js - for (const entryName of compilation.__NEXTJS._ampFirstEntryNames) { - const pagePath = getRouteFromEntrypoint(entryName) - if (!pagePath) { - continue - } + const ampFirstEntryNames = ampFirstEntryNamesMap.get(compilation) + if (ampFirstEntryNames) { + for (const entryName of ampFirstEntryNames) { + const pagePath = getRouteFromEntrypoint(entryName) + if (!pagePath) { + continue + } - assetMap.ampFirstPages.push(pagePath) + assetMap.ampFirstPages.push(pagePath) + } } const mainJsChunk = chunks.find( diff --git a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts index c89cb8f82edcb..87b7231156ef0 100644 --- a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts +++ b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts @@ -1,6 +1,11 @@ -import { Compiler, Plugin } from 'webpack' +import { Compiler, compilation as CompilationType, Plugin } from 'webpack' import { STRING_LITERAL_DROP_BUNDLE } from '../../../next-server/lib/constants' +export const ampFirstEntryNamesMap: WeakMap< + CompilationType.Compilation, + string[] +> = new WeakMap() + const PLUGIN_NAME = 'DropAmpFirstPagesPlugin' // Recursively look up the issuer till it ends up at the root @@ -44,10 +49,13 @@ export class DropClientPage implements Plugin { .for('javascript/auto') .tap(PLUGIN_NAME, handler) - // @ts-ignore Additional property just for Next.js - compilation.__NEXTJS = {} - // @ts-ignore Additional property just for Next.js - compilation.__NEXTJS._ampFirstEntryNames = [] + if (!ampFirstEntryNamesMap.has(compilation)) { + ampFirstEntryNamesMap.set(compilation, []) + } + + const ampFirstEntryNamesItem = ampFirstEntryNamesMap.get( + compilation + ) as string[] compilation.hooks.seal.tap(PLUGIN_NAME, () => { // Remove preparedEntrypoint that has bundle drop marker @@ -59,8 +67,7 @@ export class DropClientPage implements Plugin { ) { const entrypoint = compilation._preparedEntrypoints[i] if (entrypoint?.module?.buildInfo?.NEXT_ampFirst) { - // @ts-ignore Additional property just for Next.js - compilation.__NEXTJS._ampFirstEntryNames.push(entrypoint.name) + ampFirstEntryNamesItem.push(entrypoint.name) compilation._preparedEntrypoints.splice(i, 1) } } From 7c92b690690bd1ebecde795e39710acd31b2159c Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Sat, 13 Jun 2020 21:23:44 +0200 Subject: [PATCH 7/8] Look up entry module through reasons --- .../plugins/next-drop-client-page-plugin.ts | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts index 87b7231156ef0..412e962b2487a 100644 --- a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts +++ b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts @@ -9,18 +9,33 @@ export const ampFirstEntryNamesMap: WeakMap< const PLUGIN_NAME = 'DropAmpFirstPagesPlugin' // Recursively look up the issuer till it ends up at the root -function findEntryModule(issuer: any): any { - if (issuer.issuer) { - return findEntryModule(issuer.issuer) +function findEntryModule(mod: any): CompilationType.Module | null { + if (mod.reasons) { + for (const reason of mod.reasons) { + // Top level modules don't have reasons including a module + if (!reason.module) { + return mod + } + + const foundEntryModule = findEntryModule(reason.module) + if (foundEntryModule) { + return foundEntryModule + } + } } - return issuer + return null } function handler(parser: any) { function markAsAmpFirst() { const entryModule = findEntryModule(parser.state.module) + if (!entryModule) { + return + } + + // @ts-ignore buildInfo exists on Module entryModule.buildInfo.NEXT_ampFirst = true } From 17c489b5fea447887bbe04c546fd472a1beef1da Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Sun, 14 Jun 2020 13:14:14 +0200 Subject: [PATCH 8/8] Update to use snippet Tobias provided --- .../plugins/next-drop-client-page-plugin.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts index 412e962b2487a..f761c5fae73c0 100644 --- a/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts +++ b/packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts @@ -10,17 +10,11 @@ const PLUGIN_NAME = 'DropAmpFirstPagesPlugin' // Recursively look up the issuer till it ends up at the root function findEntryModule(mod: any): CompilationType.Module | null { - if (mod.reasons) { - for (const reason of mod.reasons) { - // Top level modules don't have reasons including a module - if (!reason.module) { - return mod - } - - const foundEntryModule = findEntryModule(reason.module) - if (foundEntryModule) { - return foundEntryModule - } + const queue = new Set([mod]) + for (const module of queue) { + for (const reason of module.reasons) { + if (!reason.module) return module + queue.add(reason.module) } }