From 4db8c49cc31e4fc182391fae6903fb5ef4e8c66e Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 4 Apr 2022 10:29:32 -0500 Subject: [PATCH 1/4] v12.1.5-canary.1 --- 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 f56c4ff4407cf31..28b50506bc92c98 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.1.5-canary.0" + "version": "12.1.5-canary.1" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index b729a99e7ca4a29..107c430c105c9ce 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.5-canary.0", + "version": "12.1.5-canary.1", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index c122ad29753ee23..b825d9afece912f 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.5-canary.0", + "version": "12.1.5-canary.1", "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.5-canary.0", + "@next/eslint-plugin-next": "12.1.5-canary.1", "@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 5881ec4d151ffb4..0371bdbb4ece01e 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.5-canary.0", + "version": "12.1.5-canary.1", "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 e66103eeec6fc49..69ca188a2bdf6f0 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.5-canary.0", + "version": "12.1.5-canary.1", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index eebef970d451642..2edd8ffd3f87729 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.1.5-canary.0", + "version": "12.1.5-canary.1", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 738eb252b148308..567bce3044296a6 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.1.5-canary.0", + "version": "12.1.5-canary.1", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 3b16da1d08570d8..a6e7875a906124a 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.1.5-canary.0", + "version": "12.1.5-canary.1", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index daec429d309d59c..33ac96cda82630b 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.5-canary.0", + "version": "12.1.5-canary.1", "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 8797fd8c32da219..2988c98ea9ce04d 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.5-canary.0", + "version": "12.1.5-canary.1", "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 5650489fd970cde..560d414b461f39a 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.5-canary.0", + "version": "12.1.5-canary.1", "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 78a07fda12acd98..18e288794b343cc 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.1.5-canary.0", + "version": "12.1.5-canary.1", "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 5d9b406bf21e9aa..8686a0ac7ee5b12 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.1.5-canary.0", + "version": "12.1.5-canary.1", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -69,7 +69,7 @@ ] }, "dependencies": { - "@next/env": "12.1.5-canary.0", + "@next/env": "12.1.5-canary.1", "caniuse-lite": "^1.0.30001283", "postcss": "8.4.5", "styled-jsx": "5.0.1" @@ -117,11 +117,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.4.4", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "12.1.5-canary.0", - "@next/polyfill-nomodule": "12.1.5-canary.0", - "@next/react-dev-overlay": "12.1.5-canary.0", - "@next/react-refresh-utils": "12.1.5-canary.0", - "@next/swc": "12.1.5-canary.0", + "@next/polyfill-module": "12.1.5-canary.1", + "@next/polyfill-nomodule": "12.1.5-canary.1", + "@next/react-dev-overlay": "12.1.5-canary.1", + "@next/react-refresh-utils": "12.1.5-canary.1", + "@next/swc": "12.1.5-canary.1", "@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 60af51c620bb66e..4660a06a3352859 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.5-canary.0", + "version": "12.1.5-canary.1", "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 8eb3cc5132f9c7e..9437586eb259efc 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.5-canary.0", + "version": "12.1.5-canary.1", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", From 081e7b00278395c205532a70a5da1be5c8f363eb Mon Sep 17 00:00:00 2001 From: Sukka Date: Tue, 5 Apr 2022 02:18:49 +0800 Subject: [PATCH 2/4] fix: reset visible state when src/href changed (#35287) * fix(#35286): reset visible state when image src changed * fix(#35286): reset visible state when link href changed * test(image): image with new src should be re-lazyloaded * test: apply code suggestions from @styfle's review * test: incorrect condition of image load check --- packages/next/client/image.tsx | 20 +++-- packages/next/client/link.tsx | 15 +++- packages/next/client/use-intersection.tsx | 8 +- .../default/pages/lazy-src-change.js | 18 ++++ .../default/test/index.test.js | 89 +++++++++++++++++++ 5 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 test/integration/image-component/default/pages/lazy-src-change.js diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index c75a88e45afe194..6f7d9eb4b5bdedc 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -417,11 +417,12 @@ export default function Image({ isLazy = false } - const [setIntersection, isIntersected] = useIntersection({ - rootRef: lazyRoot, - rootMargin: lazyBoundary, - disabled: !isLazy, - }) + const [setIntersection, isIntersected, resetIntersected] = + useIntersection({ + rootRef: lazyRoot, + rootMargin: lazyBoundary, + disabled: !isLazy, + }) const isVisible = !isLazy || isIntersected const wrapperStyle: JSX.IntrinsicElements['span']['style'] = { @@ -639,7 +640,6 @@ export default function Image({ ? { aspectRatio: `${widthInt} / ${heightInt}` } : layoutStyle ) - const blurStyle = placeholder === 'blur' ? { @@ -743,14 +743,20 @@ export default function Image({ typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect const onLoadingCompleteRef = useRef(onLoadingComplete) + const previousImageSrc = useRef(src) const imgRef = useRef(null) useEffect(() => { onLoadingCompleteRef.current = onLoadingComplete }, [onLoadingComplete]) useLayoutEffect(() => { + if (previousImageSrc.current !== src) { + resetIntersected() + previousImageSrc.current = src + } + setIntersection(imgRef.current) - }, [setIntersection]) + }, [setIntersection, resetIntersected, src]) useEffect(() => { handleLoading(imgRef, srcString, layout, placeholder, onLoadingCompleteRef) diff --git a/packages/next/client/link.tsx b/packages/next/client/link.tsx index 379d21123e152e6..517a7d22829b249 100644 --- a/packages/next/client/link.tsx +++ b/packages/next/client/link.tsx @@ -219,6 +219,9 @@ function Link(props: React.PropsWithChildren) { } }, [router, props.href, props.as]) + const previousHref = React.useRef(href) + const previousAs = React.useRef(as) + let { children, replace, shallow, scroll, locale } = props if (typeof children === 'string') { @@ -248,11 +251,19 @@ function Link(props: React.PropsWithChildren) { } const childRef: any = child && typeof child === 'object' && child.ref - const [setIntersectionRef, isVisible] = useIntersection({ + const [setIntersectionRef, isVisible, resetVisible] = useIntersection({ rootMargin: '200px', }) + const setRef = React.useCallback( (el: Element) => { + // Before the link getting observed, check if visible state need to be reset + if (previousAs.current !== as || previousHref.current !== href) { + resetVisible() + previousAs.current = as + previousHref.current = href + } + setIntersectionRef(el) if (childRef) { if (typeof childRef === 'function') childRef(el) @@ -261,7 +272,7 @@ function Link(props: React.PropsWithChildren) { } } }, - [childRef, setIntersectionRef] + [as, childRef, href, resetVisible, setIntersectionRef] ) React.useEffect(() => { const shouldPrefetch = isVisible && p && isLocalURL(href) diff --git a/packages/next/client/use-intersection.tsx b/packages/next/client/use-intersection.tsx index 1b3a39db57d9d3e..afcc29004fb0c49 100644 --- a/packages/next/client/use-intersection.tsx +++ b/packages/next/client/use-intersection.tsx @@ -29,7 +29,7 @@ export function useIntersection({ rootRef, rootMargin, disabled, -}: UseIntersection): [(element: T | null) => void, boolean] { +}: UseIntersection): [(element: T | null) => void, boolean, () => void] { const isDisabled: boolean = disabled || !hasIntersectionObserver const unobserve = useRef() @@ -55,6 +55,10 @@ export function useIntersection({ [isDisabled, root, rootMargin, visible] ) + const resetVisible = useCallback(() => { + setVisible(false) + }, []) + useEffect(() => { if (!hasIntersectionObserver) { if (!visible) { @@ -67,7 +71,7 @@ export function useIntersection({ useEffect(() => { if (rootRef) setRoot(rootRef.current) }, [rootRef]) - return [setRef, visible] + return [setRef, visible, resetVisible] } function observe( diff --git a/test/integration/image-component/default/pages/lazy-src-change.js b/test/integration/image-component/default/pages/lazy-src-change.js new file mode 100644 index 000000000000000..9500a29ea186b41 --- /dev/null +++ b/test/integration/image-component/default/pages/lazy-src-change.js @@ -0,0 +1,18 @@ +import React from 'react' +import Image from 'next/image' + +const Page = () => { + const [src, setSrc] = React.useState('/test.jpg') + return ( +
+

Home Page

+
+ + +
+ ) +} + +export default Page diff --git a/test/integration/image-component/default/test/index.test.js b/test/integration/image-component/default/test/index.test.js index afb6a71e4fdc044..fc09281dec0c132 100644 --- a/test/integration/image-component/default/test/index.test.js +++ b/test/integration/image-component/default/test/index.test.js @@ -1183,6 +1183,95 @@ function runTests(mode) { } }) + it('should re-lazyload images after src changes', async () => { + let browser + try { + browser = await webdriver(appPort, '/lazy-src-change') + // image should not be loaded as it is out of viewport + await check(async () => { + const result = await browser.eval( + `document.getElementById('basic-image').naturalWidth` + ) + + if (result >= 400) { + throw new Error('Incorrectly loaded image') + } + + return 'result-correct' + }, /result-correct/) + + // Move image into viewport + await browser.eval( + 'document.getElementById("spacer").style.display = "none"' + ) + + // image should be loaded by now + await check(async () => { + const result = await browser.eval( + `document.getElementById('basic-image').naturalWidth` + ) + + if (result < 400) { + throw new Error('Incorrectly loaded image') + } + + return 'result-correct' + }, /result-correct/) + + await check( + () => browser.eval(`document.getElementById("basic-image").currentSrc`), + /test\.jpg/ + ) + + // Make image out of viewport again + await browser.eval( + 'document.getElementById("spacer").style.display = "block"' + ) + // Toggle image's src + await browser.eval( + 'document.getElementById("button-change-image-src").click()' + ) + // "new" image should be lazy loaded + await check(async () => { + const result = await browser.eval( + `document.getElementById('basic-image').naturalWidth` + ) + + if (result >= 400) { + throw new Error('Incorrectly loaded image') + } + + return 'result-correct' + }, /result-correct/) + + // Move image into viewport again + await browser.eval( + 'document.getElementById("spacer").style.display = "none"' + ) + // "new" image should be loaded by now + await check(async () => { + const result = await browser.eval( + `document.getElementById('basic-image').naturalWidth` + ) + + if (result < 400) { + throw new Error('Incorrectly loaded image') + } + + return 'result-correct' + }, /result-correct/) + + await check( + () => browser.eval(`document.getElementById("basic-image").currentSrc`), + /test\.png/ + ) + } finally { + if (browser) { + await browser.close() + } + } + }) + it('should initially load only two of four images using lazyroot', async () => { let browser try { From 686a0f598a9555bf98bb88561a11ffaef094e6ef Mon Sep 17 00:00:00 2001 From: Lee Robinson Date: Mon, 4 Apr 2022 13:25:56 -0500 Subject: [PATCH 3/4] Add Vitest example. (#35858) ## 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 - [x] Make sure the linting passes by running `yarn lint` --- docs/testing.md | 1 + examples/with-vitest/.gitignore | 34 ++++++ examples/with-vitest/README.md | 23 ++++ examples/with-vitest/__tests__/Home.test.tsx | 15 +++ examples/with-vitest/next-env.d.ts | 5 + examples/with-vitest/next.config.js | 6 + examples/with-vitest/package.json | 23 ++++ examples/with-vitest/pages/_app.tsx | 6 + examples/with-vitest/pages/index.tsx | 72 ++++++++++++ examples/with-vitest/public/favicon.ico | Bin 0 -> 9662 bytes examples/with-vitest/public/vercel.svg | 4 + examples/with-vitest/styles/Home.module.css | 116 +++++++++++++++++++ examples/with-vitest/styles/globals.css | 16 +++ examples/with-vitest/tsconfig.json | 20 ++++ examples/with-vitest/vitest.config.ts | 12 ++ 15 files changed, 353 insertions(+) create mode 100644 examples/with-vitest/.gitignore create mode 100644 examples/with-vitest/README.md create mode 100644 examples/with-vitest/__tests__/Home.test.tsx create mode 100644 examples/with-vitest/next-env.d.ts create mode 100644 examples/with-vitest/next.config.js create mode 100644 examples/with-vitest/package.json create mode 100644 examples/with-vitest/pages/_app.tsx create mode 100644 examples/with-vitest/pages/index.tsx create mode 100644 examples/with-vitest/public/favicon.ico create mode 100644 examples/with-vitest/public/vercel.svg create mode 100644 examples/with-vitest/styles/Home.module.css create mode 100644 examples/with-vitest/styles/globals.css create mode 100644 examples/with-vitest/tsconfig.json create mode 100644 examples/with-vitest/vitest.config.ts diff --git a/docs/testing.md b/docs/testing.md index 500016c6bff84fa..d24cd71f3249a9e 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -10,6 +10,7 @@ description: Learn how to set up Next.js with three commonly used testing tools
  • Next.js with Cypress
  • Next.js with Playwright
  • Next.js with Jest and React Testing Library
  • +
  • Next.js with Vitest
  • diff --git a/examples/with-vitest/.gitignore b/examples/with-vitest/.gitignore new file mode 100644 index 000000000000000..1437c53f70bc211 --- /dev/null +++ b/examples/with-vitest/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/examples/with-vitest/README.md b/examples/with-vitest/README.md new file mode 100644 index 000000000000000..5bd869b5c98a63f --- /dev/null +++ b/examples/with-vitest/README.md @@ -0,0 +1,23 @@ +# Vitest + +This example shows how to use [Vitest](https://github.com/vitest-dev/vitest) with Next.js. + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com/) or preview live with [StackBlitz](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-vitest) + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-vitest&project-name=with-vitest&repository-name=with-vitest) + +## How to use + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npx create-next-app --example with-vitest with-vitest-app +# or +yarn create next-app --example with-vitest with-vitest-app +# or +pnpm create next-app -- --example with-vitest with-vitest-app +``` + +Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-vitest/__tests__/Home.test.tsx b/examples/with-vitest/__tests__/Home.test.tsx new file mode 100644 index 000000000000000..c6f8dc2303427a2 --- /dev/null +++ b/examples/with-vitest/__tests__/Home.test.tsx @@ -0,0 +1,15 @@ +import { expect, test } from 'vitest' +import { render, screen, within } from '@testing-library/react' +import Home from '../pages' + +test('home', () => { + render() + const main = within(screen.getByRole('main')) + expect( + main.getByRole('heading', { level: 1, name: /welcome to next\.js!/i }) + ).toBeDefined() + + const footer = within(screen.getByRole('contentinfo')) + const link = within(footer.getByRole('link')) + expect(link.getByRole('img', { name: /vercel logo/i })).toBeDefined() +}) diff --git a/examples/with-vitest/next-env.d.ts b/examples/with-vitest/next-env.d.ts new file mode 100644 index 000000000000000..4f11a03dc6cc37f --- /dev/null +++ b/examples/with-vitest/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/examples/with-vitest/next.config.js b/examples/with-vitest/next.config.js new file mode 100644 index 000000000000000..a843cbee09afaad --- /dev/null +++ b/examples/with-vitest/next.config.js @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, +} + +module.exports = nextConfig diff --git a/examples/with-vitest/package.json b/examples/with-vitest/package.json new file mode 100644 index 000000000000000..973a91ffeed555a --- /dev/null +++ b/examples/with-vitest/package.json @@ -0,0 +1,23 @@ +{ + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "test": "vitest" + }, + "dependencies": { + "next": "latest", + "react": "18.0.0", + "react-dom": "18.0.0" + }, + "devDependencies": { + "@testing-library/react": "^12.1.4", + "@types/node": "17.0.23", + "@types/react": "17.0.43", + "@vitejs/plugin-react": "1.3.0", + "jsdom": "^19.0.0", + "typescript": "4.6.3", + "vitest": "0.8.4" + } +} diff --git a/examples/with-vitest/pages/_app.tsx b/examples/with-vitest/pages/_app.tsx new file mode 100644 index 000000000000000..33da2fce548ca16 --- /dev/null +++ b/examples/with-vitest/pages/_app.tsx @@ -0,0 +1,6 @@ +import '../styles/globals.css' +import type { AppProps } from 'next/app' + +export default function MyApp({ Component, pageProps }: AppProps) { + return +} diff --git a/examples/with-vitest/pages/index.tsx b/examples/with-vitest/pages/index.tsx new file mode 100644 index 000000000000000..86b5b3b5bf3fdf0 --- /dev/null +++ b/examples/with-vitest/pages/index.tsx @@ -0,0 +1,72 @@ +import type { NextPage } from 'next' +import Head from 'next/head' +import Image from 'next/image' +import styles from '../styles/Home.module.css' + +const Home: NextPage = () => { + return ( + + ) +} + +export default Home diff --git a/examples/with-vitest/public/favicon.ico b/examples/with-vitest/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d14dbd1d8638dedb13d7e28fe6c3a3b9b5252921 GIT binary patch literal 9662 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 NmKV{Y3p@wx{lAx8wfg`7 literal 0 HcmV?d00001 diff --git a/examples/with-vitest/public/vercel.svg b/examples/with-vitest/public/vercel.svg new file mode 100644 index 000000000000000..fbf0e25a651c289 --- /dev/null +++ b/examples/with-vitest/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/examples/with-vitest/styles/Home.module.css b/examples/with-vitest/styles/Home.module.css new file mode 100644 index 000000000000000..32a57d52f34c482 --- /dev/null +++ b/examples/with-vitest/styles/Home.module.css @@ -0,0 +1,116 @@ +.container { + padding: 0 2rem; +} + +.main { + min-height: 100vh; + padding: 4rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + display: flex; + flex: 1; + padding: 2rem 0; + border-top: 1px solid #eaeaea; + justify-content: center; + align-items: center; +} + +.footer a { + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; +} + +.title a { + color: #0070f3; + text-decoration: none; +} + +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} + +.title { + margin: 0; + line-height: 1.15; + font-size: 4rem; +} + +.title, +.description { + text-align: center; +} + +.description { + margin: 4rem 0; + line-height: 1.5; + font-size: 1.5rem; +} + +.code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, + Bitstream Vera Sans Mono, Courier New, monospace; +} + +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + max-width: 800px; +} + +.card { + margin: 1rem; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: color 0.15s ease, border-color 0.15s ease; + max-width: 300px; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h2 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; + margin-left: 0.5rem; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/examples/with-vitest/styles/globals.css b/examples/with-vitest/styles/globals.css new file mode 100644 index 000000000000000..e5e2dcc23baf192 --- /dev/null +++ b/examples/with-vitest/styles/globals.css @@ -0,0 +1,16 @@ +html, +body { + padding: 0; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +} diff --git a/examples/with-vitest/tsconfig.json b/examples/with-vitest/tsconfig.json new file mode 100644 index 000000000000000..99710e857874ff8 --- /dev/null +++ b/examples/with-vitest/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/examples/with-vitest/vitest.config.ts b/examples/with-vitest/vitest.config.ts new file mode 100644 index 000000000000000..e82ca6b60b1d660 --- /dev/null +++ b/examples/with-vitest/vitest.config.ts @@ -0,0 +1,12 @@ +/// + +import { defineConfig } from 'vitest/config' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + test: { + environment: 'jsdom', + }, +}) From 384953b35c5e9935bb4a2fcdfe5056efb73cd740 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 4 Apr 2022 13:35:46 -0500 Subject: [PATCH 4/4] Stabilize react streaming ISR test (#35885) --- .../test/switchable-runtime.test.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/integration/react-streaming-and-server-components/test/switchable-runtime.test.js b/test/integration/react-streaming-and-server-components/test/switchable-runtime.test.js index ff3375015cf193a..f53496b58b1f448 100644 --- a/test/integration/react-streaming-and-server-components/test/switchable-runtime.test.js +++ b/test/integration/react-streaming-and-server-components/test/switchable-runtime.test.js @@ -1,7 +1,7 @@ /* eslint-env jest */ import webdriver from 'next-webdriver' import { join } from 'path' -import { findPort, killApp, renderViaHTTP } from 'next-test-utils' +import { check, findPort, killApp, renderViaHTTP } from 'next-test-utils' import { nextBuild, nextDev, nextStart } from './utils' const appDir = join(__dirname, '../switchable-runtime') @@ -109,11 +109,13 @@ describe('Switchable runtime (prod)', () => { await new Promise((resolve) => setTimeout(resolve, 4000)) await renderViaHTTP(context.appPort, '/node-rsc-isr') - const html3 = await renderViaHTTP(context.appPort, '/node-rsc-isr') - const renderedAt3 = +html3.match(/Time: (\d+)/)[1] - expect(html3).toContain('Runtime: Node.js') - - expect(renderedAt2).toBeLessThan(renderedAt3) + await check(async () => { + const html3 = await renderViaHTTP(context.appPort, '/node-rsc-isr') + const renderedAt3 = +html3.match(/Time: (\d+)/)[1] + return renderedAt2 < renderedAt3 + ? 'success' + : `${renderedAt2} should be less than ${renderedAt3}` + }, 'success') }) it('should build /edge as a dynamic page with the edge runtime', async () => {