From 51bdd970338e22deae6db9acfec90458c810c349 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 27 Apr 2022 10:32:44 -0500 Subject: [PATCH 01/40] Fix failing yarn PnP test from missing dependency (#36515) --- examples/with-styled-components-babel/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/with-styled-components-babel/package.json b/examples/with-styled-components-babel/package.json index a9a999263eda5..73fccf597a88b 100644 --- a/examples/with-styled-components-babel/package.json +++ b/examples/with-styled-components-babel/package.json @@ -14,6 +14,7 @@ }, "devDependencies": { "@types/node": "17.0.24", + "@types/react": "^17.0.2", "@types/styled-components": "5.1.25", "babel-plugin-styled-components": "^1.12.0", "typescript": "4.6.3" From f550da7031ba58f62ad66c842b4abcee0b86168f Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 27 Apr 2022 17:33:13 +0200 Subject: [PATCH 02/40] Remove passhref Eslint rule as it's no longer needed with new link behavior (#36511) --- packages/eslint-plugin-next/lib/index.js | 2 - .../lib/rules/link-passhref.js | 64 ---------- .../eslint-plugin-next/link-passhref.test.ts | 109 ------------------ 3 files changed, 175 deletions(-) delete mode 100644 packages/eslint-plugin-next/lib/rules/link-passhref.js delete mode 100644 test/unit/eslint-plugin-next/link-passhref.test.ts diff --git a/packages/eslint-plugin-next/lib/index.js b/packages/eslint-plugin-next/lib/index.js index 98554159b6601..84b77fddeb32c 100644 --- a/packages/eslint-plugin-next/lib/index.js +++ b/packages/eslint-plugin-next/lib/index.js @@ -10,7 +10,6 @@ module.exports = { 'no-title-in-document-head': require('./rules/no-title-in-document-head'), 'google-font-display': require('./rules/google-font-display'), 'google-font-preconnect': require('./rules/google-font-preconnect'), - 'link-passhref': require('./rules/link-passhref'), 'no-document-import-in-page': require('./rules/no-document-import-in-page'), 'no-head-import-in-document': require('./rules/no-head-import-in-document'), 'no-script-component-in-head': require('./rules/no-script-component-in-head'), @@ -36,7 +35,6 @@ module.exports = { '@next/next/no-title-in-document-head': 1, '@next/next/google-font-display': 1, '@next/next/google-font-preconnect': 1, - '@next/next/link-passhref': 1, '@next/next/next-script-for-ga': 1, '@next/next/no-document-import-in-page': 2, '@next/next/no-head-import-in-document': 2, diff --git a/packages/eslint-plugin-next/lib/rules/link-passhref.js b/packages/eslint-plugin-next/lib/rules/link-passhref.js deleted file mode 100644 index 97c13029aff94..0000000000000 --- a/packages/eslint-plugin-next/lib/rules/link-passhref.js +++ /dev/null @@ -1,64 +0,0 @@ -const NodeAttributes = require('../utils/node-attributes.js') - -module.exports = { - meta: { - docs: { - description: - 'Ensure passHref is assigned if child of Link component is a custom component', - category: 'HTML', - recommended: true, - url: 'https://nextjs.org/docs/messages/link-passhref', - }, - fixable: null, - }, - - create: function (context) { - let linkImport = null - - return { - ImportDeclaration(node) { - if (node.source.value === 'next/link') { - linkImport = node.specifiers[0].local.name - } - }, - - JSXOpeningElement(node) { - if (node.name.name !== linkImport) { - return - } - - const attributes = new NodeAttributes(node) - const children = node.parent.children - - if ( - !attributes.hasAny() || - !attributes.has('href') || - !children.some((attr) => attr.type === 'JSXElement') - ) { - return - } - - const hasPassHref = - attributes.has('passHref') && - (typeof attributes.value('passHref') === 'undefined' || - attributes.value('passHref') === true) - - const hasAnchorChild = children.some( - (attr) => - attr.type === 'JSXElement' && attr.openingElement.name.name === 'a' - ) - - if (!hasAnchorChild && !hasPassHref) { - context.report({ - node, - message: `passHref ${ - attributes.value('passHref') !== true - ? 'must be set to true' - : 'is missing' - }. See: https://nextjs.org/docs/messages/link-passhref`, - }) - } - }, - } - }, -} diff --git a/test/unit/eslint-plugin-next/link-passhref.test.ts b/test/unit/eslint-plugin-next/link-passhref.test.ts deleted file mode 100644 index 6b8f3668edf0f..0000000000000 --- a/test/unit/eslint-plugin-next/link-passhref.test.ts +++ /dev/null @@ -1,109 +0,0 @@ -import rule from '@next/eslint-plugin-next/lib/rules/link-passhref' -import { RuleTester } from 'eslint' -;(RuleTester as any).setDefaultConfig({ - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - ecmaFeatures: { - modules: true, - jsx: true, - }, - }, -}) -const ruleTester = new RuleTester() - -ruleTester.run('link-passhref', rule, { - valid: [ - ` - import Link from 'next/link' - export const Home = () => ( - - )`, - - ` - import Link from 'next/link' - export const Home = () => ( - - Test - - )`, - - ` - import Link from 'next/link' - export const Home = () => ( - - Test - - )`, - - `const Link = () =>
Fake Link
- - const Home = () => ( - - - - )`, - - ` - import NextLink from 'next/link' - export const Home = () => ( - - Test - - )`, - ], - - invalid: [ - { - code: ` - import Link from 'next/link' - - export const Home = () => ( - - Test - - )`, - errors: [ - { - message: - 'passHref is missing. See: https://nextjs.org/docs/messages/link-passhref', - type: 'JSXOpeningElement', - }, - ], - }, - { - code: ` - import NextLink from 'next/link' - - export const Home = () => ( - - Test - - )`, - errors: [ - { - message: - 'passHref is missing. See: https://nextjs.org/docs/messages/link-passhref', - type: 'JSXOpeningElement', - }, - ], - }, - { - code: ` - import Link from 'next/link' - - export const Home = () => ( - - Test - - )`, - errors: [ - { - message: - 'passHref must be set to true. See: https://nextjs.org/docs/messages/link-passhref', - type: 'JSXOpeningElement', - }, - ], - }, - ], -}) From 5907e9d3945d6471438cc087e652ca244e3d3c8e Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 27 Apr 2022 17:34:18 +0200 Subject: [PATCH 03/40] v12.1.6-canary.10 --- 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 3655810e0487b..5e56185468f5e 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.1.6-canary.9" + "version": "12.1.6-canary.10" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 184b7c7ca76be..19f1086d23120 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.6-canary.9", + "version": "12.1.6-canary.10", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 4658e35c3c0c2..6751e5f540e3c 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.6-canary.9", + "version": "12.1.6-canary.10", "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.6-canary.9", + "@next/eslint-plugin-next": "12.1.6-canary.10", "@rushstack/eslint-patch": "1.0.8", "@typescript-eslint/parser": "5.19.0", "eslint-import-resolver-node": "0.3.4", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index c79ac9de9bc06..6bd0ac6f127aa 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.6-canary.9", + "version": "12.1.6-canary.10", "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 588a90c1764b7..0218187553a1c 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.6-canary.9", + "version": "12.1.6-canary.10", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index f60e46d202a86..b593e5e675666 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.1.6-canary.9", + "version": "12.1.6-canary.10", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 6c0967f0732d9..f652d05c5eddd 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.1.6-canary.9", + "version": "12.1.6-canary.10", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index cb98df8525e1c..df755cd441912 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.1.6-canary.9", + "version": "12.1.6-canary.10", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index b59b74bf68b27..f63a336a029c9 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.6-canary.9", + "version": "12.1.6-canary.10", "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 ba53ff75e15d8..0892b3521787d 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.6-canary.9", + "version": "12.1.6-canary.10", "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 ac661c1dde5f3..a13dbc7b5be62 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.6-canary.9", + "version": "12.1.6-canary.10", "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 aa08aeb669f01..b674f04eed06e 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.1.6-canary.9", + "version": "12.1.6-canary.10", "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 a2d6d03d54ab2..3edc4af67c28c 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.1.6-canary.9", + "version": "12.1.6-canary.10", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -69,7 +69,7 @@ ] }, "dependencies": { - "@next/env": "12.1.6-canary.9", + "@next/env": "12.1.6-canary.10", "caniuse-lite": "^1.0.30001332", "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.6-canary.9", - "@next/polyfill-nomodule": "12.1.6-canary.9", - "@next/react-dev-overlay": "12.1.6-canary.9", - "@next/react-refresh-utils": "12.1.6-canary.9", - "@next/swc": "12.1.6-canary.9", + "@next/polyfill-module": "12.1.6-canary.10", + "@next/polyfill-nomodule": "12.1.6-canary.10", + "@next/react-dev-overlay": "12.1.6-canary.10", + "@next/react-refresh-utils": "12.1.6-canary.10", + "@next/swc": "12.1.6-canary.10", "@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 9a6cb4929e4d6..ee285979325bc 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.6-canary.9", + "version": "12.1.6-canary.10", "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 c8a3c2447b651..0141cf5eeb800 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.6-canary.9", + "version": "12.1.6-canary.10", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", From c232d3856aa069f6d90ee4726e89338e59b7374f Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 27 Apr 2022 18:39:56 +0200 Subject: [PATCH 04/40] Add string children case for newNextLinkBehavior codemod (#36516) --- .../__testfixtures__/new-link/link-string.input.js | 8 ++++++++ .../__testfixtures__/new-link/link-string.output.js | 8 ++++++++ .../transforms/__tests__/new-link.test.js | 3 ++- packages/next-codemod/transforms/new-link.ts | 13 +++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 packages/next-codemod/transforms/__testfixtures__/new-link/link-string.input.js create mode 100644 packages/next-codemod/transforms/__testfixtures__/new-link/link-string.output.js diff --git a/packages/next-codemod/transforms/__testfixtures__/new-link/link-string.input.js b/packages/next-codemod/transforms/__testfixtures__/new-link/link-string.input.js new file mode 100644 index 0000000000000..4bad6108ed55e --- /dev/null +++ b/packages/next-codemod/transforms/__testfixtures__/new-link/link-string.input.js @@ -0,0 +1,8 @@ +import Link from 'next/link' +export default function Page() { + return ( + + Link + + ); +} \ No newline at end of file diff --git a/packages/next-codemod/transforms/__testfixtures__/new-link/link-string.output.js b/packages/next-codemod/transforms/__testfixtures__/new-link/link-string.output.js new file mode 100644 index 0000000000000..4bad6108ed55e --- /dev/null +++ b/packages/next-codemod/transforms/__testfixtures__/new-link/link-string.output.js @@ -0,0 +1,8 @@ +import Link from 'next/link' +export default function Page() { + return ( + + Link + + ); +} \ No newline at end of file diff --git a/packages/next-codemod/transforms/__tests__/new-link.test.js b/packages/next-codemod/transforms/__tests__/new-link.test.js index 4807a16967232..36724ec0e7df0 100644 --- a/packages/next-codemod/transforms/__tests__/new-link.test.js +++ b/packages/next-codemod/transforms/__tests__/new-link.test.js @@ -8,7 +8,8 @@ const fixtures = [ 'add-legacy-behavior', 'excludes-links-with-legacybehavior-prop', 'children-interpolation', - 'spread-props' + 'spread-props', + 'link-string' ] for (const fixture of fixtures) { diff --git a/packages/next-codemod/transforms/new-link.ts b/packages/next-codemod/transforms/new-link.ts index 21cb4c0757da9..95f5c7dee5880 100644 --- a/packages/next-codemod/transforms/new-link.ts +++ b/packages/next-codemod/transforms/new-link.ts @@ -36,6 +36,19 @@ export default function transformer(file: FileInfo, api: API) { if ($link.size() === 0) { return } + + const linkChildrenNodes = $link.get('children') + + // Text-only link children are already correct with the new behavior + // `next/link` would previously auto-wrap typeof 'string' children already + if ( + linkChildrenNodes.value && + linkChildrenNodes.value.length === 1 && + linkChildrenNodes.value[0].type === 'JSXText' + ) { + return + } + // Direct child elements referenced const $childrenElements = $link.childElements() const $childrenWithA = $childrenElements.filter((childPath) => { From 5e3225da0fd7140136e3437af43a89fa1deda143 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 27 Apr 2022 18:40:33 +0200 Subject: [PATCH 05/40] v12.1.6-canary.11 --- 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 5e56185468f5e..f9ca4bf9efab6 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.1.6-canary.10" + "version": "12.1.6-canary.11" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 19f1086d23120..ce72667507e5c 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.6-canary.10", + "version": "12.1.6-canary.11", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 6751e5f540e3c..0f24f91d184f0 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.6-canary.10", + "version": "12.1.6-canary.11", "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.6-canary.10", + "@next/eslint-plugin-next": "12.1.6-canary.11", "@rushstack/eslint-patch": "1.0.8", "@typescript-eslint/parser": "5.19.0", "eslint-import-resolver-node": "0.3.4", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 6bd0ac6f127aa..ba84887f45c74 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.6-canary.10", + "version": "12.1.6-canary.11", "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 0218187553a1c..961aabf9b9c61 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.6-canary.10", + "version": "12.1.6-canary.11", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index b593e5e675666..549cc8f67a04d 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.1.6-canary.10", + "version": "12.1.6-canary.11", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index f652d05c5eddd..022030f17671c 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.1.6-canary.10", + "version": "12.1.6-canary.11", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index df755cd441912..69714f3f389d2 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.1.6-canary.10", + "version": "12.1.6-canary.11", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index f63a336a029c9..dcae1cf02898b 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.6-canary.10", + "version": "12.1.6-canary.11", "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 0892b3521787d..b1f9aea65260c 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.6-canary.10", + "version": "12.1.6-canary.11", "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 a13dbc7b5be62..9c8db63e3e5fb 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.6-canary.10", + "version": "12.1.6-canary.11", "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 b674f04eed06e..080fc9813de6c 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.1.6-canary.10", + "version": "12.1.6-canary.11", "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 3edc4af67c28c..49486a24762de 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.1.6-canary.10", + "version": "12.1.6-canary.11", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -69,7 +69,7 @@ ] }, "dependencies": { - "@next/env": "12.1.6-canary.10", + "@next/env": "12.1.6-canary.11", "caniuse-lite": "^1.0.30001332", "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.6-canary.10", - "@next/polyfill-nomodule": "12.1.6-canary.10", - "@next/react-dev-overlay": "12.1.6-canary.10", - "@next/react-refresh-utils": "12.1.6-canary.10", - "@next/swc": "12.1.6-canary.10", + "@next/polyfill-module": "12.1.6-canary.11", + "@next/polyfill-nomodule": "12.1.6-canary.11", + "@next/react-dev-overlay": "12.1.6-canary.11", + "@next/react-refresh-utils": "12.1.6-canary.11", + "@next/swc": "12.1.6-canary.11", "@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 ee285979325bc..a9e935b31c8f2 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.6-canary.10", + "version": "12.1.6-canary.11", "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 0141cf5eeb800..fcbaa6dbbda34 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.6-canary.10", + "version": "12.1.6-canary.11", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", From 89a4c1626b2f0690c8c780972e1bcc40b31b4def Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 27 Apr 2022 11:41:34 -0500 Subject: [PATCH 06/40] Remove extra yarn PnP example test (#36518) --- test/e2e/yarn-pnp/test/with-styled-components-babel.test.ts | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 test/e2e/yarn-pnp/test/with-styled-components-babel.test.ts diff --git a/test/e2e/yarn-pnp/test/with-styled-components-babel.test.ts b/test/e2e/yarn-pnp/test/with-styled-components-babel.test.ts deleted file mode 100644 index 35c778df540b5..0000000000000 --- a/test/e2e/yarn-pnp/test/with-styled-components-babel.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { runTests } from './utils' - -describe('yarn PnP', () => { - runTests('with-styled-components-babel') -}) From 842e4ec02381234bdea82a9c95e75cc79e211a09 Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Wed, 27 Apr 2022 09:49:17 -0700 Subject: [PATCH 07/40] Add with-edgedb example (#35929) ## Documentation / Examples - [X] Make sure the linting passes by running `yarn lint` --- examples/with-edgedb/.eslintignore | 1 + examples/with-edgedb/.gitignore | 38 ++++ examples/with-edgedb/README.md | 150 +++++++++++++++ examples/with-edgedb/client.ts | 9 + examples/with-edgedb/components/Header.tsx | 55 ++++++ examples/with-edgedb/components/Layout.tsx | 51 ++++++ examples/with-edgedb/components/Post.tsx | 40 ++++ examples/with-edgedb/dbschema/default.esdl | 11 ++ .../dbschema/migrations/00001.edgeql | 15 ++ examples/with-edgedb/edgedb.toml | 2 + examples/with-edgedb/next-env.d.ts | 5 + examples/with-edgedb/package.json | 25 +++ examples/with-edgedb/pages/api/post/[id].ts | 44 +++++ examples/with-edgedb/pages/api/post/index.ts | 20 ++ .../with-edgedb/pages/api/publish/[id].ts | 19 ++ examples/with-edgedb/pages/blog/[id].tsx | 172 ++++++++++++++++++ examples/with-edgedb/pages/create.tsx | 97 ++++++++++ examples/with-edgedb/pages/drafts.tsx | 62 +++++++ examples/with-edgedb/pages/index.tsx | 65 +++++++ examples/with-edgedb/seed.ts | 51 ++++++ examples/with-edgedb/tsconfig.json | 26 +++ 21 files changed, 958 insertions(+) create mode 100644 examples/with-edgedb/.eslintignore create mode 100644 examples/with-edgedb/.gitignore create mode 100644 examples/with-edgedb/README.md create mode 100644 examples/with-edgedb/client.ts create mode 100644 examples/with-edgedb/components/Header.tsx create mode 100644 examples/with-edgedb/components/Layout.tsx create mode 100644 examples/with-edgedb/components/Post.tsx create mode 100644 examples/with-edgedb/dbschema/default.esdl create mode 100644 examples/with-edgedb/dbschema/migrations/00001.edgeql create mode 100644 examples/with-edgedb/edgedb.toml create mode 100644 examples/with-edgedb/next-env.d.ts create mode 100644 examples/with-edgedb/package.json create mode 100644 examples/with-edgedb/pages/api/post/[id].ts create mode 100644 examples/with-edgedb/pages/api/post/index.ts create mode 100644 examples/with-edgedb/pages/api/publish/[id].ts create mode 100644 examples/with-edgedb/pages/blog/[id].tsx create mode 100644 examples/with-edgedb/pages/create.tsx create mode 100644 examples/with-edgedb/pages/drafts.tsx create mode 100644 examples/with-edgedb/pages/index.tsx create mode 100644 examples/with-edgedb/seed.ts create mode 100644 examples/with-edgedb/tsconfig.json diff --git a/examples/with-edgedb/.eslintignore b/examples/with-edgedb/.eslintignore new file mode 100644 index 0000000000000..1749e6c3ad9b1 --- /dev/null +++ b/examples/with-edgedb/.eslintignore @@ -0,0 +1 @@ +dbschema/edgeql-js \ No newline at end of file diff --git a/examples/with-edgedb/.gitignore b/examples/with-edgedb/.gitignore new file mode 100644 index 0000000000000..0256922fe850e --- /dev/null +++ b/examples/with-edgedb/.gitignore @@ -0,0 +1,38 @@ +# 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 +.vscode +*.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 + +# query builder +dbschema/edgeql-js diff --git a/examples/with-edgedb/README.md b/examples/with-edgedb/README.md new file mode 100644 index 0000000000000..16ca965307e28 --- /dev/null +++ b/examples/with-edgedb/README.md @@ -0,0 +1,150 @@ +# Full-stack EdgeDB + Next.js application + +A simple blog application built with Next.js, TypeScript, [React](https://reactjs.org/), and [EdgeDB](https://www.edgedb.com/docs) on the backend. + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): + +[![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-edgedb&project-name=with-edgedb&repository-name=with-edgedb&env=EDGEDB_DSN) + +## How to use + +### Download the example project + +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-edgedb with-edgedb-app +# or +yarn create next-app --example with-edgedb with-edgedb-app +# or +pnpm create next-app -- --example with-edgedb with-edgedb-app +``` + +Then `cd` into the created directory. + +```bash +$ cd with-edgedb-app +``` + +### Install the CLI + +First install the EdgeDB CLI if you haven't already. + +```bash +# macOS/Linux +$ curl --proto '=https' --tlsv1.2 -sSf https://sh.edgedb.com | sh + +# Windows (Powershell) +$ iwr https://ps1.edgedb.com -useb | iex +``` + +### Initialize the EdgeDB project + +Initialize the project with the following CLI command: + +```bash +$ edgedb project init +``` + +After you follow the prompts, this command will spin up a local EdgeDB instance and apply all the migrations inside `dbschema/migrations`. Now that the project is initialized, all EdgeDB clients initialized inside the project directory will connect to this instance automatically—no need for environment variables or hard-coded configuration. ([Read more about projects here.](https://www.edgedb.com/docs/guides/projects)) + +### Install dependencies + +Install npm dependencies: + +```bash +$ npm install +# or +$ yarn +``` + +### Generate the query builder + +This project uses the EdgeQL query builder for TypeScript. This tool can express any EdgeQL query in a code-first way and infers a static return type. Generate it with the following command: + +```bash +$ npx edgeql-js +``` + +The query builder consists of several files that are generated into the `dbschema/edgeql-js` directory. Import it like so: + +```ts +import e from './dbschema/edgeql-js' +``` + +### Seed the database + +```bash +$ npx ts-node seed.ts +``` + +### Start the app + +```bash +$ yarn dev +``` + +The application should now be running on http://localhost:3000. + +## Notes + +#### packages structure + +- `/`: See all published posts +- `/drafts`: See all drafts +- `/create`: Form to create new draft +- `/blog/:id`: See either an edit page or a published post, depending on the publish status of the post. + +#### API structure + +- `POST /api/post`: Create a new post + - Body: `{title: string; content: string; authorName: string}` +- `PATCH /api/post/:id`: Update a post by `id` + - Body: `{title?: string; content?: string;}` +- `PUT /api/publish/:id`: Publish a post by `id` +- `DELETE /api/post/:id`: Delete a post by `id` + +## Evolving the app + +Evolving the application typically requires three steps: + +1. Update the schema in `dbschema/default.esdl` +2. Generate a new migration with `edgedb migration create` +3. Apply the migration with `edgedb migrate` +4. Regenerate the query builder with `npx edgeql-js` +5. Update the application code, as needed. + +## Deployment + +To deploy this application, deploy EdgeDB to your preferred cloud provider: + +- [AWS](https://www.edgedb.com/docs/guides/deployment/aws_aurora_ecs) +- [Google Cloud](https://www.edgedb.com/docs/guides/deployment/gcp) +- [Azure](https://www.edgedb.com/docs/guides/deployment/azure_flexibleserver) +- [DigitalOcean](https://www.edgedb.com/docs/guides/deployment/digitalocean) +- [Fly.io](https://www.edgedb.com/docs/guides/deployment/fly_io) +- [Docker](https://www.edgedb.com/docs/guides/deployment/docker) (cloud-agnostic) + +Then: + +1. Find your instance's DSN (AKA connection string). The exact instructions for this depend on which cloud you are deploying to. + +2. Use this DSN to migrate your remote instance to the latest schema. Run this command from inside your project directory. + +``` +edgedb migrate --dsn --tls-security insecure +``` + +You have to disable TLS checks with `--tls-security insecure`. All EdgeDB instances use TLS by default, but configuring it is out of scope of this project. + +3. Deploy this app to Vercel with the button above. You'll be prompted to provide a value for `EDGEDB_DSN`, the value from the previous step. + +4. Open the application at the deployment URL supplied by Vercel. + +## Next steps + +- Check out the [EdgeDB docs](https://www.edgedb.com/docs) +- Join the EdgeDB [Discord server](https://edgedb.com/p/discord) +- Check out the code on [GitHub](https://github.com/edgedb/edgedb) diff --git a/examples/with-edgedb/client.ts b/examples/with-edgedb/client.ts new file mode 100644 index 0000000000000..4cb2a65302ebf --- /dev/null +++ b/examples/with-edgedb/client.ts @@ -0,0 +1,9 @@ +import { createClient } from 'edgedb' +import e from './dbschema/edgeql-js' + +// reads value of EDGEDB_DSN automatically +export const client = createClient({ + // TLS configuration is beyond the scope of this example project + tlsSecurity: 'insecure', +}) +export { e } diff --git a/examples/with-edgedb/components/Header.tsx b/examples/with-edgedb/components/Header.tsx new file mode 100644 index 0000000000000..84ac53b51696e --- /dev/null +++ b/examples/with-edgedb/components/Header.tsx @@ -0,0 +1,55 @@ +import React from 'react' +import Link from 'next/link' + +const Header: React.FC = () => { + return ( + + ) +} + +export default Header diff --git a/examples/with-edgedb/components/Layout.tsx b/examples/with-edgedb/components/Layout.tsx new file mode 100644 index 0000000000000..2ccd1e683196a --- /dev/null +++ b/examples/with-edgedb/components/Layout.tsx @@ -0,0 +1,51 @@ +import React, { ReactNode } from 'react' +import Header from './Header' + +type Props = { + children: ReactNode +} + +const Layout: React.FC = (props) => ( +
+
+
{props.children}
+ + +
+) + +export default Layout diff --git a/examples/with-edgedb/components/Post.tsx b/examples/with-edgedb/components/Post.tsx new file mode 100644 index 0000000000000..9a7b6a7e8b9e5 --- /dev/null +++ b/examples/with-edgedb/components/Post.tsx @@ -0,0 +1,40 @@ +import React from 'react' +import ReactMarkdown from 'react-markdown' +import Link from 'next/link' +import { PostProps } from '../pages/blog/[id]' + +const Post: React.FC<{ post: PostProps }> = ({ post }) => { + return ( + +
+

{post.title}

+ By {post.authorName} +
+
+ + {post.content || ''} + + +
+ + ) +} + +export default Post diff --git a/examples/with-edgedb/dbschema/default.esdl b/examples/with-edgedb/dbschema/default.esdl new file mode 100644 index 0000000000000..0c9a5e13df134 --- /dev/null +++ b/examples/with-edgedb/dbschema/default.esdl @@ -0,0 +1,11 @@ +module default { + + type Post { + required property title -> str; + required property content -> str { default := '' }; + required property authorName -> str { default := 'Unknown author' }; + property published -> datetime; + property publishedISO := .published; + } + +} \ No newline at end of file diff --git a/examples/with-edgedb/dbschema/migrations/00001.edgeql b/examples/with-edgedb/dbschema/migrations/00001.edgeql new file mode 100644 index 0000000000000..bf37d554ef070 --- /dev/null +++ b/examples/with-edgedb/dbschema/migrations/00001.edgeql @@ -0,0 +1,15 @@ +CREATE MIGRATION m1gcnribdubi476w7daqzhuxvbutfpiqyhhbm2nyfv3xhzc6z757ia + ONTO initial +{ + CREATE TYPE default::Post { + CREATE REQUIRED PROPERTY authorName -> std::str { + SET default := 'Unknown author'; + }; + CREATE REQUIRED PROPERTY content -> std::str { + SET default := ''; + }; + CREATE PROPERTY published -> std::datetime; + CREATE PROPERTY publishedISO := (.published); + CREATE REQUIRED PROPERTY title -> std::str; + }; +}; diff --git a/examples/with-edgedb/edgedb.toml b/examples/with-edgedb/edgedb.toml new file mode 100644 index 0000000000000..b4968c856040c --- /dev/null +++ b/examples/with-edgedb/edgedb.toml @@ -0,0 +1,2 @@ +[edgedb] +server-version = "1.2" diff --git a/examples/with-edgedb/next-env.d.ts b/examples/with-edgedb/next-env.d.ts new file mode 100644 index 0000000000000..4f11a03dc6cc3 --- /dev/null +++ b/examples/with-edgedb/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-edgedb/package.json b/examples/with-edgedb/package.json new file mode 100644 index 0000000000000..abdcf9f56d391 --- /dev/null +++ b/examples/with-edgedb/package.json @@ -0,0 +1,25 @@ +{ + "private": true, + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start", + "seed": "ts-node dbschema/seed.ts", + "prebuild": "npx edgeql-js" + }, + "dependencies": { + "@types/react": "^18.0.5", + "@types/react-dom": "^18.0.1", + "edgedb": "latest", + "next": "latest", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "react-markdown": "^8.0.2" + }, + "devDependencies": { + "@types/node": "^16.11.26", + "prettier": "^2.6.2", + "ts-node": "^10.7.0", + "typescript": "^4.6.3" + } +} diff --git a/examples/with-edgedb/pages/api/post/[id].ts b/examples/with-edgedb/pages/api/post/[id].ts new file mode 100644 index 0000000000000..32aa946615b92 --- /dev/null +++ b/examples/with-edgedb/pages/api/post/[id].ts @@ -0,0 +1,44 @@ +import type { NextApiRequest, NextApiResponse } from 'next' +import { client, e } from '../../../client' + +export default async function handle( + req: NextApiRequest, + res: NextApiResponse +) { + const postId = req.query.id as string + + if (req.method === 'DELETE') { + res.json(await deletePost(postId)) + } else if (req.method === 'PATCH') { + res.json(await updatePost(postId, req.body)) + } else { + throw new Error( + `The HTTP ${req.method} method is not supported at this route.` + ) + } +} + +// PATCH /api/post/:id +async function updatePost( + postId: string, + data: { title?: string; content?: string } +) { + return await e + .update(e.Post, (post) => ({ + filter: e.op(post.id, '=', e.uuid(postId)), + set: { + title: data.title, + content: data.content, + }, + })) + .run(client) +} + +// DELETE /api/post/:id +async function deletePost(postId: string) { + return await e + .delete(e.Post, (post) => ({ + filter: e.op(post.id, '=', e.uuid(postId)), + })) + .run(client) +} diff --git a/examples/with-edgedb/pages/api/post/index.ts b/examples/with-edgedb/pages/api/post/index.ts new file mode 100644 index 0000000000000..2c073d10e306a --- /dev/null +++ b/examples/with-edgedb/pages/api/post/index.ts @@ -0,0 +1,20 @@ +import type { NextApiRequest, NextApiResponse } from 'next' +import { client, e } from '../../../client' + +// POST /api/post +// body {title: string; content: string; authorName: string} +export default async function handle( + req: NextApiRequest, + res: NextApiResponse +) { + const { title, content, authorName } = req.body + + const result = await e + .insert(e.Post, { + title, + content, + authorName, + }) + .run(client) + res.json(result) +} diff --git a/examples/with-edgedb/pages/api/publish/[id].ts b/examples/with-edgedb/pages/api/publish/[id].ts new file mode 100644 index 0000000000000..accb4bc9bfda2 --- /dev/null +++ b/examples/with-edgedb/pages/api/publish/[id].ts @@ -0,0 +1,19 @@ +import type { NextApiRequest, NextApiResponse } from 'next' +import { client, e } from '../../../client' + +// PUT /api/publish/:id +export default async function handle( + req: NextApiRequest, + res: NextApiResponse +) { + const postId = req.query.id as string + const post = await e + .update(e.Post, (post) => ({ + filter: e.op(post.id, '=', e.uuid(postId)), + set: { + published: e.std.datetime_of_statement(), + }, + })) + .run(client) + res.json(post) +} diff --git a/examples/with-edgedb/pages/blog/[id].tsx b/examples/with-edgedb/pages/blog/[id].tsx new file mode 100644 index 0000000000000..f9d0b79e53dc2 --- /dev/null +++ b/examples/with-edgedb/pages/blog/[id].tsx @@ -0,0 +1,172 @@ +import React, { useState } from 'react' +import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next' +import Layout from '../../components/Layout' +import Router from 'next/router' +import { client, e } from '../../client' + +import ReactMarkdown from 'react-markdown' + +async function update( + id: string, + data: { title?: string; content?: string } +): Promise { + await fetch(`/api/post/${id}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }) + alert('Draft saved!') +} + +async function publish(id: string): Promise { + await fetch(`/api/publish/${id}`, { + method: 'PUT', + }) + await Router.push(`/blog/${id}`) +} + +async function destroy(id: string): Promise { + await fetch(`/api/post/${id}`, { + method: 'DELETE', + }) + await Router.push('/') +} + +const Post: React.FC = (props) => { + const [patch, setPatch] = useState<{ + title?: string + content?: string + }>({ + title: props.title, + content: props.content || undefined, + }) + + if (props.publishedISO) { + return ( + +
+

+ {props.title} +

+

+ By {props.authorName} +

+
+
+ {props.content || ''} +
+
+ ) + } + + return ( + +
+ { + setPatch({ ...patch, title: e.target.value }) + }} + /> + +