From 0355e5f63f87db489f36db8d814958cb4c2b828b Mon Sep 17 00:00:00 2001 From: Steven Date: Thu, 10 Mar 2022 06:02:13 -0800 Subject: [PATCH 1/4] Fix `next/image` when src is webp but browser doesnt support it (#35190) * Fix `next/image` when src is webp but browser doesnt support it * Exclude old sharp since it doesnt support AVIF --- packages/next/server/image-optimizer.ts | 7 +++- .../image-optimizer/app/public/test.avif | Bin 0 -> 1043 bytes .../image-optimizer/app/public/test.webp | Bin 0 -> 1018 bytes test/integration/image-optimizer/test/util.js | 38 ++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/integration/image-optimizer/app/public/test.avif create mode 100644 test/integration/image-optimizer/app/public/test.webp diff --git a/packages/next/server/image-optimizer.ts b/packages/next/server/image-optimizer.ts index 976bd8c29fd6..9adec2dd8a1d 100644 --- a/packages/next/server/image-optimizer.ts +++ b/packages/next/server/image-optimizer.ts @@ -419,7 +419,12 @@ export async function imageOptimizer( if (mimeType) { contentType = mimeType - } else if (upstreamType?.startsWith('image/') && getExtension(upstreamType)) { + } else if ( + upstreamType?.startsWith('image/') && + getExtension(upstreamType) && + upstreamType !== WEBP && + upstreamType !== AVIF + ) { contentType = upstreamType } else { contentType = JPEG diff --git a/test/integration/image-optimizer/app/public/test.avif b/test/integration/image-optimizer/app/public/test.avif new file mode 100644 index 0000000000000000000000000000000000000000..e2c8170a6833ebff1ae4e11b9abff1bee6f4bdeb GIT binary patch literal 1043 zcmZQzU{FXasVqn=%S>Yc0uY^>nP!-qnV9D5Xy^nK`jnemk_eIm0*#E6oFWL5fuSHX zxdg@r(K(q(Fk|=%GD~v7a*RMyE;A=T8N_p8U|HGYPp_`;RN zQI{$oYx^~h{C(Tl1>lMeCPK)4A9urjDmcF}Sym>Oq zuQvx$8Y^FDRZDZOWigVCZeiEkrgxdQRO`S}W#70Swno%#aR?0O_-fq@A z-td)488LdsvuqsOrJH7$mpA;W{kt{rw6ka2>P6SsmbvX-Aywq>sQL4q8{^?~mjnJg z20obKDzi<|bg6crjj7nL&JLcE+fO_VBRQ8@g@t_nB@%R!>CSEYYUf!`7hLns*tTd> zSWy-Gb7sq_oii%;?o^*IcRoF4R$A*kG5^U`OFsSW3(c9ZQt8M zob`Q+N!|6H`07RK4oh-e^;{*{7S<|t-8djNcUhnIfm{C!4jj3$VX>{8g{4pX*>^6T zT(>g5aGCZtO|AQ=c0|p&tk~r!&%xKXR-Whno43-~uSGn0M(wpNqM?_#CeJPGxvD(z z{6Zl!X%nq=i^}`Lg)}a;PG*i{bJ7WFX4p~rhiM^mP+0QgIn%Gt(YT`Pp7ZwbcCmX8 zWVc7J-??N}_n$*M6TdNLr07%x{9L-mp21sQc-6yijyltyR=BP#OPsFth@+or&m-O` ai*%+vXFpb>?I3lmL0LhJC*)VwLI(iE8=mC= literal 0 HcmV?d00001 diff --git a/test/integration/image-optimizer/app/public/test.webp b/test/integration/image-optimizer/app/public/test.webp new file mode 100644 index 0000000000000000000000000000000000000000..4b306cb0898cc93e83dd6f72566e13cbd1339eaa GIT binary patch literal 1018 zcmWIYbaVT}%)k)t>J$(bV4?5~$lhSgFqctl0^gPIDuB8qHv48H-EEbk|FBuIt(=eGzI!$@2M@ z#TTkpe-pQ_(pI`{*bt+CqK4g>WuD^-8`F(nA0CC+|Bv@@pq)xt!UWH|e=J2I&PYA^ zWlqk)0|9oTHfu`3u4+!vT_4xYrvJXmxxu=z`*eD{~o~@4h9AWfq9;% zqR$+A*q{}?M)}6!)9;$Um~P0+FB3LdlX7i)VN-;n!!5QNkGLvHafX9Y89~=x2}Fh~ z6{=Xw=Xf8owQpHQQhfe*DWBsR$IZ_)v2DNh4;YT~5_h_!EDZl17V~0$^#W^&%R;M9 z1TEjSC+p$CeWvFQFka)8vCV&;F*&+u0)t$j-NbM5|Eshts#iT?RJqI9Y@6$P?sJE; z(L-rLjkkxn89m~?Lr5i{_oxx zSN0*UK=A6}>)z2FvXA5!`;<=WJryi<{b@Bvy@XxL&U~+rMl7KV^LSQ#f56oEGG)cK z=rpw;j*oejQy>@ zO`}}>1>=?-D{WT%kUkpAsF(X!&bNaVHSjask0+H4Wp zPLZ)O`L|h_E7aw-7d((IxEm7R?EL(E9LSfq9oZdPx)1Qg`#-(@lK0TJ8-elG*X7c( z`yam$?FnSP{2}Dw-$B|+seK+ P+udJbdSnVPy+8l}7RKRp literal 0 HcmV?d00001 diff --git a/test/integration/image-optimizer/test/util.js b/test/integration/image-optimizer/test/util.js index 51c57a75552d..ee83f9e93b18 100644 --- a/test/integration/image-optimizer/test/util.js +++ b/test/integration/image-optimizer/test/util.js @@ -313,6 +313,44 @@ export function runTests(ctx) { ) }) + it('should downlevel webp format to jpeg for old Safari', async () => { + const accept = + 'image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5' + const query = { w: ctx.w, q: 74, url: '/test.webp' } + const opts = { headers: { accept } } + const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) + expect(res.status).toBe(200) + expect(res.headers.get('Content-Type')).toContain('image/jpeg') + expect(res.headers.get('Cache-Control')).toBe( + `public, max-age=0, must-revalidate` + ) + expect(res.headers.get('Vary')).toBe('Accept') + expect(res.headers.get('etag')).toBeTruthy() + expect(res.headers.get('Content-Disposition')).toBe( + `inline; filename="test.jpeg"` + ) + }) + + if (!ctx.isOutdatedSharp) { + it('should downlevel avif format to jpeg for old Safari', async () => { + const accept = + 'image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5' + const query = { w: ctx.w, q: 74, url: '/test.avif' } + const opts = { headers: { accept } } + const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) + expect(res.status).toBe(200) + expect(res.headers.get('Content-Type')).toContain('image/jpeg') + expect(res.headers.get('Cache-Control')).toBe( + `public, max-age=0, must-revalidate` + ) + expect(res.headers.get('Vary')).toBe('Accept') + expect(res.headers.get('etag')).toBeTruthy() + expect(res.headers.get('Content-Disposition')).toBe( + `inline; filename="test.jpeg"` + ) + }) + } + it('should fail when url is missing', async () => { const query = { w: ctx.w, q: 100 } const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, {}) From ea87415fd9fa56014a1b100d2ea22a3673cef1b9 Mon Sep 17 00:00:00 2001 From: Huzaifa Arif Date: Thu, 10 Mar 2022 21:36:50 +0530 Subject: [PATCH 2/4] [Fix] Adds try/catch to gracefully handle performance observer exception (#35202) * fix: add try/catch to gracefull handle performance observer exception on older browsers * fix: run prettier Co-authored-by: Steven --- packages/next/client/image.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index d6ebf363b0f6..d152015405a0 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -516,7 +516,15 @@ export default function Image({ } } }) - perfObserver.observe({ type: 'largest-contentful-paint', buffered: true }) + try { + perfObserver.observe({ + type: 'largest-contentful-paint', + buffered: true, + }) + } catch (err) { + // Log error but don't crash the app + console.error(err) + } } } From ceb7bfb29dce38f6c63457976c637067e300228e Mon Sep 17 00:00:00 2001 From: Steven Date: Thu, 10 Mar 2022 08:22:40 -0800 Subject: [PATCH 3/4] v12.1.1-canary.9 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lerna.json b/lerna.json index f411ef9ce6c8..515a9edf1e50 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.1.1-canary.8" + "version": "12.1.1-canary.9" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 3e02fb5edb32..ff787d70a9af 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index e9023015fd1c..84dc3c6fe711 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.1.1-canary.8", + "@next/eslint-plugin-next": "12.1.1-canary.9", "@rushstack/eslint-patch": "1.0.8", "@typescript-eslint/parser": "5.10.1", "eslint-import-resolver-node": "0.3.4", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 0208b5a89096..f5caaaf2e34e 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index a7ef9334de69..998d8d06c23e 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index d1e9a336c93a..c12d1f599644 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index c3996ab34cb2..2682cbc60a86 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index f808a21e2c9a..53576caa4125 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 50a018b2482e..f7081a66c65d 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 3a0f758e0e10..a92f24e82548 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "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", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 5cdc322cc818..84fcf5adb90f 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 8c242db5a02f..dae7970e300b 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "private": true, "scripts": { "build-native": "napi build --platform --cargo-name next_swc_napi native", diff --git a/packages/next/package.json b/packages/next/package.json index 2771e7bd430b..d046592a1eb1 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -69,7 +69,7 @@ ] }, "dependencies": { - "@next/env": "12.1.1-canary.8", + "@next/env": "12.1.1-canary.9", "caniuse-lite": "^1.0.30001283", "postcss": "8.4.5", "styled-jsx": "5.0.0", @@ -118,11 +118,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.4.4", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.1.1-canary.8", - "@next/polyfill-nomodule": "12.1.1-canary.8", - "@next/react-dev-overlay": "12.1.1-canary.8", - "@next/react-refresh-utils": "12.1.1-canary.8", - "@next/swc": "12.1.1-canary.8", + "@next/polyfill-module": "12.1.1-canary.9", + "@next/polyfill-nomodule": "12.1.1-canary.9", + "@next/react-dev-overlay": "12.1.1-canary.9", + "@next/react-refresh-utils": "12.1.1-canary.9", + "@next/swc": "12.1.1-canary.9", "@peculiar/webcrypto": "1.3.1", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index bf695d697fb4..f6b6eaea5c62 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 716883592004..45dcab7bbabf 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.1.1-canary.8", + "version": "12.1.1-canary.9", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", From 7ce5d3f2408b08c6121b7edd825615161c616309 Mon Sep 17 00:00:00 2001 From: chemicalkosek Date: Thu, 10 Mar 2022 19:12:23 +0100 Subject: [PATCH 4/4] Re-add _document to with-styled-components example (#35163) `_document.js` was removed from the styled components swc example I have tested with and without the custom `_document.js` Unfortunately without `_document.js` there is FOUC (Flash of unstyled content) on initial request. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint` Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com> --- .../with-styled-components/pages/_document.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 examples/with-styled-components/pages/_document.js diff --git a/examples/with-styled-components/pages/_document.js b/examples/with-styled-components/pages/_document.js new file mode 100644 index 000000000000..2a59afeb93c1 --- /dev/null +++ b/examples/with-styled-components/pages/_document.js @@ -0,0 +1,30 @@ +import Document from 'next/document' +import { ServerStyleSheet } from 'styled-components' + +export default class MyDocument extends Document { + static async getInitialProps(ctx) { + const sheet = new ServerStyleSheet() + const originalRenderPage = ctx.renderPage + + try { + ctx.renderPage = () => + originalRenderPage({ + enhanceApp: (App) => (props) => + sheet.collectStyles(), + }) + + const initialProps = await Document.getInitialProps(ctx) + return { + ...initialProps, + styles: ( + <> + {initialProps.styles} + {sheet.getStyleElement()} + + ), + } + } finally { + sheet.seal() + } + } +}