Skip to content

Commit

Permalink
Polyfill window.fetch by Default (#9168)
Browse files Browse the repository at this point in the history
* Polyfilling fetch and object-assign

* Polyfilling corejs object-assign

* Adding object-assign in polyfills.js. IE11 does not support Object.assign

* Fixing failing test

* Updating object.assign polyfill to fix aliasing

* Updating test case value to match new build stats

* Increasing the size of default build to 225kb

* Fixing defer-script test case to not include polyfill.js

* Revert README.md

* Re-design the polyfill approach based on PR feedback

* Adding comment and fixing test case

* Rename polyfills chunk

* Extract aliases into helper

* Remove extra new line

* Fix TypeScript typings

* Adding _internal_fetch alias

* Adjust build manifest plugin

* Build manifest plugin changes - adding a separate entry for polyfills

* Rename polyfills entry in build-manifest.json

* Remove old comment

* Fix TS

* Set key

* Polyfills already added

* Filtring polyfill.module.js

* Fix test

* Add __internal_fetch to alias rule

* Adjust name

* bump size

* ignore polyfills

* sigh
  • Loading branch information
janicklas-ralph authored and Timer committed Nov 2, 2019
1 parent 99755b6 commit ff2d3fd
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 12 deletions.
5 changes: 4 additions & 1 deletion packages/next/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,10 @@ export default async function build(dir: string, conf = null): Promise<void> {
console.error(error)
console.error()

if (error.indexOf('private-next-pages') > -1) {
if (
error.indexOf('private-next-pages') > -1 ||
error.indexOf('__next_polyfill__') > -1
) {
throw new Error(
'> webpack config.resolve.alias was incorrectly overriden. https://err.sh/zeit/next.js/invalid-resolve-alias'
)
Expand Down
1 change: 1 addition & 0 deletions packages/next/build/polyfills/fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default window.fetch
23 changes: 22 additions & 1 deletion packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { fileExists } from '../lib/file-exists'
import { resolveRequest } from '../lib/resolve-request'
import {
CLIENT_STATIC_FILES_RUNTIME_MAIN,
CLIENT_STATIC_FILES_RUNTIME_POLYFILLS,
CLIENT_STATIC_FILES_RUNTIME_WEBPACK,
REACT_LOADABLE_MANIFEST,
SERVER_DIRECTORY,
Expand Down Expand Up @@ -54,6 +55,20 @@ const escapePathVariables = (value: any) => {
: value
}

function getOptimizedAliases(isServer: boolean): { [pkg: string]: string } {
if (isServer) {
return {}
}

const stubWindowFetch = path.join(__dirname, 'polyfills', 'fetch.js')
return {
__next_polyfill__fetch: require.resolve('whatwg-fetch'),
unfetch$: stubWindowFetch,
'isomorphic-unfetch$': stubWindowFetch,
'whatwg-fetch$': stubWindowFetch,
}
}

export default async function getBaseWebpackConfig(
dir: string,
{
Expand Down Expand Up @@ -148,6 +163,10 @@ export default async function getBaseWebpackConfig(
dev ? `next-dev.js` : 'next.js'
)
),
[CLIENT_STATIC_FILES_RUNTIME_POLYFILLS]: path.join(
NEXT_PROJECT_ROOT_DIST_CLIENT,
'polyfills.js'
),
}
: undefined

Expand Down Expand Up @@ -196,6 +215,7 @@ export default async function getBaseWebpackConfig(
next: NEXT_PROJECT_ROOT,
[PAGES_DIR_ALIAS]: pagesDir,
[DOT_NEXT_ALIAS]: distDir,
...getOptimizedAliases(isServer),
},
mainFields: isServer ? ['main', 'module'] : ['browser', 'module', 'main'],
plugins: [PnpWebpackPlugin],
Expand Down Expand Up @@ -531,7 +551,8 @@ export default async function getBaseWebpackConfig(
if (
!dev &&
(chunk.name === CLIENT_STATIC_FILES_RUNTIME_MAIN ||
chunk.name === CLIENT_STATIC_FILES_RUNTIME_WEBPACK)
chunk.name === CLIENT_STATIC_FILES_RUNTIME_WEBPACK ||
chunk.name === CLIENT_STATIC_FILES_RUNTIME_POLYFILLS)
) {
return chunk.name.replace(/\.js$/, '-[contenthash].js')
}
Expand Down
16 changes: 13 additions & 3 deletions packages/next/build/webpack/plugins/build-manifest-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import devalue from 'devalue'
import { Compiler } from 'webpack'
import { RawSource } from 'webpack-sources'

import {
BUILD_MANIFEST,
CLIENT_STATIC_FILES_PATH,
CLIENT_STATIC_FILES_RUNTIME_MAIN,
CLIENT_STATIC_FILES_RUNTIME_POLYFILLS,
IS_BUNDLED_PAGE_REGEX,
ROUTE_NAME_REGEX,
} from '../../../next-server/lib/constants'
import { Compiler } from 'webpack'
import { RawSource } from 'webpack-sources'

interface AssetMap {
devFiles: string[]
Expand All @@ -27,7 +29,7 @@ const generateClientManifest = (
const appDependencies = new Set(assetMap.pages['/_app'])

Object.entries(assetMap.pages).forEach(([page, dependencies]) => {
if (page === '/_app') return
if (page === '/_app' || page === '/_polyfills') return
// Filter out dependencies in the _app entry, because those will have already
// been loaded by the client prior to a navigation event
const filteredDeps = dependencies.filter(
Expand Down Expand Up @@ -74,6 +76,11 @@ export default class BuildManifestPlugin {
? mainJsChunk.files.filter((file: string) => /\.js$/.test(file))
: []

const polyfillChunk = chunks.find(
c => c.name === CLIENT_STATIC_FILES_RUNTIME_POLYFILLS
)
const polyfillFiles: string[] = polyfillChunk ? polyfillChunk.files : []

for (const filePath of Object.keys(compilation.assets)) {
const path = filePath.replace(/\\/g, '/')
if (/^static\/development\/dll\//.test(path)) {
Expand Down Expand Up @@ -125,6 +132,9 @@ export default class BuildManifestPlugin {
assetMap.pages['/'] = assetMap.pages['/index']
}

// Create a separate entry for polyfills
assetMap.pages['/_polyfills'] = polyfillFiles

// Add the runtime build manifest file (generated later in this file)
// as a dependency for the app. If the flag is false, the file won't be
// downloaded by the client.
Expand Down
1 change: 1 addition & 0 deletions packages/next/client/polyfills.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '__next_polyfill__fetch'
2 changes: 2 additions & 0 deletions packages/next/next-server/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export const CLIENT_STATIC_FILES_RUNTIME_MAIN = `${CLIENT_STATIC_FILES_RUNTIME_P
export const CLIENT_STATIC_FILES_RUNTIME_AMP = `${CLIENT_STATIC_FILES_RUNTIME_PATH}/amp.js`
// static/runtime/webpack.js
export const CLIENT_STATIC_FILES_RUNTIME_WEBPACK = `${CLIENT_STATIC_FILES_RUNTIME_PATH}/webpack.js`
// static/runtime/polyfills.js
export const CLIENT_STATIC_FILES_RUNTIME_POLYFILLS = `${CLIENT_STATIC_FILES_RUNTIME_PATH}/polyfills.js`
// matches static/<buildid>/pages/<page>.js
export const IS_BUNDLED_PAGE_REGEX = /^static[/\\][^/\\]+[/\\]pages.*\.js$/
// matches static/<buildid>/pages/:page*.js
Expand Down
1 change: 1 addition & 0 deletions packages/next/next-server/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export type DocumentProps = DocumentInitialProps & {
hasCssMode: boolean
devFiles: string[]
files: string[]
polyfillFiles: string[]
dynamicImports: ManifestItem[]
assetPrefix?: string
canonicalBase: string
Expand Down
5 changes: 5 additions & 0 deletions packages/next/next-server/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ function renderDocument(
staticMarkup,
devFiles,
files,
polyfillFiles,
dynamicImports,
htmlProps,
bodyTags,
Expand All @@ -207,6 +208,7 @@ function renderDocument(
dynamicImports: ManifestItem[]
files: string[]
devFiles: string[]
polyfillFiles: string[]
htmlProps: any
bodyTags: any
headTags: any
Expand Down Expand Up @@ -242,6 +244,7 @@ function renderDocument(
staticMarkup,
devFiles,
files,
polyfillFiles,
dynamicImports,
assetPrefix,
htmlProps,
Expand Down Expand Up @@ -488,6 +491,7 @@ export async function renderToHTML(
...getPageFiles(buildManifest, '/_app'),
]),
]
const polyfillFiles = getPageFiles(buildManifest, '/_polyfills')

const renderElementToString = staticMarkup
? renderToStaticMarkup
Expand Down Expand Up @@ -642,6 +646,7 @@ export async function renderToHTML(
dynamicImports,
files,
devFiles,
polyfillFiles,
})

if (inAmpMode && html) {
Expand Down
3 changes: 2 additions & 1 deletion packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@
"webpack": "4.39.0",
"webpack-dev-middleware": "3.7.0",
"webpack-hot-middleware": "2.25.0",
"webpack-sources": "1.4.3"
"webpack-sources": "1.4.3",
"whatwg-fetch": "3.0.0"
},
"peerDependencies": {
"react": "^16.6.0",
Expand Down
20 changes: 20 additions & 0 deletions packages/next/pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,25 @@ export class NextScript extends Component<OriginProps> {
})
}

getPolyfillScripts() {
// polyfills.js has to be rendered as nomodule without async
// It also has to be the first script to load
const { assetPrefix, polyfillFiles } = this.context._documentProps
const { _devOnlyInvalidateCacheQueryString } = this.context

return polyfillFiles
.filter(polyfill => !/\.module\.js$/.test(polyfill))
.map(polyfill => (
<script
key={polyfill}
nonce={this.props.nonce}
crossOrigin={this.props.crossOrigin || process.crossOrigin}
noModule={true}
src={`${assetPrefix}/_next/${polyfill}${_devOnlyInvalidateCacheQueryString}`}
/>
))
}

static getInlineScriptSource(documentProps: DocumentProps) {
const { __NEXT_DATA__ } = documentProps
try {
Expand Down Expand Up @@ -784,6 +803,7 @@ export class NextScript extends Component<OriginProps> {
}}
/>
) : null}
{this.getPolyfillScripts()}
{page !== '/_error' && pageScript}
{appScript}
{staticMarkup ? null : this.getDynamicChunks()}
Expand Down
2 changes: 1 addition & 1 deletion test/integration/build-stats-output/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ const appDir = join(__dirname, '../react-site')
describe('Build Stats Output', () => {
it('Shows correct package count in output', async () => {
const { stdout } = await nextBuild(appDir, undefined, { stdout: true })
expect(stdout).toMatch(/\/something .*?4/)
expect(stdout).toMatch(/\/something .*?2/)
})
})
5 changes: 3 additions & 2 deletions test/integration/defer-scripts/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ describe('Defer Scripts', () => {
let missing = false

for (const script of $('script').toArray()) {
const { defer, type } = script.attribs
const { defer, type, src } = script.attribs
// application/json doesn't need defer
if (type === 'application/json') {
// polyfills cannot be deferred or async'd
if (type === 'application/json' || src.includes('polyfills')) {
continue
}

Expand Down
5 changes: 4 additions & 1 deletion test/integration/production/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,10 @@ describe('Production Usage', () => {

for (const script of $('script').toArray()) {
// application/json doesn't need defer
if (script.attribs.type === 'application/json') {
if (
script.attribs.type === 'application/json' ||
script.attribs.src.includes('polyfills')
) {
continue
}

Expand Down
2 changes: 1 addition & 1 deletion test/integration/size-limit/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ describe('Production response size', () => {
)

// These numbers are without gzip compression!
expect(responseSizeKilobytes).toBeLessThanOrEqual(222) // Kilobytes
expect(responseSizeKilobytes).toBeLessThanOrEqual(230) // Kilobytes
})

it('should not increase the overall response size of modern build', async () => {
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15264,7 +15264,7 @@ [email protected]:
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==

whatwg-fetch@>=0.10.0:
whatwg-fetch@3.0.0, whatwg-fetch@>=0.10.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==
Expand Down

0 comments on commit ff2d3fd

Please sign in to comment.