Files
next.js/test/production/app-dir/browser-chunks/browser-chunks.test.ts
Arian Tron 61f56f997c
Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
first commit
2026-03-10 19:37:31 +03:30

119 lines
4.0 KiB
TypeScript

import { nextTestSetup } from 'e2e-utils'
import { join } from 'path'
import { readdir, readFile } from 'fs/promises'
async function readFilesRecursive(
dir: string,
predicate: (filename: string) => boolean
): Promise<string[]> {
const entries = await readdir(dir, { withFileTypes: true })
const results: string[] = []
for (const entry of entries) {
const fullPath = join(dir, entry.name)
if (entry.isDirectory()) {
results.push(...(await readFilesRecursive(fullPath, predicate)))
} else if (predicate(entry.name)) {
results.push(await readFile(fullPath, 'utf8'))
}
}
return results
}
describe('browser-chunks', () => {
const { next } = nextTestSetup({
files: __dirname,
skipDeployment: true,
})
let sources: string[] = []
let jsContents: string[] = []
beforeAll(async () => {
const chunksDir = join(next.testDir, '.next/static/chunks')
const sourcemaps = await readFilesRecursive(chunksDir, (filename) =>
filename.endsWith('.js.map')
)
sources = sourcemaps.flatMap((sourcemap) => JSON.parse(sourcemap).sources)
jsContents = await readFilesRecursive(chunksDir, (filename) =>
filename.endsWith('.js')
)
})
it('must not bundle any server modules into browser chunks', () => {
const serverSources = sources.filter(
(source) =>
/webpack:\/\/_N_E\/(\.\.\/)*src\/server\//.test(source) ||
source.includes('next/dist/esm/server') ||
source.includes('next/dist/server') ||
source.includes('next-devtools/server')
)
if (serverSources.length > 0) {
console.error(
`Found the following server modules:\n ${serverSources.join('\n ')}\nIf any of these modules are allowed to be included in browser chunks, move them to src/shared or src/client.`
)
throw new Error('Did not expect any server modules in browser chunks.')
}
})
it('must not bundle any dev overlay into browser chunks', () => {
const devOverlaySources = sources.filter((source) => {
return source.includes('next-devtools')
})
if (devOverlaySources.length > 0) {
const message = `Found the following dev overlay modules:\n ${devOverlaySources.join('\n')}`
console.error(
`${message}\nIf any of these modules are allowed to be included in production chunks, check the import and render conditions.`
)
throw new Error(
'Did not expect any dev overlay modules in browser chunks.\n' + message
)
}
})
it('must not include heavy dependencies into browser chunks', () => {
const heavyDependencies = sources.filter((source) => {
return source.includes('next/dist/compiled/safe-stable-stringify')
})
if (heavyDependencies.length > 0) {
const message = `Found the following heavy dependencies:\n ${heavyDependencies.join('\n ')}`
throw new Error(
'Did not expect any heavy dependencies in browser chunks.\n' + message
)
}
})
it('must not pull server internals from next/cache into browser chunks', () => {
// When a Client Component imports from next/cache, the bundler should
// DCE the server require() branch (via process.env.NEXT_RUNTIME === '')
// and only include lightweight client stubs. Pre-compiled dist/ modules
// don't appear in sourcemaps, so we check the actual JS content.
const serverOnlyPatterns = [
// IncrementalCache is a class from next/dist/server used by unstable_cache
'IncrementalCache',
]
for (const pattern of serverOnlyPatterns) {
const chunksWithPattern = jsContents.filter((content) =>
content.includes(pattern)
)
if (chunksWithPattern.length > 0) {
throw new Error(
`Found server-only pattern "${pattern}" in ${chunksWithPattern.length} browser chunk(s). ` +
`This likely means next/cache is pulling server internals into the client bundle. ` +
`Ensure the server require() calls in packages/next/cache.js are behind a DCE-able branch.`
)
}
}
})
})