Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic granular chunking #9090

Merged
merged 10 commits into from
Oct 30, 2019
4 changes: 1 addition & 3 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,11 @@ export default async function getBaseWebpackConfig(
},
},
prodGranular: {
chunks: 'initial',
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
framework: {
// Framework chunk applies to modules in dynamic chunks, unlike shared chunks
// TODO(atcastle): Analyze if other cache groups should be set to 'all' as well
chunks: 'all',
name: 'framework',
// This regex ignores nested copies of framework libraries so they're
Expand Down
31 changes: 13 additions & 18 deletions packages/next/build/webpack/plugins/build-manifest-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,29 +95,24 @@ export default class BuildManifestPlugin {
}

const filesForEntry: string[] = []
for (const chunk of entrypoint.chunks) {
// If there's no name or no files
if (!chunk.name || !chunk.files) {

// getFiles() - helper function to read the files for an entrypoint from stats object
for (const file of entrypoint.getFiles()) {
if (/\.map$/.test(file) || /\.hot-update\.js$/.test(file)) {
continue
}

for (const file of chunk.files) {
if (/\.map$/.test(file) || /\.hot-update\.js$/.test(file)) {
continue
}

// Only `.js` and `.css` files are added for now. In the future we can also handle other file types.
if (!/\.js$/.test(file) && !/\.css$/.test(file)) {
continue
}

// The page bundles are manually added to _document.js as they need extra properties
if (IS_BUNDLED_PAGE_REGEX.exec(file)) {
continue
}
// Only `.js` and `.css` files are added for now. In the future we can also handle other file types.
if (!/\.js$/.test(file) && !/\.css$/.test(file)) {
continue
}

filesForEntry.push(file.replace(/\\/g, '/'))
// The page bundles are manually added to _document.js as they need extra properties
if (IS_BUNDLED_PAGE_REGEX.exec(file)) {
continue
}

filesForEntry.push(file.replace(/\\/g, '/'))
}

assetMap.pages[`/${pagePath.replace(/\\/g, '/')}`] = [
Expand Down
11 changes: 10 additions & 1 deletion test/integration/chunking/pages/page2.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import * as _ from 'lodash'
import { useState, useEffect } from 'react'
import _ from 'lodash'
import dynamic from 'next/dynamic'
import Link from 'next/link'

const One = dynamic(() => import('../components/one'))

const Page = () => {
const [str, setStr] = useState('rad')
useEffect(() => {
setStr(_.pad(str, 7, '_'))
}, [])

console.log(_)
return (
<div>
page2
<p id='padded-str'>{str}</p>
<One />
<Link href='/page3'>Page3</Link>
</div>
)
}
Expand Down
13 changes: 13 additions & 0 deletions test/integration/chunking/pages/page3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Link from 'next/link'
import('lodash').then(_ => console.log(_.chunk(['a', 'b', 'c', 'd'], 2)))

const Page = () => {
return (
<div>
<h2>Page3</h2>
<Link href='/page2'>Page2</Link>
</div>
)
}

export default Page
31 changes: 29 additions & 2 deletions test/integration/chunking/test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
/* eslint-env jest */
/* global jasmine */
import { join } from 'path'
import { nextBuild } from 'next-test-utils'
import {
nextBuild,
findPort,
waitFor,
nextStart,
killApp
} from 'next-test-utils'
import { readdir, readFile, unlink, access } from 'fs-extra'
import cheerio from 'cheerio'
import webdriver from 'next-webdriver'

jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 1

Expand All @@ -30,7 +37,12 @@ describe('Chunking', () => {
} catch (e) {
// Error here means old chunks don't exist, so we don't need to do anything
}
await nextBuild(appDir)
const { stdout, stderr } = await nextBuild(appDir, [], {
stdout: true,
stderr: true
})
console.log(stdout)
console.error(stderr)
stats = (await readFile(join(appDir, '.next', 'stats.json'), 'utf8'))
// fixes backslashes in keyNames not being escaped on windows
.replace(/"static\\(.*?":)/g, '"static\\\\$1')
Expand Down Expand Up @@ -95,4 +107,19 @@ describe('Chunking', () => {
})
expect(misplacedReactDom).toBe(false)
})

it('should hydrate with granularChunks config', async () => {
const appPort = await findPort()
const app = await nextStart(appDir, appPort)

const browser = await webdriver(appPort, '/page2')
await waitFor(1000)
const text = await browser.elementByCss('#padded-str').text()

expect(text).toBe('__rad__')

await browser.close()

await killApp(app)
})
})