diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index 2877acecb5e5..bd8eafaac3a2 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -153,7 +153,7 @@ jobs: - run: cat package.json | jq '.resolutions."react-dom" = "^17.0.1"' > package.json.tmp && mv package.json.tmp package.json - run: yarn install --check-files - run: yarn list webpack react react-dom - - run: xvfb-run node run-tests.js test/integration/link-ref/test/index.test.js test/integration/production/test/index.test.js test/integration/basic/test/index.test.js test/integration/async-modules/test/index.test.js test/integration/font-optimization/test/index.test.js test/acceptance/*.test.js + - run: xvfb-run node run-tests.js test/integration/{link-ref,production,basic,async-modules,font-optimization,ssr-ctx}/test/index.test.js test/acceptance/*.test.js testFirefox: name: Test Firefox (production) diff --git a/docs/api-reference/next.config.js/rewrites.md b/docs/api-reference/next.config.js/rewrites.md index 28c040178919..c32a370eddab 100644 --- a/docs/api-reference/next.config.js/rewrites.md +++ b/docs/api-reference/next.config.js/rewrites.md @@ -154,9 +154,10 @@ module.exports = { destination: '/another', // automatically becomes /docs/another }, { - // does not add /docs since basePath: false is set + // does not add /docs to /without-basePath since basePath: false is set + // Note: this can not be used for internal rewrites e.g. `destination: '/another'` source: '/without-basePath', - destination: '/another', + destination: 'https://example.com', basePath: false, }, ] diff --git a/docs/api-reference/next/router.md b/docs/api-reference/next/router.md index 3c92861ce46e..56de35581fb5 100644 --- a/docs/api-reference/next/router.md +++ b/docs/api-reference/next/router.md @@ -49,6 +49,7 @@ The following is the definition of the `router` object returned by both [`useRou - `locale`: `String` - The active locale (if enabled). - `locales`: `String[]` - All supported locales (if enabled). - `defaultLocale`: `String` - The current default locale (if enabled). +- `isReady`: `boolean` - Whether the router fields are updated client-side and ready for use. Should only be used inside of `useEffect` methods and not for conditionally rendering on the server. Additionally, the following methods are also included inside `router`: diff --git a/errors/incompatible-href-as.md b/errors/incompatible-href-as.md index b6c4e68e1d88..f6677e90b6e7 100644 --- a/errors/incompatible-href-as.md +++ b/errors/incompatible-href-as.md @@ -11,13 +11,15 @@ Note: this error will only show when the `next/link` component is clicked not wh ```jsx import Link from 'next/link' -export default () => ( - <> - - Invalid link - - > -) +export default function Page(props) { + return ( + <> + + Invalid link + + > + ) +} ``` **Compatible `href` and `as`** @@ -25,13 +27,15 @@ export default () => ( ```jsx import Link from 'next/link' -export default () => ( - <> - - Valid link - - > -) +export default function Page(props) { + return ( + <> + + Valid link + + > + ) +} ``` #### Possible Ways to Fix It diff --git a/errors/invalid-relative-url-external-as.md b/errors/invalid-relative-url-external-as.md new file mode 100644 index 000000000000..848b56d422e4 --- /dev/null +++ b/errors/invalid-relative-url-external-as.md @@ -0,0 +1,47 @@ +# Invalid relative `href` and external `as` values + +#### Why This Error Occurred + +Somewhere you are utilizing the `next/link` component, `Router#push`, or `Router#replace` with a relative route in your `href` that has an external `as` value. The `as` value must be relative also or only `href` should be used with an external URL. + +Note: this error will only show when the `next/link` component is clicked not when only rendered. + +**Incompatible `href` and `as`** + +```jsx +import Link from 'next/link' + +export default function Page(props) { + return ( + <> + + Invalid link + + > + ) +} +``` + +**Compatible `href` and `as`** + +```jsx +import Link from 'next/link' + +export default function Page(props) { + return ( + <> + + Invalid link + + > + ) +} +``` + +#### Possible Ways to Fix It + +Look for any usage of the `next/link` component, `Router#push`, or `Router#replace` and make sure that the provided `href` and `as` values are compatible + +### Useful Links + +- [Routing section in Documentation](https://nextjs.org/docs/routing/introduction) diff --git a/examples/blog-starter-typescript/README.md b/examples/blog-starter-typescript/README.md index e8db3fc2498c..671760cb4b37 100644 --- a/examples/blog-starter-typescript/README.md +++ b/examples/blog-starter-typescript/README.md @@ -30,4 +30,6 @@ Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&ut # Notes -This blog-starter-typescript uses [Tailwind CSS](https://tailwindcss.com). To control the generated stylesheet's filesize, this example uses Tailwind CSS' v1.4 [`purge` option](https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css) to remove unused CSS. +This blog-starter-typescript uses [Tailwind CSS](https://tailwindcss.com). To control the generated stylesheet's filesize, this example uses Tailwind CSS' v2.0 [`purge` option](https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css) to remove unused CSS. + +[Tailwind CSS v2.0 no longer supports Node.js 8 or 10](https://tailwindcss.com/docs/upgrading-to-v2#upgrade-to-node-js-12-13-or-higher). To build your CSS you'll need to ensure you are running Node.js 12.13.0 or higher in both your local and CI environments. diff --git a/examples/blog-starter-typescript/components/hero-post.tsx b/examples/blog-starter-typescript/components/hero-post.tsx index 5bd84f9bbe0d..cd0f121c01fa 100644 --- a/examples/blog-starter-typescript/components/hero-post.tsx +++ b/examples/blog-starter-typescript/components/hero-post.tsx @@ -26,7 +26,7 @@ const HeroPost = ({
+ Get started by editing pages/index.js
+
content
' + }, +} + +// elements with display:flex are focusable in IE10-11 +var focusFlexboxContainer = { + element: 'span', + mutate: function mutate(element) { + element.setAttribute( + 'style', + 'display: -webkit-flex; display: -ms-flexbox; display: flex;' + ) + element.innerHTML = 'hello' + }, +} + +// form[tabindex=0][disabled] should be focusable as the +// specification doesn't know the disabled attribute on the form element +// @specification https://www.w3.org/TR/html5/forms.html#the-form-element +var focusFormDisabled = { + element: 'form', + mutate: function mutate(element) { + element.setAttribute('tabindex', 0) + element.setAttribute('disabled', 'disabled') + }, +} + +// NOTE: https://github.com/medialize/ally.js/issues/35 +// fixes https://github.com/medialize/ally.js/issues/20 +// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-ismap +var focusImgIsmap = { + element: 'a', + mutate: function mutate(element) { + element.href = '#void' + element.innerHTML = '' + return element.querySelector('img') + }, +} + +// NOTE: https://github.com/medialize/ally.js/issues/35 +// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-usemap +var focusImgUsemapTabindex = { + element: 'div', + mutate: function mutate(element) { + element.innerHTML = + '' + + '' + + return element.querySelector('img') + }, +} + +var focusInHiddenIframe = { + element: function element(wrapper, _document) { + var iframe = _document.createElement('iframe') + + // iframe must be part of the DOM before accessing the contentWindow is possible + wrapper.appendChild(iframe) + + // create the iframe's default document () + var iframeDocument = iframe.contentWindow.document + iframeDocument.open() + iframeDocument.close() + return iframe + }, + mutate: function mutate(iframe) { + iframe.style.visibility = 'hidden' + + var iframeDocument = iframe.contentWindow.document + var input = iframeDocument.createElement('input') + iframeDocument.body.appendChild(input) + return input + }, + validate: function validate(iframe) { + var iframeDocument = iframe.contentWindow.document + var focus = iframeDocument.querySelector('input') + return iframeDocument.activeElement === focus + }, +} + +var result = !platform.is.WEBKIT + +function focusInZeroDimensionObject() { + return result +} + +// Firefox allows *any* value and treats invalid values like tabindex="-1" +// @browser-issue Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054 +var focusInvalidTabindex = { + element: 'div', + mutate: function mutate(element) { + element.setAttribute('tabindex', 'invalid-value') + }, +} + +var focusLabelTabindex = { + element: 'label', + mutate: function mutate(element) { + element.setAttribute('tabindex', '-1') + }, + validate: function validate(element, focusTarget, _document) { + // force layout in Chrome 49, otherwise the element won't be focusable + /* eslint-disable no-unused-vars */ + var variableToPreventDeadCodeElimination = element.offsetHeight + /* eslint-enable no-unused-vars */ + element.focus() + return _document.activeElement === element + }, +} + +var svg = + 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtb' + + 'G5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBpZD0ic3ZnIj48dGV4dCB4PSIxMCIgeT0iMjAiIGlkPSJ' + + 'zdmctbGluay10ZXh0Ij50ZXh0PC90ZXh0Pjwvc3ZnPg==' + +// Note: IE10 on BrowserStack does not like this test + +var focusObjectSvgHidden = { + element: 'object', + mutate: function mutate(element) { + element.setAttribute('type', 'image/svg+xml') + element.setAttribute('data', svg) + element.setAttribute('width', '200') + element.setAttribute('height', '50') + element.style.visibility = 'hidden' + }, +} + +// Note: IE10 on BrowserStack does not like this test + +var focusObjectSvg = { + name: 'can-focus-object-svg', + element: 'object', + mutate: function mutate(element) { + element.setAttribute('type', 'image/svg+xml') + element.setAttribute('data', svg) + element.setAttribute('width', '200') + element.setAttribute('height', '50') + }, + validate: function validate(element, focusTarget, _document) { + if (platform.is.GECKO) { + // Firefox seems to be handling the object creation asynchronously and thereby produces a false negative test result. + // Because we know Firefox is able to focus object elements referencing SVGs, we simply cheat by sniffing the user agent string + return true + } + + return _document.activeElement === element + }, +} + +// Every Environment except IE9 considers SWF objects focusable +var result$1 = !platform.is.IE9 + +function focusObjectSwf() { + return result$1 +} + +var focusRedirectImgUsemap = { + element: 'div', + mutate: function mutate(element) { + element.innerHTML = + '' + + '' + + // focus the , not the