From 49a59b1ad2fde90ddcba01d2f7eb0c779ab5d9ff Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Mon, 14 Sep 2020 15:25:30 -0400 Subject: [PATCH] Polyfill missing std lib fns for module browsers (#17083) --- packages/next-polyfill-module/package.json | 18 ++++ packages/next-polyfill-module/src/index.js | 94 +++++++++++++++++++ packages/next/client/index.tsx | 9 +- packages/next/package.json | 2 +- packages/next/taskfile.js | 14 +-- .../build-output/test/index.test.js | 8 +- yarn.lock | 5 - 7 files changed, 121 insertions(+), 29 deletions(-) create mode 100644 packages/next-polyfill-module/package.json create mode 100644 packages/next-polyfill-module/src/index.js diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json new file mode 100644 index 0000000000000..891086ee11d0d --- /dev/null +++ b/packages/next-polyfill-module/package.json @@ -0,0 +1,18 @@ +{ + "name": "@next/polyfill-module", + "version": "9.5.4-canary.16", + "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", + "main": "dist/polyfill-module.js", + "license": "MIT", + "repository": { + "url": "vercel/next.js", + "directory": "packages/next-polyfill-module" + }, + "scripts": { + "prepublish": "microbundle src/index.js -f iife --no-sourcemap --external none", + "build": "microbundle watch src/index.js -f iife --no-sourcemap --external none" + }, + "devDependencies": { + "microbundle": "0.11.0" + } +} diff --git a/packages/next-polyfill-module/src/index.js b/packages/next-polyfill-module/src/index.js new file mode 100644 index 0000000000000..42a9f1391ea9f --- /dev/null +++ b/packages/next-polyfill-module/src/index.js @@ -0,0 +1,94 @@ +/* eslint-disable no-extend-native */ + +// Contains polyfills for methods missing after browser version(s): +// Edge 16, Firefox 60, Chrome 61, Safari 10.1 + +/** + * Available in: + * Edge: never + * Firefox: 61 + * Chrome: 66 + * Safari: 12 + * + * https://caniuse.com/mdn-javascript_builtins_string_trimstart + * https://caniuse.com/mdn-javascript_builtins_string_trimend + */ +if (!('trimStart' in String.prototype)) { + String.prototype.trimStart = String.prototype.trimLeft +} +if (!('trimEnd' in String.prototype)) { + String.prototype.trimEnd = String.prototype.trimRight +} + +/** + * Available in: + * Edge: never + * Firefox: 63 + * Chrome: 70 + * Safari: 12.1 + * + * https://caniuse.com/mdn-javascript_builtins_symbol_description + */ +if (!('description' in Symbol.prototype)) { + Object.defineProperty(Symbol.prototype, 'description', { + get: function get() { + return /\((.+)\)/.exec(this)[1] + }, + }) +} + +/** + * Available in: + * Edge: never + * Firefox: 62 + * Chrome: 69 + * Safari: 12 + * + * https://caniuse.com/array-flat + */ +// Copied from https://gist.github.com/developit/50364079cf0390a73e745e513fa912d9 +// Licensed Apache-2.0 +if (!Array.prototype.flat) { + Array.prototype.flat = function flat(d, c) { + return ( + (c = this.concat.apply([], this)), + d > 1 && c.some(Array.isArray) ? c.flat(d - 1) : c + ) + } + Array.prototype.flatMap = function (c, a) { + return this.map(c, a).flat() + } +} + +/** + * Available in: + * Edge: 18 + * Firefox: 58 + * Chrome: 63 + * Safari: 11.1 + * + * https://caniuse.com/promise-finally + */ +// Modified from https://gist.github.com/developit/e96097d9b657f2a2f3e588ffde433437 +// Licensed Apache-2.0 +if (!Promise.prototype.finally) { + Promise.prototype.finally = function (callback) { + if (typeof callback !== 'function') { + return this.then(callback, callback) + } + + var P = this.constructor || Promise + return this.then( + function (value) { + return P.resolve(callback()).then(function () { + return value + }) + }, + function (err) { + return P.resolve(callback()).then(function () { + throw err + }) + } + ) + } +} diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index fde93fd9bfdc9..7739cb72afffc 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -1,21 +1,22 @@ /* global location */ +import '@next/polyfill-module' import React from 'react' import ReactDOM from 'react-dom' import { HeadManagerContext } from '../next-server/lib/head-manager-context' import mitt from '../next-server/lib/mitt' import { RouterContext } from '../next-server/lib/router-context' -import { delBasePath, hasBasePath } from '../next-server/lib/router/router' import type Router from '../next-server/lib/router/router' import type { AppComponent, AppProps, PrivateRouteInfo, } from '../next-server/lib/router/router' +import { delBasePath, hasBasePath } from '../next-server/lib/router/router' import { isDynamicRoute } from '../next-server/lib/router/utils/is-dynamic' import * as querystring from '../next-server/lib/router/utils/querystring' import * as envConfig from '../next-server/lib/runtime-config' -import { getURL, loadGetInitialProps, ST } from '../next-server/lib/utils' import type { NEXT_DATA } from '../next-server/lib/utils' +import { getURL, loadGetInitialProps, ST } from '../next-server/lib/utils' import initHeadManager from './head-manager' import PageLoader, { looseToArray, StyleSheetTuple } from './page-loader' import measureWebVitals from './performance-relayer' @@ -41,10 +42,6 @@ declare global { type RenderRouteInfo = PrivateRouteInfo & { App: AppComponent } type RenderErrorProps = Omit -if (!('finally' in Promise.prototype)) { - ;(Promise.prototype as PromiseConstructor['prototype']).finally = require('next/dist/build/polyfills/finally-polyfill.min') -} - const data: typeof window['__NEXT_DATA__'] = JSON.parse( document.getElementById('__NEXT_DATA__')!.textContent! ) diff --git a/packages/next/package.json b/packages/next/package.json index a30ee757dd457..c071cf6bd8802 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -76,6 +76,7 @@ "@babel/preset-typescript": "7.10.4", "@babel/runtime": "7.11.2", "@babel/types": "7.11.5", + "@next/polyfill-module": "9.5.4-canary.16", "@next/react-dev-overlay": "9.5.4-canary.16", "@next/react-refresh-utils": "9.5.4-canary.16", "ast-types": "0.13.2", @@ -179,7 +180,6 @@ "escape-string-regexp": "2.0.0", "etag": "1.8.1", "file-loader": "6.0.0", - "finally-polyfill": "0.1.0", "find-up": "4.1.0", "fresh": "0.5.2", "gzip-size": "5.1.1", diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 755001996804c..f0b1b9b415759 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -11,14 +11,6 @@ export async function next__polyfill_nomodule(task, opts) { .target('dist/build/polyfills') } -export async function finally_polyfill(task, opts) { - await task - .source( - opts.src || relative(__dirname, require.resolve('finally-polyfill')) - ) - .target('dist/build/polyfills') -} - export async function unfetch(task, opts) { await task .source(opts.src || relative(__dirname, require.resolve('unfetch'))) @@ -26,11 +18,7 @@ export async function unfetch(task, opts) { } export async function browser_polyfills(task) { - await task.parallel([ - 'next__polyfill_nomodule', - 'finally_polyfill', - 'unfetch', - ]) + await task.parallel(['next__polyfill_nomodule', 'unfetch']) } const externals = { diff --git a/test/integration/build-output/test/index.test.js b/test/integration/build-output/test/index.test.js index e027f80ecc671..b8970b78e32a8 100644 --- a/test/integration/build-output/test/index.test.js +++ b/test/integration/build-output/test/index.test.js @@ -94,17 +94,17 @@ describe('Build Output', () => { expect(parseFloat(indexSize) - 265).toBeLessThanOrEqual(0) expect(indexSize.endsWith('B')).toBe(true) - // should be no bigger than 60.2 kb - expect(parseFloat(indexFirstLoad) - 60.5).toBeLessThanOrEqual(0) + // should be no bigger than 60.8 kb + expect(parseFloat(indexFirstLoad) - 60.8).toBeLessThanOrEqual(0) expect(indexFirstLoad.endsWith('kB')).toBe(true) expect(parseFloat(err404Size) - 3.5).toBeLessThanOrEqual(0) expect(err404Size.endsWith('kB')).toBe(true) - expect(parseFloat(err404FirstLoad) - 63.7).toBeLessThanOrEqual(0) + expect(parseFloat(err404FirstLoad) - 63.8).toBeLessThanOrEqual(0) expect(err404FirstLoad.endsWith('kB')).toBe(true) - expect(parseFloat(sharedByAll) - 60.2).toBeLessThanOrEqual(0) + expect(parseFloat(sharedByAll) - 60.4).toBeLessThanOrEqual(0) expect(sharedByAll.endsWith('kB')).toBe(true) if (_appSize.endsWith('kB')) { diff --git a/yarn.lock b/yarn.lock index ef39521971cc6..30c492a6a51f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7545,11 +7545,6 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -finally-polyfill@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/finally-polyfill/-/finally-polyfill-0.1.0.tgz#2a17b16581d9477db16a703c7b79a898ac0b7d50" - integrity sha512-J1LEcZ5VXe1l3sEO+S//WqL5wcJ/ep7QeKJA6HhNZrcEEFj0eyC8IW3DEZhxySI2bx3r85dwAXz+vYPGuHx5UA== - find-cache-dir@3.3.1, find-cache-dir@^3.0.0, find-cache-dir@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880"