fix(link): cancel idle callback on unmount (#22072)
Co-authored-by: mAAdhaTTah <jamesorodig@gmail.com>
This commit is contained in:
parent
27b6dd6b02
commit
5f41abda9a
10 changed files with 149 additions and 11 deletions
|
@ -50,6 +50,7 @@
|
|||
"@opentelemetry/plugin-http": "0.14.0",
|
||||
"@opentelemetry/plugin-https": "0.14.0",
|
||||
"@opentelemetry/tracing": "0.14.0",
|
||||
"@testing-library/react": "11.2.5",
|
||||
"@types/cheerio": "0.22.16",
|
||||
"@types/fs-extra": "8.1.0",
|
||||
"@types/http-proxy": "1.17.3",
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { useEffect, useContext } from 'react'
|
|||
import { ScriptHTMLAttributes } from 'react'
|
||||
import { HeadManagerContext } from '../next-server/lib/head-manager-context'
|
||||
import { DOMAttributeNames } from './head-manager'
|
||||
import requestIdleCallback from './request-idle-callback'
|
||||
import { requestIdleCallback } from './request-idle-callback'
|
||||
|
||||
const ScriptCache = new Map()
|
||||
const LoadCache = new Set()
|
||||
|
|
|
@ -13,10 +13,11 @@ declare global {
|
|||
callback: (deadline: RequestIdleCallbackDeadline) => void,
|
||||
opts?: RequestIdleCallbackOptions
|
||||
) => RequestIdleCallbackHandle
|
||||
cancelIdleCallback: (id: RequestIdleCallbackHandle) => void
|
||||
}
|
||||
}
|
||||
|
||||
const requestIdleCallback =
|
||||
export const requestIdleCallback =
|
||||
(typeof self !== 'undefined' && self.requestIdleCallback) ||
|
||||
function (
|
||||
cb: (deadline: RequestIdleCallbackDeadline) => void
|
||||
|
@ -32,4 +33,8 @@ const requestIdleCallback =
|
|||
}, 1)
|
||||
}
|
||||
|
||||
export default requestIdleCallback
|
||||
export const cancelIdleCallback =
|
||||
(typeof self !== 'undefined' && self.cancelIdleCallback) ||
|
||||
function (id: RequestIdleCallbackHandle) {
|
||||
return clearTimeout(id)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ComponentType } from 'react'
|
||||
import { ClientBuildManifest } from '../build/webpack/plugins/build-manifest-plugin'
|
||||
import getAssetPathFromRoute from '../next-server/lib/router/utils/get-asset-path-from-route'
|
||||
import requestIdleCallback from './request-idle-callback'
|
||||
import { requestIdleCallback } from './request-idle-callback'
|
||||
|
||||
// 3.8s was arbitrarily chosen as it's what https://web.dev/interactive
|
||||
// considers as "Good" time-to-interactive. We must assume something went
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import requestIdleCallback from './request-idle-callback'
|
||||
import {
|
||||
requestIdleCallback,
|
||||
cancelIdleCallback,
|
||||
} from './request-idle-callback'
|
||||
|
||||
type UseIntersectionObserverInit = Pick<IntersectionObserverInit, 'rootMargin'>
|
||||
type UseIntersection = { disabled?: boolean } & UseIntersectionObserverInit
|
||||
|
@ -43,7 +46,10 @@ export function useIntersection<T extends Element>({
|
|||
|
||||
useEffect(() => {
|
||||
if (!hasIntersectionObserver) {
|
||||
if (!visible) requestIdleCallback(() => setVisible(true))
|
||||
if (!visible) {
|
||||
const idleCallback = requestIdleCallback(() => setVisible(true))
|
||||
return () => cancelIdleCallback(idleCallback)
|
||||
}
|
||||
}
|
||||
}, [visible])
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
module.exports=(()=>{"use strict";var e={301:(e,r,t)=>{const _=t(979);e.exports=(e=>typeof e==="string"?e.replace(_(),""):e)},979:e=>{e.exports=(({onlyFirst:e=false}={})=>{const r=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(r,e?undefined:"g")})}};var r={};function __nccwpck_require__(t){if(r[t]){return r[t].exports}var _=r[t]={exports:{}};var n=true;try{e[t](_,_.exports,__nccwpck_require__);n=false}finally{if(n)delete r[t]}return _.exports}__nccwpck_require__.ab=__dirname+"/";return __nccwpck_require__(301)})();
|
||||
module.exports=(()=>{"use strict";var e={161:e=>{e.exports=(({onlyFirst:e=false}={})=>{const r=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(r,e?undefined:"g")})},301:(e,r,t)=>{const _=t(161);e.exports=(e=>typeof e==="string"?e.replace(_(),""):e)}};var r={};function __nccwpck_require__(t){if(r[t]){return r[t].exports}var _=r[t]={exports:{}};var n=true;try{e[t](_,_.exports,__nccwpck_require__);n=false}finally{if(n)delete r[t]}return _.exports}__nccwpck_require__.ab=__dirname+"/";return __nccwpck_require__(301)})();
|
|
@ -94,14 +94,14 @@ describe('Build Output', () => {
|
|||
expect(parseFloat(indexSize) - 266).toBeLessThanOrEqual(0)
|
||||
expect(indexSize.endsWith('B')).toBe(true)
|
||||
|
||||
// should be no bigger than 63.8 kb
|
||||
expect(parseFloat(indexFirstLoad)).toBeCloseTo(63.8, 1)
|
||||
// should be no bigger than 63.9 kb
|
||||
expect(parseFloat(indexFirstLoad)).toBeCloseTo(63.9, 1)
|
||||
expect(indexFirstLoad.endsWith('kB')).toBe(true)
|
||||
|
||||
expect(parseFloat(err404Size) - 3.7).toBeLessThanOrEqual(0)
|
||||
expect(err404Size.endsWith('kB')).toBe(true)
|
||||
|
||||
expect(parseFloat(err404FirstLoad)).toBeCloseTo(67, 1)
|
||||
expect(parseFloat(err404FirstLoad)).toBeCloseTo(67.1, 0)
|
||||
expect(err404FirstLoad.endsWith('kB')).toBe(true)
|
||||
|
||||
expect(parseFloat(sharedByAll)).toBeCloseTo(63.6, 1)
|
||||
|
|
|
@ -81,6 +81,6 @@ describe('Production response size', () => {
|
|||
const delta = responseSizesBytes / 1024
|
||||
|
||||
// Expected difference: < 0.5
|
||||
expect(delta).toBeCloseTo(284.1, 0)
|
||||
expect(delta).toBeCloseTo(284.7, 0)
|
||||
})
|
||||
})
|
||||
|
|
33
test/unit/link-warnings.test.js
Normal file
33
test/unit/link-warnings.test.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { act, render } from '@testing-library/react'
|
||||
import Link from 'next/link'
|
||||
|
||||
describe('<Link/>', () => {
|
||||
let spy
|
||||
beforeAll(() => {
|
||||
spy = jest.spyOn(console, 'error').mockImplementation(() => {})
|
||||
})
|
||||
|
||||
it('test link with unmount', () => {
|
||||
act(() => {
|
||||
const { unmount } = render(<Link href="/">hello</Link>)
|
||||
unmount()
|
||||
})
|
||||
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('test link without unmount', () => {
|
||||
act(() => {
|
||||
render(<Link href="/">hello</Link>)
|
||||
})
|
||||
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
spy.mockRestore()
|
||||
})
|
||||
})
|
93
yarn.lock
93
yarn.lock
|
@ -958,6 +958,14 @@
|
|||
pirates "^4.0.0"
|
||||
source-map-support "^0.5.16"
|
||||
|
||||
"@babel/runtime-corejs3@^7.10.2":
|
||||
version "7.12.13"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.12.13.tgz#53d09813b7c20d616caf258e9325550ff701c039"
|
||||
integrity sha512-8fSpqYRETHATtNitsCXq8QQbKJP31/KnDl2Wz2Vtui9nKzjss2ysuZtyVsWjBtvkeEFo346gkwjYPab1hvrXkQ==
|
||||
dependencies:
|
||||
core-js-pure "^3.0.0"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime-corejs3@^7.12.1":
|
||||
version "7.12.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz#ffee91da0eb4c6dae080774e94ba606368e414f4"
|
||||
|
@ -973,6 +981,13 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.10.2":
|
||||
version "7.12.13"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.13.tgz#0a21452352b02542db0ffb928ac2d3ca7cb6d66d"
|
||||
integrity sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.3.3", "@babel/template@^7.4.0":
|
||||
version "7.12.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc"
|
||||
|
@ -1551,6 +1566,17 @@
|
|||
"@types/yargs" "^15.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@jest/types@^26.6.2":
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e"
|
||||
integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==
|
||||
dependencies:
|
||||
"@types/istanbul-lib-coverage" "^2.0.0"
|
||||
"@types/istanbul-reports" "^3.0.0"
|
||||
"@types/node" "*"
|
||||
"@types/yargs" "^15.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@lerna/add@3.14.0":
|
||||
version "3.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.14.0.tgz#799d416e67d48c285967abf883be746557aefa48"
|
||||
|
@ -2604,12 +2630,39 @@
|
|||
dependencies:
|
||||
chokidar "^1.7.0"
|
||||
|
||||
"@testing-library/dom@^7.28.1":
|
||||
version "7.29.4"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.29.4.tgz#1647c2b478789621ead7a50614ad81ab5ae5b86c"
|
||||
integrity sha512-CtrJRiSYEfbtNGtEsd78mk1n1v2TUbeABlNIcOCJdDfkN5/JTOwQEbbQpoSRxGqzcWPgStMvJ4mNolSuBRv1NA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.10.4"
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@types/aria-query" "^4.2.0"
|
||||
aria-query "^4.2.2"
|
||||
chalk "^4.1.0"
|
||||
dom-accessibility-api "^0.5.4"
|
||||
lz-string "^1.4.4"
|
||||
pretty-format "^26.6.2"
|
||||
|
||||
"@testing-library/react@11.2.5":
|
||||
version "11.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.5.tgz#ae1c36a66c7790ddb6662c416c27863d87818eb9"
|
||||
integrity sha512-yEx7oIa/UWLe2F2dqK0FtMF9sJWNXD+2PPtp39BvE0Kh9MJ9Kl0HrZAgEuhUJR+Lx8Di6Xz+rKwSdEPY2UV8ZQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@testing-library/dom" "^7.28.1"
|
||||
|
||||
"@types/amphtml-validator@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/amphtml-validator/-/amphtml-validator-1.0.0.tgz#9d4e0c879642938bbe5f363d49cafc8ae9f57c81"
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/aria-query@^4.2.0":
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.1.tgz#78b5433344e2f92e8b306c06a5622c50c245bf6b"
|
||||
integrity sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==
|
||||
|
||||
"@types/async-retry@1.4.2":
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/async-retry/-/async-retry-1.4.2.tgz#7f910188cd3893b51e32df51765ee8d5646053e3"
|
||||
|
@ -2811,6 +2864,13 @@
|
|||
"@types/istanbul-lib-coverage" "*"
|
||||
"@types/istanbul-lib-report" "*"
|
||||
|
||||
"@types/istanbul-reports@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821"
|
||||
integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==
|
||||
dependencies:
|
||||
"@types/istanbul-lib-report" "*"
|
||||
|
||||
"@types/jest-diff@*":
|
||||
version "24.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-24.3.0.tgz#29e237a3d954babfe6e23cc59b57ecd8ca8d858d"
|
||||
|
@ -3578,6 +3638,14 @@ args@4.0.0:
|
|||
leven "2.1.0"
|
||||
mri "1.1.0"
|
||||
|
||||
aria-query@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
|
||||
integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.2"
|
||||
"@babel/runtime-corejs3" "^7.10.2"
|
||||
|
||||
arity-n@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745"
|
||||
|
@ -6072,6 +6140,11 @@ doctrine@^3.0.0:
|
|||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
dom-accessibility-api@^0.5.4:
|
||||
version "0.5.4"
|
||||
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz#b06d059cdd4a4ad9a79275f9d414a5c126241166"
|
||||
integrity sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==
|
||||
|
||||
dom-serializer@0:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
|
||||
|
@ -10244,6 +10317,11 @@ lru_map@^0.3.3:
|
|||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
|
||||
|
||||
lz-string@^1.4.4:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
|
||||
integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=
|
||||
|
||||
macos-release@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
|
||||
|
@ -12943,6 +13021,16 @@ pretty-format@^26.0.1:
|
|||
ansi-styles "^4.0.0"
|
||||
react-is "^16.12.0"
|
||||
|
||||
pretty-format@^26.6.2:
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93"
|
||||
integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==
|
||||
dependencies:
|
||||
"@jest/types" "^26.6.2"
|
||||
ansi-regex "^5.0.0"
|
||||
ansi-styles "^4.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
pretty-hrtime@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||
|
@ -13248,6 +13336,11 @@ react-is@16.13.1, react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1, react-i
|
|||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
|
||||
react-is@^17.0.1:
|
||||
version "17.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
|
||||
integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==
|
||||
|
||||
react-refresh@0.8.3:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
|
||||
|
|
Loading…
Reference in a new issue