1
0
mirror of synced 2026-02-07 12:00:13 -05:00

Compare commits

..

3 Commits
react18 ... r18

Author SHA1 Message Date
Brandon Bayer
353b2099ea bump 2021-06-11 13:29:55 -04:00
Brandon Bayer
d2dda69612 fix 2021-06-11 13:18:03 -04:00
Brandon Bayer
067d4f3f75 upgrade to react 18 2021-06-11 12:33:07 -04:00
3931 changed files with 97560 additions and 14593 deletions

View File

@@ -357,8 +357,7 @@
"contributions": [
"test",
"code",
"review",
"doc"
"review"
]
},
{
@@ -2412,8 +2411,7 @@
"avatar_url": "https://avatars.githubusercontent.com/u/1384885?v=4",
"profile": "www.usertrack.net",
"contributions": [
"doc",
"code"
"doc"
]
},
{
@@ -2743,9 +2741,7 @@
"avatar_url": "https://avatars.githubusercontent.com/u/6707308?v=4",
"profile": "https://github.com/swinner2",
"contributions": [
"code",
"test",
"doc"
"code"
]
},
{
@@ -2793,83 +2789,6 @@
"contributions": [
"code"
]
},
{
"login": "lksnmnn",
"name": "Lukas Neumann",
"avatar_url": "https://avatars.githubusercontent.com/u/4983285?v=4",
"profile": "lksnmnn.com",
"contributions": [
"doc",
"code",
"test"
]
},
{
"login": "dbachrach",
"name": "Dustin Bachrach",
"avatar_url": "https://avatars.githubusercontent.com/u/45016?v=4",
"profile": "dbachrach.com",
"contributions": [
"code",
"doc"
]
},
{
"login": "ashikka",
"name": "Ashikka Gupta",
"avatar_url": "https://avatars.githubusercontent.com/u/58368421?v=4",
"profile": "https://github.com/ashikka",
"contributions": [
"code",
"test"
]
},
{
"login": "deini",
"name": "Daniel Almaguer",
"avatar_url": "https://avatars.githubusercontent.com/u/2752665?v=4",
"profile": "https://github.com/deini",
"contributions": [
"doc"
]
},
{
"login": "igeligel",
"name": "Kevin Peters",
"avatar_url": "https://avatars.githubusercontent.com/u/12736734?v=4",
"profile": "https://www.kevinpeters.net/about/",
"contributions": [
"doc"
]
},
{
"login": "prisis",
"name": "Daniel Bannert",
"avatar_url": "https://avatars.githubusercontent.com/u/2716058?v=4",
"profile": "http://anolilab.de",
"contributions": [
"code"
]
},
{
"login": "benjakugler96",
"name": "Benja Kugler",
"avatar_url": "https://avatars.githubusercontent.com/u/53273645?v=4",
"profile": "https://benjakugler96.github.io/",
"contributions": [
"code"
]
},
{
"login": "esemeniuc",
"name": "Eric Semeniuc",
"avatar_url": "https://avatars.githubusercontent.com/u/3838856?v=4",
"profile": "https://semeniuc.ml/",
"contributions": [
"test",
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -29,14 +29,15 @@ eslint.config.*
/packages/cli/lib
/packages/babel-preset/src/fix-node-file-trace/tests/**
/test/integration/**/out/**
/nextjs/packages/create-next-app
// COPIED FROM nextjs/.eslintignore
/nextjs/**/.next/**
/nextjs/**/_next/**
/nextjs/**/dist/**
/nextjs/examples/**
/nextjs/examples/with-eslint/**
/nextjs/examples/with-typescript-eslint-jest/**
/nextjs/examples/with-kea/**
/nextjs/packages/next/bundles/webpack/packages/*.runtime.js
/nextjs/packages/next/compiled/**/*
/nextjs/packages/react-refresh-utils/**/*.js

View File

@@ -80,19 +80,6 @@ module.exports = {
"@typescript-eslint/no-floating-promises": "off",
},
},
{
files: ["examples/**"],
plugins: ["cypress"],
parserOptions: {
project: null,
},
env: {
"cypress/globals": true,
},
rules: {
"simple-import-sort/imports": "off",
},
},
{
files: ["packages/cli/src/commands/**/*"],
rules: {

View File

@@ -1,11 +1,11 @@
name: Size Check
name: CI
on:
pull_request:
branches: [master, canary]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.head_ref }}
cancel-in-progress: true
jobs:

View File

@@ -7,7 +7,7 @@ on:
types: [opened, synchronize]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.head_ref }}
cancel-in-progress: true
jobs:
@@ -30,9 +30,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v10-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
${{ runner.os }}-${{ runner.node_version}}-yarn-v10-
- name: Install dependencies
run: yarn install --frozen-lockfile --silent
env:
@@ -76,9 +76,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v10-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
${{ runner.os }}-${{ runner.node_version}}-yarn-v10-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
@@ -144,9 +144,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v10-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
${{ runner.os }}-${{ runner.node_version}}-yarn-v10-
- run: yarn install --frozen-lockfile --check-files
# - run: yarn cpy node_modules/.blitz packages/core/node_modules/.blitz
# if: matrix.os == 'windows-latest'
@@ -245,7 +245,7 @@ jobs:
strategy:
fail-fast: false
matrix:
group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
steps:
- run: echo ${{needs.build.outputs.docsChange}}
working-directory: ./
@@ -260,7 +260,7 @@ jobs:
- run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
- run: xvfb-run node run-tests.js --timings -g ${{ matrix.group }}/20 -c 3
- run: xvfb-run node run-tests.js --timings -g ${{ matrix.group }}/10 -c 3
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testElectron:
@@ -308,6 +308,95 @@ jobs:
steps:
- run: exit 0
testFutureDependencies:
name: Nextjs - Webpack 5 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
needs: build
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
NEXT_PRIVATE_TEST_WEBPACK5_MODE: 1
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ github.sha }}
- run: xvfb-run node run-tests.js test/integration/{fallback-modules,link-ref,production,basic,async-modules,font-optimization,ssr-ctx}/test/index.test.js test/acceptance/*.test.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
working-directory: nextjs
testLegacyReact:
name: Nextjs - React 16 + Webpack 4 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
NEXT_TEST_LEGACY_REACT: 1
HEADLESS: true
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 25
- run: echo ::set-output name=DOCS_CHANGE::$(node skip-docs-change.js echo 'not-docs-only-change')
id: docs-change
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: cat package.json | jq '.resolutions.react = "^16.14.0"' > package.json.tmp && mv package.json.tmp package.json
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: cat package.json | jq '.resolutions."react-dom" = "^16.14.0"' > package.json.tmp && mv package.json.tmp package.json
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- name: Use Node.js
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
uses: actions/setup-node@v2
with:
node-version: "14"
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- name: Get yarn cache directory path
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache node_modules
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
id: yarn-cache
uses: actions/cache@v2
with:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
/home/runner/.cache/Cypress
C:\Users\runneradmin\AppData\Local\Cypress\Cache
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v10-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v10-
- run: yarn install --check-files
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: yarn list react react-dom
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: yarn build:nextjs
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: xvfb-run node run-tests.js test/integration/{link-ref,production,basic,async-modules,font-optimization,ssr-ctx,worker-loader}/test/index.test.js test/acceptance/*.test.js
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
working-directory: nextjs
testFirefox:
name: Nextjs - Test Firefox (production)
defaults:
@@ -317,7 +406,7 @@ jobs:
needs: build
env:
HEADLESS: true
BROWSER_NAME: "firefox"
BROWSERNAME: "firefox"
NEXT_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
@@ -326,7 +415,7 @@ jobs:
with:
path: ./*
key: ${{ github.sha }}
- run: node run-tests.js -c 1 test/integration/production/test/index.test.js
- run: node run-tests.js test/integration/production/test/index.test.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testSafari:
@@ -338,7 +427,7 @@ jobs:
needs: build
env:
BROWSERSTACK: true
BROWSER_NAME: "safari"
BROWSERNAME: "safari"
NEXT_TELEMETRY_DISABLED: 1
SKIP_LOCAL_SELENIUM_SERVER: true
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
@@ -350,7 +439,7 @@ jobs:
with:
path: ./*
key: ${{ github.sha }}
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js -c 1 test/integration/production/test/index.test.js'
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js test/integration/production/test/index.test.js'
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testSafariOld:

1
.gitignore vendored
View File

@@ -30,4 +30,3 @@ examples/auth2
db.sqlite-journal
test/integration/**/db.json
test/**/*/out
.blitz**

View File

@@ -13,14 +13,10 @@
1. `git pull`
2. `git fetch --all`
3. `git merge v10.2.0` (change the version to be the version you are updating to)
4. Run `rm -rf examples && git add examples`
5. To resolve conflict with their version for a path, like docs, run this:
- `git checkout --theirs docs && git add docs`
6. Resolve all merge conflicts and complete merge
7. Run `yarn` and make sure all builds complete
8. Run `yarn lint` and fix any issues
9. `git push`
4. Resolve all merge conflicts and complete merge
5. `git push`
4. Run `yarn pull next-nextjs`
- If it fails, run `git subrepo clean nextjs` and try again
5. Run `yarn`
6. Run `yarn manypkg check` and optionally `yarn manypkg fix` to fix any issues
7. Under `nextjs/`, run `./check-pre-compiled.sh` and commit the changes
@@ -29,7 +25,4 @@
10. Run `yarn build` - fix any issues
11. Run `yarn test:nextjs-size` and update tests if there are any failures
12. Open PR and fix any failing tests
13. Update any references to nextjs in new code including imports like `next/image`, etc.
14. Any doc updates needed?
15. Merge PR
16. `yarn push-nextjs`
13. Any doc updates?

View File

@@ -6,7 +6,7 @@
<img alt="" src="https://img.shields.io/badge/Join%20our%20community-6700EB.svg?style=for-the-badge&labelColor=000000&logoWidth=20&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ9SURBVHgB7d3dVdtAEIbhcSpICUoH0IEogQqSVBBSAU4FSSpIOoAORAfQgSghHXzZ1U/YcMD4R9rZmf2ec3y448LyiNf27iLiGIAmPLrweC9Un3DhrzG6EarLNP09nlwJ1SOZ/lQr5N80/S/p2QMVCBf5N17XCfm1Y/rBHqjAG9PPHvBsz+mf9WAP+HLA9M/YA14cOP2payH7jpj+VCtk1wnTP+vj7xCy6cTpn7EHLMLp059iD1iD8eveJbVCNsSLheX1YA/YgOWnf8YeKB3Wmf7Ud6Fy4f/FHmtpxbl3YlC4MJ/Cj0bWdwPnPbARg+L0S54XQHS32WwuxClzd4CM0z9rPfeAuTtA5ulPXYQ7wZ04Y+oOoDD9KZc9YOoOoDj9s4dwFzgXR6w1wIPoOvPWA9buAHEJ173o3gWiy3AnuBUHLEbgmYwvAk1/wuM8vAgexThzbwPDkx7/DHwVXfFOxP2GmsKd4Ab6zPeAyU8CI7AHFmH2BRCBPXAyk18GzUrqAXCTiR4ssyj0VFw/oCU8+e+RZ33AWz6KMaYbIIWxB+JSLs1bsbkeMN0AqakHvoku9oA2sAfqBvbAQdw0QArsgb25aYBUQT3QgT2gB+yBuqGcHij2UCqXDZACe2Anlw2QYg/QAOyBuoE98CL3DZDCuK4/rh/Q7oGL6U+TOvcNkJoijN8X1C48+T+g75eQDrAH/qmqAVJgDwyqaoAUe4AGYA/UDZX3QLUNkEIZPRCd5+6BahsgVUgPROwBTSijB7jpVAvGHriHvmw9wAZ4BpX1ABvgmakHtPcbRuwBTWAPULgAV9D/jKDY9YRvwvgEaurD44uQHvAol7qBW7WKluVtIHiUS7GyvA0s6CiXDnxrpQfsgbqBS7GKk/2jYHCrVlGyfxTMrVo0ALdq1Q3sgSKofh0M9oA61a+D2QM0AHugbmAPqClmSRjK2apVVQ8UsySsoK1aHdgDesCtWnUDeyCrIpeFg1u3sylyWTi3btMA7IG6gT2wuuK3hoE9sKrit4YVslWLPaAN7IG6ocKt2zmY2h4O9sDiTG0PZw/QANy6XTewBxZj9ogYVHy025LMHhEz9cBn0We6B0yfERReBLfhx0/R1YQHPx/QBPbA0VwcEwf2wNFcHBPHHjiem3MC2QPHcXdSaJjA+KfgTPQ8hhfjBzHC40mhlzJ+Xq9lK4a4PCs43AVaGTed5mZq+iOXZwWHi3AnOj2wFWNcnxYe7gTxLtBKHuamP/J+Wnh8a5irB7ZC5Yk9gPX1QuXC+usHWqGyhYvUYR0a7zboUOFCNVhnk0krZAOW7wFOvzXhom2xnEbIHizTA1wEYhWW6YFGyC6c1gOcfg9wfA80Qj7g8B7g9HuCww+haIR8wf49wOn3Cvv9k8tGyC/s7gFOv3fY3QONkH+v9MBWqB7PeqDn9FcIT//kcitUn6kHOu/T/xfWzlQy3dEHhwAAAABJRU5ErkJggg==">
</a>
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-304-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-296-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<a aria-label="License" href="https://github.com/blitz-js/blitz/blob/canary/LICENSE">
<img alt="" src="https://img.shields.io/npm/l/blitz.svg?style=for-the-badge&labelColor=000000&color=blue">
@@ -288,7 +288,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://mikeattara.com"><img src="https://avatars1.githubusercontent.com/u/31483629?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike Perry Y Attara</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=mikeattara" title="Documentation">📖</a></td>
<td align="center"><a href="https://devanthe.dev"><img src="https://avatars0.githubusercontent.com/u/354652?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Devan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=DevanB" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/jclancy93"><img src="https://avatars2.githubusercontent.com/u/7850202?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jack Clancy</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jclancy93" title="Code">💻</a> <a href="#maintenance-jclancy93" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/ntgussoni"><img src="https://avatars0.githubusercontent.com/u/10161067?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nicolas Torres</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/pulls?q=is%3Apr+reviewed-by%3Antgussoni" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ntgussoni"><img src="https://avatars0.githubusercontent.com/u/10161067?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nicolas Torres</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/pulls?q=is%3Apr+reviewed-by%3Antgussoni" title="Reviewed Pull Requests">👀</a></td>
</tr>
<tr>
<td align="center"><a href="http://simonknott.de"><img src="https://avatars1.githubusercontent.com/u/14912729?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Simon Knott</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Skn0tt" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Skn0tt" title="Tests">⚠️</a> <a href="#maintenance-Skn0tt" title="Maintenance">🚧</a> <a href="https://github.com/blitz-js/blitz/commits?author=Skn0tt" title="Documentation">📖</a></td>
@@ -572,7 +572,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<tr>
<td align="center"><a href="jahred.com.au"><img src="https://avatars.githubusercontent.com/u/13903378?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jahred Hope</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jahredhope" title="Documentation">📖</a></td>
<td align="center"><a href="simonelnahas.github.io/"><img src="https://avatars.githubusercontent.com/u/29279201?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Simon El Nahas</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=simonelnahas" title="Documentation">📖</a></td>
<td align="center"><a href="www.usertrack.net"><img src="https://avatars.githubusercontent.com/u/1384885?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Buleandra Cristian</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Cristy94" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Cristy94" title="Code">💻</a></td>
<td align="center"><a href="www.usertrack.net"><img src="https://avatars.githubusercontent.com/u/1384885?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Buleandra Cristian</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Cristy94" title="Documentation">📖</a></td>
<td align="center"><a href="http://palauisaac.me/"><img src="https://avatars.githubusercontent.com/u/12257885?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pedro Enrique Palau Isaac</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=peterpalau" title="Code">💻</a></td>
<td align="center"><a href="www.seanbrydon.me"><img src="https://avatars.githubusercontent.com/u/55134778?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sean-brydon</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sean-brydon" title="Documentation">📖</a></td>
<td align="center"><a href="buonerba.dev"><img src="https://avatars.githubusercontent.com/u/28837891?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alessandro</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Dieman89" title="Documentation">📖</a></td>
@@ -618,7 +618,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://github.com/timbooker"><img src="https://avatars.githubusercontent.com/u/612681?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=timbooker" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=timbooker" title="Tests">⚠️</a></td>
<td align="center"><a href="http://orlowski.me/"><img src="https://avatars.githubusercontent.com/u/16357457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marek Orłowski</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ormarek" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/AntoineGuestin"><img src="https://avatars.githubusercontent.com/u/70888750?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Antoine G</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=AntoineGuestin" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/swinner2"><img src="https://avatars.githubusercontent.com/u/6707308?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sean Winner</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=swinner2" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=swinner2" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=swinner2" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/swinner2"><img src="https://avatars.githubusercontent.com/u/6707308?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sean Winner</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=swinner2" title="Code">💻</a></td>
<td align="center"><a href="https://usman-s.me"><img src="https://avatars.githubusercontent.com/u/51731966?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Max Programming</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=max-programming" title="Code">💻</a></td>
<td align="center"><a href="https://makemake.sh"><img src="https://avatars.githubusercontent.com/u/353768?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sebastian Hoitz</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sebastianhoitz" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=sebastianhoitz" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/garnerp"><img src="https://avatars.githubusercontent.com/u/737307?v=4?s=100" width="100px;" alt=""/><br /><sub><b>garnerp</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=garnerp" title="Documentation">📖</a></td>
@@ -626,16 +626,6 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<tr>
<td align="center"><a href="https://github.com/kivi"><img src="https://avatars.githubusercontent.com/u/366163?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kivi</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kivi" title="Code">💻</a></td>
<td align="center"><a href="http://dangreaves.com"><img src="https://avatars.githubusercontent.com/u/1036142?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dan Greaves</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dangreaves" title="Code">💻</a></td>
<td align="center"><a href="lksnmnn.com"><img src="https://avatars.githubusercontent.com/u/4983285?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lukas Neumann</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=lksnmnn" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=lksnmnn" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=lksnmnn" title="Tests">⚠️</a></td>
<td align="center"><a href="dbachrach.com"><img src="https://avatars.githubusercontent.com/u/45016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dustin Bachrach</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dbachrach" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=dbachrach" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ashikka"><img src="https://avatars.githubusercontent.com/u/58368421?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ashikka Gupta</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ashikka" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=ashikka" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/deini"><img src="https://avatars.githubusercontent.com/u/2752665?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Almaguer</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=deini" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.kevinpeters.net/about/"><img src="https://avatars.githubusercontent.com/u/12736734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Peters</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=igeligel" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="http://anolilab.de"><img src="https://avatars.githubusercontent.com/u/2716058?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Bannert</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=prisis" title="Code">💻</a></td>
<td align="center"><a href="https://benjakugler96.github.io/"><img src="https://avatars.githubusercontent.com/u/53273645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benja Kugler</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=benjakugler96" title="Code">💻</a></td>
<td align="center"><a href="https://semeniuc.ml/"><img src="https://avatars.githubusercontent.com/u/3838856?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eric Semeniuc</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=esemeniuc" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=esemeniuc" title="Code">💻</a></td>
</tr>
</table>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,7 +1,6 @@
import React, {ReactNode, PropsWithoutRef} from "react"
import {Form as FinalForm, FormProps as FinalFormProps} from "react-final-form"
import {z} from "zod"
import {validateZodSchema} from "blitz"
export {FORM_ERROR} from "final-form"
export interface FormProps<S extends z.ZodType<any, any>>
@@ -26,7 +25,14 @@ export function Form<S extends z.ZodType<any, any>>({
return (
<FinalForm
initialValues={initialValues}
validate={validateZodSchema(schema)}
validate={(values) => {
if (!schema) return
try {
schema.parse(values)
} catch (error) {
return error.formErrors.fieldErrors
}
}}
onSubmit={onSubmit}
render={({handleSubmit, submitting, submitError}) => (
<form onSubmit={handleSubmit} className="form" {...props}>

View File

@@ -1,22 +1,28 @@
import {
AppProps,
ErrorBoundary,
ErrorComponent,
useRouter,
AuthenticationError,
AuthorizationError,
ErrorFallbackProps,
useQueryErrorResetBoundary,
} from "blitz"
import {ErrorBoundary} from "react-error-boundary"
import LoginForm from "app/auth/components/LoginForm"
import {ReactQueryDevtools} from "react-query/devtools"
export default function App({Component, pageProps}: AppProps) {
const getLayout = Component.getLayout || ((page) => page)
const router = useRouter()
const {reset} = useQueryErrorResetBoundary()
return (
<>
<ErrorBoundary FallbackComponent={RootErrorFallback} onReset={reset}>
<ErrorBoundary
FallbackComponent={RootErrorFallback}
resetKeys={[router.asPath]}
onReset={reset}
>
{getLayout(<Component {...pageProps} />)}
</ErrorBoundary>
<ReactQueryDevtools />

View File

@@ -10,14 +10,7 @@ import {Routes} from ".blitz"
export const EditProject = () => {
const router = useRouter()
const projectId = useParam("projectId", "number")
const [project, {setQueryData}] = useQuery(
getProject,
{id: projectId},
{
// This ensures the query never refreshes and overwrites the form data while the user is editing.
staleTime: Infinity,
},
)
const [project, {setQueryData}] = useQuery(getProject, {id: projectId})
const [updateProjectMutation] = useMutation(updateProject)
return (

View File

@@ -23,7 +23,7 @@ const NewProjectPage: BlitzPage = () => {
onSubmit={async (values) => {
try {
const project = await createProjectMutation(values)
router.push(Routes.ShowProjectPage({projectId: project.id}))
router.push(`/projects/${project.id}`)
} catch (error) {
console.error(error)
return {

View File

@@ -12,8 +12,16 @@ import {
} from "blitz"
import getUser from "app/users/queries/getUser"
import logout from "app/auth/mutations/logout"
import path from "path"
export const getServerSideProps: GetServerSideProps = async ({req, res}) => {
// Ensure these files are not eliminated by trace-based tree-shaking (like Vercel)
// https://github.com/blitz-js/blitz/issues/794
path.resolve("next.config.js")
path.resolve("blitz.config.js")
path.resolve(".next/blitz/db.js")
// End anti-tree-shaking
const session = await getSession(req, res)
console.log("Session id:", session.userId)
try {

View File

@@ -29,15 +29,17 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.38.3-canary.1",
"blitz": "0.37.0",
"final-form": "4.20.1",
"passport-auth0": "1.4.0",
"passport-github2": "0.1.12",
"passport-twitter": "1.0.4",
"prisma": "2.24.1",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
"react": "18.0.0-alpha-01be61c12",
"react-dom": "18.0.0-alpha-01be61c12",
"react-error-boundary": "3.1.1",
"react-final-form": "6.5.2",
"zod": "3.0.2"
},
"devDependencies": {
"@cypress/skip-test": "2.6.0",
@@ -48,7 +50,7 @@
"@types/passport-github2": "1.2.4",
"@types/passport-twitter": "1.0.36",
"@types/preview-email": "2.0.0",
"@types/react": "17.0.13",
"@types/react": "17.0.2",
"cross-env": "7.0.3",
"cypress": "6.2.1",
"eslint": "7.21.0",
@@ -57,7 +59,8 @@
"prettier": "2.2.1",
"pretty-quick": "3.1.0",
"preview-email": "3.0.3",
"start-server-and-test": "1.11.7"
"start-server-and-test": "1.11.7",
"typescript": "4.1.5"
},
"private": true
}

View File

@@ -1,7 +1,6 @@
import React, {ReactNode, PropsWithoutRef} from "react"
import {Form as FinalForm, FormProps as FinalFormProps} from "react-final-form"
import {z} from "zod"
import {validateZodSchema} from "blitz"
export {FORM_ERROR} from "final-form"
type FormProps<S extends z.ZodType<any, any>> = {
@@ -25,7 +24,14 @@ export function Form<S extends z.ZodType<any, any>>({
return (
<FinalForm
initialValues={initialValues}
validate={validateZodSchema(schema)}
validate={(values) => {
if (!schema) return
try {
schema.parse(values)
} catch (error) {
return error.formErrors.fieldErrors
}
}}
onSubmit={onSubmit}
render={({handleSubmit, submitting, submitError}) => (
<form onSubmit={handleSubmit} className="form" {...props}>

View File

@@ -1,26 +1,31 @@
import {
AppProps,
ErrorBoundary,
ErrorFallbackProps,
ErrorComponent,
useRouter,
AuthenticationError,
AuthorizationError,
useQueryErrorResetBoundary,
} from "blitz"
import {ErrorBoundary, FallbackProps} from "react-error-boundary"
import LoginForm from "app/auth/components/LoginForm"
export default function App({Component, pageProps}: AppProps) {
const getLayout = Component.getLayout || ((page) => page)
const router = useRouter()
const {reset} = useQueryErrorResetBoundary()
return (
<ErrorBoundary FallbackComponent={RootErrorFallback} onReset={reset}>
<ErrorBoundary
FallbackComponent={RootErrorFallback}
resetKeys={[router.asPath]}
onReset={reset}
>
{getLayout(<Component {...pageProps} />)}
</ErrorBoundary>
)
}
function RootErrorFallback({error, resetErrorBoundary}: ErrorFallbackProps) {
function RootErrorFallback({error, resetErrorBoundary}: FallbackProps) {
if (error instanceof AuthenticationError) {
return <LoginForm onSuccess={resetErrorBoundary} />
} else if (error instanceof AuthorizationError) {

View File

@@ -31,19 +31,22 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.38.3-canary.1",
"blitz": "0.37.0",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react": "18.0.0-alpha-01be61c12",
"react-dom": "18.0.0-alpha-01be61c12",
"react-error-boundary": "3.1.1",
"react-final-form": "6.5.2",
"secure-password": "4.0.0"
"secure-password": "4.0.0",
"typescript": "4.1.5",
"zod": "3.0.2"
},
"devDependencies": {
"@cypress/skip-test": "2.6.0",
"@testing-library/react": "11.2.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/react": "17.0.13",
"@types/react": "17.0.2",
"@types/secure-password": "3.1.0",
"cypress": "6.2.1",
"eslint": "7.21.0",

View File

@@ -1,7 +1,6 @@
import { ReactNode, PropsWithoutRef } from "react"
import { Form as FinalForm, FormProps as FinalFormProps } from "react-final-form"
import { z } from "zod"
import { validateZodSchema } from "blitz"
export { FORM_ERROR } from "final-form"
type FormProps<S extends z.ZodType<any, any>> = {
@@ -25,7 +24,14 @@ export function Form<S extends z.ZodType<any, any>>({
return (
<FinalForm
initialValues={initialValues}
validate={validateZodSchema(schema)}
validate={(values) => {
if (!schema) return
try {
schema.parse(values)
} catch (error) {
return error.formErrors.fieldErrors
}
}}
onSubmit={onSubmit}
render={({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit} className="form" {...props}>

View File

@@ -1,24 +1,24 @@
import {
AppProps,
ErrorBoundary,
ErrorFallbackProps,
ErrorComponent,
useQueryErrorResetBoundary,
} from "blitz"
import { AppProps, ErrorComponent, useRouter, useQueryErrorResetBoundary } from "blitz"
import { ErrorBoundary, FallbackProps } from "react-error-boundary"
import LoginForm from "app/auth/components/LoginForm"
export default function App({ Component, pageProps }: AppProps) {
const getLayout = Component.getLayout || ((page) => page)
const router = useRouter()
const { reset } = useQueryErrorResetBoundary()
return (
<ErrorBoundary FallbackComponent={RootErrorFallback} onReset={reset}>
<ErrorBoundary
FallbackComponent={RootErrorFallback}
resetKeys={[router.asPath]}
onReset={reset}
>
{getLayout(<Component {...pageProps} />)}
</ErrorBoundary>
)
}
function RootErrorFallback({ error, resetErrorBoundary }: ErrorFallbackProps) {
function RootErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
if (error?.name === "AuthenticationError") {
return <LoginForm onSuccess={resetErrorBoundary} />
} else if (error?.name === "AuthorizationError") {

View File

@@ -28,29 +28,33 @@
]
},
"dependencies": {
"blitz": "0.38.3-canary.1",
"blitz": "0.37.0",
"final-form": "4.20.1",
"graphql": "15.5.0",
"graphql-request": "3.4.0",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
"react": "18.0.0-alpha-01be61c12",
"react-dom": "18.0.0-alpha-01be61c12",
"react-error-boundary": "3.1.1",
"react-final-form": "6.5.2",
"secure-password": "4.0.0",
"zod": "3.0.2"
},
"devDependencies": {
"@testing-library/react": "11.2.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/react": "17.0.13",
"@types/react": "17.0.2",
"@types/secure-password": "3.1.0",
"babel-eslint": "~10.1.0",
"eslint": "7.21.0",
"eslint-config-react-app": "~6.0.0",
"eslint-plugin-flowtype": "~5.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-jsx-a11y": "~6.4.1",
"eslint-plugin-react": "^7.23.1",
"eslint-plugin-react-hooks": "^4.2.0",
"husky": "5.1.2",
"start-server-and-test": "1.11.7"
"start-server-and-test": "1.11.7",
"typescript": "4.1.5"
},
"private": true
}

View File

@@ -26,26 +26,27 @@
]
},
"dependencies": {
"blitz": "0.38.3-canary.1",
"blitz": "0.37.0",
"knex": "0.21.16",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react": "18.0.0-alpha-01be61c12",
"react-dom": "18.0.0-alpha-01be61c12",
"sqlite3": "5.0.2"
},
"devDependencies": {
"@types/react": "17.0.13",
"@types/react": "17.0.2",
"babel-eslint": "~10.1.0",
"eslint": "7.21.0",
"eslint-config-react-app": "~6.0.0",
"eslint-plugin-flowtype": "~5.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-jsx-a11y": "~6.4.1",
"eslint-plugin-react": "^7.23.1",
"eslint-plugin-react-hooks": "^4.2.0",
"husky": "5.1.2",
"lint-staged": "10.5.4",
"prettier": "2.2.1",
"pretty-quick": "3.1.0"
"pretty-quick": "3.1.0",
"typescript": "4.1.5"
},
"private": true
}

View File

@@ -33,10 +33,10 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.38.3-canary.1",
"blitz": "0.37.0",
"prisma": "2.24.1",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701"
"react": "18.0.0-alpha-01be61c12",
"react-dom": "18.0.0-alpha-01be61c12"
},
"devDependencies": {
"babel-eslint": "~10.1.0",
@@ -44,13 +44,14 @@
"eslint-config-react-app": "~6.0.0",
"eslint-plugin-flowtype": "~5.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-jsx-a11y": "~6.4.1",
"eslint-plugin-react": "^7.23.1",
"eslint-plugin-react-hooks": "^4.2.0",
"husky": "5.1.2",
"lint-staged": "10.5.4",
"prettier": "2.2.1",
"pretty-quick": "3.1.0"
"pretty-quick": "3.1.0",
"typescript": "4.1.5"
},
"private": true
}

View File

@@ -1,17 +1,23 @@
import {
AppProps,
ErrorBoundary,
ErrorComponent,
useRouter,
ErrorFallbackProps,
useQueryErrorResetBoundary,
} from "blitz"
import { ErrorBoundary } from "react-error-boundary"
export default function App({ Component, pageProps }: AppProps) {
const getLayout = Component.getLayout || ((page) => page)
const router = useRouter()
const { reset } = useQueryErrorResetBoundary()
return (
<ErrorBoundary FallbackComponent={RootErrorFallback} onReset={reset}>
<ErrorBoundary
FallbackComponent={RootErrorFallback}
resetKeys={[router.asPath]}
onReset={reset}
>
{getLayout(<Component {...pageProps} />)}
</ErrorBoundary>
)

View File

@@ -33,16 +33,19 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.38.3-canary.1",
"blitz": "0.37.0",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
"react": "18.0.0-alpha-01be61c12",
"react-dom": "18.0.0-alpha-01be61c12",
"react-error-boundary": "3.1.1",
"react-final-form": "6.5.2",
"typescript": "4.1.5",
"zod": "3.0.2"
},
"devDependencies": {
"@types/preview-email": "2.0.0",
"@types/react": "17.0.13",
"@types/react": "17.0.2",
"eslint": "7.21.0",
"husky": "5.1.2",
"lint-staged": "10.5.4",

View File

@@ -0,0 +1,3 @@
module.exports = {
extends: ["blitz"],
}

View File

@@ -1,4 +1,5 @@
import {AppProps, ErrorBoundary, ErrorComponent, useQueryErrorResetBoundary} from "blitz"
import {AppProps, ErrorComponent, useQueryErrorResetBoundary} from "blitz"
import {ErrorBoundary} from "react-error-boundary"
if (typeof window !== "undefined") {
window["DEBUG_BLITZ"] = 1

View File

@@ -21,16 +21,19 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.38.3-canary.1",
"blitz": "0.37.0",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
"react": "18.0.0-alpha-01be61c12",
"react-dom": "18.0.0-alpha-01be61c12",
"react-error-boundary": "3.1.1",
"react-final-form": "6.5.2",
"typescript": "4.1.5"
},
"devDependencies": {
"@types/react": "17.0.13",
"@types/react": "17.0.2",
"cypress": "6.2.1",
"eslint-plugin-cypress": "~2.11.2",
"start-server-and-test": "1.11.7"
}
}

View File

@@ -1,5 +1,5 @@
{
"version": "0.38.3-canary.1",
"version": "0.37.0",
"packages": ["packages/*"],
"npmClient": "yarn",
"useWorkspaces": true,

View File

@@ -1,4 +0,0 @@
CODE_OF_CONDUCT.md
docs/
errors/
examples/

View File

@@ -1,8 +1,8 @@
FROM node:14-buster
FROM node:10-buster
LABEL com.github.actions.name="Next.js PR Stats"
LABEL com.github.actions.description="Compares stats of a PR with the main branch"
LABEL repository="https://github.com/vercel/next-stats-action"
LABEL repository="https://github.com/zeit/next-stats-action"
COPY . /next-stats

View File

@@ -156,15 +156,15 @@ jobs:
steps:
- run: exit 0
testLegacyWebpack:
name: Webpack 4 (Basic, Production, Acceptance)
testFutureDependencies:
name: Webpack 5 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
needs: build
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
NEXT_PRIVATE_TEST_WEBPACK4_MODE: 1
NEXT_PRIVATE_TEST_WEBPACK5_MODE: 1
steps:
- uses: actions/cache@v2
@@ -174,16 +174,50 @@ jobs:
path: ./*
key: ${{ github.sha }}
- run: xvfb-run node run-tests.js test/integration/{basic,fallback-modules,link-ref,production,async-modules,font-optimization,ssr-ctx}/test/index.test.js test/acceptance/*.test.js
- run: xvfb-run node run-tests.js test/integration/{fallback-modules,link-ref,production,basic,async-modules,font-optimization,ssr-ctx}/test/index.test.js test/acceptance/*.test.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testLegacyReact:
name: React 16 + Webpack 4 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 25
- run: echo ::set-output name=DOCS_CHANGE::$(node skip-docs-change.js echo 'not-docs-only-change')
id: docs-change
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: cat package.json | jq '.resolutions.react = "^16.14.0"' > package.json.tmp && mv package.json.tmp package.json
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: cat package.json | jq '.resolutions."react-dom" = "^16.14.0"' > package.json.tmp && mv package.json.tmp package.json
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: yarn install --check-files
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: yarn list react react-dom
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- run: xvfb-run node run-tests.js test/integration/{link-ref,production,basic,async-modules,font-optimization,ssr-ctx,worker-loader}/test/index.test.js test/acceptance/*.test.js
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
testFirefox:
name: Test Firefox (production)
runs-on: ubuntu-latest
needs: build
env:
HEADLESS: true
BROWSER_NAME: 'firefox'
BROWSERNAME: 'firefox'
NEXT_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
@@ -192,7 +226,7 @@ jobs:
with:
path: ./*
key: ${{ github.sha }}
- run: node run-tests.js -c 1 test/integration/production/test/index.test.js
- run: node run-tests.js test/integration/production/test/index.test.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testSafari:
@@ -201,7 +235,7 @@ jobs:
needs: build
env:
BROWSERSTACK: true
BROWSER_NAME: 'safari'
BROWSERNAME: 'safari'
NEXT_TELEMETRY_DISABLED: 1
SKIP_LOCAL_SELENIUM_SERVER: true
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
@@ -213,7 +247,7 @@ jobs:
with:
path: ./*
key: ${{ github.sha }}
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js -c 1 test/integration/production/test/index.test.js'
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js test/integration/production/test/index.test.js'
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testSafariOld:
@@ -223,7 +257,7 @@ jobs:
env:
BROWSERSTACK: true
LEGACY_SAFARI: true
BROWSER_NAME: 'safari'
BROWSERNAME: 'safari'
NEXT_TELEMETRY_DISABLED: 1
SKIP_LOCAL_SELENIUM_SERVER: true
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
@@ -235,7 +269,7 @@ jobs:
with:
path: ./*
key: ${{ github.sha }}
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js -c 1 test/integration/production-nav/test/index.test.js'
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js test/integration/production-nav/test/index.test.js'
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
publishRelease:

View File

@@ -26,7 +26,6 @@ jobs:
NEXT_TELEMETRY_DISABLED: 1
HEADLESS: true
NEXT_PRIVATE_SKIP_SIZE_TESTS: true
NEXT_PRIVATE_REACT_ROOT: 1
strategy:
fail-fast: false
matrix:

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = git@github.com:blitz-js/next.js.git
branch = canary
commit = 4be32b7a54fa68dfcf66d4a5cc7744409c409c7f
parent = 194a3720ce56aa3fabace4b07c5faeac1121b8d6
commit = 9d5938e8f444bfd2bb5e6cb69f48a868386a9e05
parent = c5b461c641f1764f8ba71f1e4d7c5cca0b405a28
method = merge
cmdver = 0.4.3

View File

@@ -117,13 +117,13 @@ stages:
vmImage: 'windows-2019'
strategy:
matrix:
nodejs-1:
node-10-1:
group: 1/4
nodejs-2:
node-10-2:
group: 2/4
nodejs-3:
node-10-3:
group: 3/4
nodejs-4:
node-10-4:
group: 4/4
steps:
- checkout: none

View File

@@ -1,5 +1,5 @@
import { createServer } from 'http'
import { writeFileSync } from 'fs'
const http = require('http')
const fs = require('fs')
const PORT = 9411
const HOST = '0.0.0.0'
@@ -53,11 +53,11 @@ const main = () => {
process.on('SIGINT', () => {
console.log(`\nSaving to ${outFile}...`)
writeFileSync(outFile, JSON.stringify(traces, null, 2))
fs.writeFileSync(outFile, JSON.stringify(traces, null, 2))
process.exit()
})
const server = createServer(onRequest)
const server = http.createServer(onRequest)
server.listen(PORT, HOST, onReady)
}

View File

@@ -8,7 +8,7 @@
"bench:recursive-copy": "node recursive-copy/run"
},
"dependencies": {
"fs-extra": "10.0.0",
"recursive-copy": "2.0.11"
"fs-extra": "7.0.1",
"recursive-copy": "2.0.10"
}
}

View File

@@ -1,7 +1,6 @@
import { join } from 'path'
import { promisify } from 'util'
import globMod from 'glob'
const { join } = require('path')
const { promisify } = require('util')
const globMod = require('glob')
const glob = promisify(globMod)
const resolveDataDir = join(__dirname, 'fixtures', '**/*')

View File

@@ -1,5 +1,5 @@
import { join } from 'path'
import { recursiveReadDir } from 'next/dist/lib/recursive-readdir'
const { join } = require('path')
const { recursiveReadDir } = require('next/dist/lib/recursive-readdir')
const resolveDataDir = join(__dirname, 'fixtures')
async function test() {

View File

@@ -1,14 +1,18 @@
import { join } from 'path'
import { ensureDir, outputFile, remove } from 'fs-extra'
import recursiveCopyNpm from 'recursive-copy'
import { recursiveCopy as recursiveCopyCustom } from 'next/dist/lib/recursive-copy'
const { join } = require('path')
const fs = require('fs-extra')
const recursiveCopyNpm = require('recursive-copy')
const {
recursiveCopy: recursiveCopyCustom,
} = require('next/dist/lib/recursive-copy')
const fixturesDir = join(__dirname, 'fixtures')
const srcDir = join(fixturesDir, 'src')
const destDir = join(fixturesDir, 'dest')
const createSrcFolder = async () => {
await ensureDir(srcDir)
await fs.ensureDir(srcDir)
const files = new Array(100)
.fill(undefined)
@@ -16,7 +20,7 @@ const createSrcFolder = async () => {
join(srcDir, `folder${i % 5}`, `folder${i + (1 % 5)}`, `file${i}`)
)
await Promise.all(files.map((file) => outputFile(file, 'hello')))
await Promise.all(files.map((file) => fs.outputFile(file, 'hello')))
}
async function run(fn) {
@@ -34,7 +38,7 @@ async function run(fn) {
for (let i = 0; i < 10; i++) {
const t = await test()
await remove(destDir)
await fs.remove(destDir)
ts.push(t)
}
@@ -53,7 +57,7 @@ async function main() {
console.log('test recursive-copy custom implementation')
await run(recursiveCopyCustom)
await remove(fixturesDir)
await fs.remove(fixturesDir)
}
main()

View File

@@ -1,5 +1,5 @@
import { join } from 'path'
import { recursiveDelete } from 'next/dist/lib/recursive-delete'
const { join } = require('path')
const { recursiveDelete } = require('next/dist/lib/recursive-delete')
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`)
async function test() {

View File

@@ -1,9 +1,8 @@
import { join } from 'path'
import { promisify } from 'util'
import rimrafMod from 'rimraf'
const rimraf = promisify(rimrafMod)
const { join } = require('path')
const { promisify } = require('util')
const rimrafMod = require('rimraf')
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`, '**/*')
const rimraf = promisify(rimrafMod)
async function test() {
const time = process.hrtime()

View File

@@ -1,6 +1,6 @@
# Contributing to Next.js
Read about our [Commitment to Open Source](https://vercel.com/oss).
Our Commitment to Open Source can be found [here](https://vercel.com/oss).
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device.
2. Create a new branch: `git checkout -b MY_BRANCH_NAME`
@@ -46,7 +46,7 @@ Running a specific test suite inside of the `test/integration` directory:
yarn testonly --testPathPattern "production"
```
Running one test in the `production` test suite:
Running just one test in the `production` test suite:
```sh
yarn testonly --testPathPattern "production" -t "should allow etag header support"
@@ -124,19 +124,12 @@ When you add an example to the [examples](examples) directory, dont forget to
- To add additional installation instructions, please add it where appropriate.
- To add additional notes, add `## Notes` section at the end.
- Remove the `Deploy your own` section if your example cant be immediately deployed to Vercel.
- Remove the `Preview` section if the example doesn't work on [StackBlitz](http://stackblitz.com/) and file an issue [here](https://github.com/stackblitz/webcontainer-core).
````markdown
# Example Name
Description
## Preview
Preview the example live on [StackBlitz](http://stackblitz.com/):
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/DIRECTORY_NAME)
## Deploy your own
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):

View File

@@ -6,4 +6,4 @@ description: Using AMP with TypeScript? Extend your typings to allow AMP compone
AMP currently doesn't have built-in types for TypeScript, but it's in their roadmap ([#13791](https://github.com/ampproject/amphtml/issues/13791)).
As a workaround you can manually create a file called `amp.d.ts` inside your project and add these [custom types](https://stackoverflow.com/a/50601125).
As a workaround you can manually create a file called `amp.d.ts` inside your project and add the custom types described [here](https://stackoverflow.com/a/50601125).

View File

@@ -17,14 +17,6 @@ Codemods are transformations that run on your codebase programmatically. This al
- `--dry` Do a dry-run, no code will be edited
- `--print` Prints the changed output for comparison
## Next.js 11
### `cra-to-next` (experimental)
Migrates a Create React App project to Next.js; creating a pages directory and necessary config to match behavior. Client-side only rendering is leveraged initially to prevent breaking compatibility due to `window` usage during SSR and can be enabled seamlessly to allow gradual adoption of Next.js specific features.
Please share any feedback related to this transform [in this discussion](https://github.com/vercel/next.js/discussions/25858).
## Next.js 10
### `add-missing-react-import`

View File

@@ -52,9 +52,6 @@ module.exports = {
{
domain: 'example.fr',
defaultLocale: 'fr',
// an optional http field can also be used to test
// locale domains locally with http instead of https
http: true,
},
],
},

View File

@@ -175,7 +175,7 @@ export function reportWebVitals(metric) {
> }
> ```
>
> Read more about [sending results to Google Analytics](https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics).
> Read more about sending results to Google Analytics [here](https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics).
## TypeScript

View File

@@ -1,139 +0,0 @@
---
description: Improve the security of your Next.js application by adding HTTP response headers.
---
# Security Headers
To improve the security of your application, you can use [`headers`](/docs/api-reference/next.config.js/headers.md) in `next.config.js` to apply HTTP response headers to all routes in your application.
```jsx
// next.config.js
// You can choose which headers to add to the list
// after learning more below.
const securityHeaders = []
module.exports = {
async headers() {
return [
{
// Apply these headers to all routes in your application.
source: '/(.*)',
headers: securityHeaders,
},
]
},
}
```
## Options
### [X-DNS-Prefetch-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control)
This header controls DNS prefetching, allowing browsers to proactively perform domain name resolution on external links, images, CSS, JavaScript, and more. This prefetching is performed in the background, so the [DNS](https://developer.mozilla.org/en-US/docs/Glossary/DNS) is more likely to be resolved by the time the referenced items are needed. This reduces latency when the user clicks a link.
```jsx
{
key: 'X-DNS-Prefetch-Control',
value: 'on'
}
```
### [Strict-Transport-Security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)
This header informs browsers it should only be accessed using HTTPS, instead of using HTTP. Using the configuration below, all present and future subdomains will use HTTPS for a `max-age` of 2 years. This blocks access to pages or subdomains that can only be served over HTTP.
If you're deploying to [Vercel](https://vercel.com/docs/edge-network/headers#strict-transport-security), this header is not necessary as it's automatically added to all deployments.
```jsx
{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains; preload'
}
```
### [X-XSS-Protection](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)
This header stops pages from loading when they detect reflected cross-site scripting (XSS) attacks. Although this protection is not necessary when sites implement a strong [`Content-Security-Policy`](#content-security-policy) disabling the use of inline JavaScript (`'unsafe-inline'`), it can still provide protection for older web browsers that don't support CSP.
```jsx
{
key: 'X-XSS-Protection',
value: '1; mode=block'
}
```
### [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)
This header indicates whether the site should be allowed to be displayed within an `iframe`. This can prevent against clickjacking attacks. This header has been superseded by CSP's `frame-ancestors` option, which has better support in modern browsers.
```jsx
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN'
}
```
### [Permissions-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy)
This header allows you to control which features and APIs can be used in the browser. It was previously named `Feature-Policy`. You can view the full list of permission options [here](https://www.w3.org/TR/permissions-policy-1/).
```jsx
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()'
}
```
### [X-Content-Type-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)
This header prevents the browser from attempting to guess the type of content if the `Content-Type` header is not explicitly set. This can prevent XSS exploits for websites that allow users to upload and share files. For example, a user trying to download an image, but having it treated as a different `Content-Type` like an executable, which could be malicious. This header also applies to downloading browser extensions. The only valid value for this header is `nosniff`.
```jsx
{
key: 'X-Content-Type-Options',
value: 'nosniff'
}
```
### [Referrer-Policy](https://scotthelme.co.uk/a-new-security-header-referrer-policy/)
This header controls how much information the browser includes when navigating from the current website (origin) to another. You can read about the different options [here](https://scotthelme.co.uk/a-new-security-header-referrer-policy/).
```jsx
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin'
}
```
### [Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
This header helps prevent cross-site scripting (XSS), clickjacking and other code injection attacks. Content Security Policy (CSP) can specify allowed origins for content including scripts, stylesheets, images, fonts, objects, media (audio, video), iframes, and more.
You can read about the many different CSP options [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
```jsx
{
key: 'Content-Security-Policy',
value: // Your CSP Policy
}
```
### References
- [MDN](https://developer.mozilla.org)
- [Varun Naik](https://blog.vnaik.com/posts/web-attacks.html)
- [Scott Helme](https://scotthelme.co.uk)
- [Mozilla Observatory](https://observatory.mozilla.org/)
## Related
For more information, we recommend the following sections:
<div class="card">
<a href="/docs/api-reference/next.config.js/headers.md">
<b>Headers:</b>
<small>Add custom HTTP headers to your Next.js app.</small>
</a>
</div>

View File

@@ -21,7 +21,7 @@ Usage
$ next <command>
Available commands
build, start, export, dev, lint, telemetry
build, start, export, dev, telemetry
Options
--version, -v Version number
@@ -74,20 +74,6 @@ The application will start at `http://localhost:3000` by default. The default po
npx next dev -p 4000
```
Or using the `PORT` environment variable:
```bash
PORT=4000 npx next dev
```
> Note: `PORT` can not be set in `.env` as booting up the HTTP server happens before any other code is initialized.
You can also set the hostname to be different from the default of `0.0.0.0`, this can be useful for making the application available for other devices on the network. The default hostname can be changed with `-H`, like so:
```bash
npx next dev -H 192.168.1.2
```
## Production
`next start` starts the application in production mode. The application should be compiled with [`next build`](#build) first.
@@ -98,27 +84,6 @@ The application will start at `http://localhost:3000` by default. The default po
npx next start -p 4000
```
Or using the `PORT` environment variable:
```bash
PORT=4000 npx next start
```
> Note: `PORT` can not be set in `.env` as booting up the HTTP server happens before any other code is initialized.
## Lint
`next lint` runs ESLint for all files in the `pages`, `components`, and `lib` directories. It also
provides a guided setup to install any required dependencies if ESLint is not already configured in
your application.
If you have other directories that you would like to lint, you can specify them using the `--dir`
flag:
```bash
next lint --dir utils
```
## Telemetry
Next.js collects **completely anonymous** telemetry data about general usage.

View File

@@ -12,22 +12,13 @@ npx create-next-app
yarn create next-app
```
You can create a [TypeScript project](https://github.com/vercel/next.js/blob/canary/docs/basic-features/typescript.md) with the `--ts, --typescript` flag:
```bash
npx create-next-app --ts
# or
yarn create next-app --typescript
```
### Options
`create-next-app` comes with the following options:
- **--ts, --typescript** - Initialize as a TypeScript project.
- **-e, --example [name]|[github-url]** - An example to bootstrap the app with. You can use an example name from the [Next.js repo](https://github.com/vercel/next.js/tree/master/examples) or a GitHub URL. The URL can use any branch and/or subdirectory.
- **--example-path [path-to-example]** - In a rare case, your GitHub URL might contain a branch name with a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this case, you must specify the path to the example separately: `--example-path foo/bar`
- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend running `yarn create next-app`
- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend to run `yarn create next-app`
### Why use Create Next App?

View File

@@ -24,21 +24,9 @@ module.exports = {
}
```
Next.js will automatically use your asset prefix for the JavaScript and CSS files it loads from the `/_next/` path (`.next/static/` folder). For example, with the above configuration, the following request for a JS chunk:
Next.js will automatically use your asset prefix for the JavaScript and CSS files it loads from the `/_next/` path (`.next/static/` folder).
```
/_next/static/chunks/4b9b41aaa062cbbfeff4add70f256968c51ece5d.4d708494b3aed70c04f0.js
```
Would instead become:
```
https://cdn.mydomain.com/_next/static/chunks/4b9b41aaa062cbbfeff4add70f256968c51ece5d.4d708494b3aed70c04f0.js
```
The exact configuration for uploading your files to a given CDN will depend on your CDN of choice. The only folder you need to host on your CDN is the contents of `.next/static/`, which should be uploaded as `_next/static/` as the above URL request indicates. **Do not upload the rest of your `.next/` folder**, as you should not expose your server code and other configuration to the public.
While `assetPrefix` covers requests to `_next/static`, it does not influence the following paths:
Asset prefix support does not influence the following paths:
- Files in the [public](/docs/basic-features/static-file-serving.md) folder; if you want to serve those assets over a CDN, you'll have to introduce the prefix yourself
- `/_next/data/` requests for `getServerSideProps` pages. These requests will always be made against the main domain since they're not static.

View File

@@ -373,14 +373,3 @@ module.exports = {
### Cache-Control
Cache-Control headers set in next.config.js will be overwritten in production to ensure that static assets can be cached effectively. If you need to revalidate the cache of a page that has been [statically generated](https://nextjs.org/docs/basic-features/pages#static-generation-recommended), you can do so by setting `revalidate` in the page's [`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) function.
## Related
For more information, we recommend the following sections:
<div class="card">
<a href="/docs/advanced-features/security-headers.md">
<b>Security Headers:</b>
<small>Improve the security of your Next.js application by add HTTP response headers.</small>
</a>
</div>

View File

@@ -1,39 +0,0 @@
---
description: Next.js reports ESLint errors and warnings during builds by default. Learn how to opt-out of this behavior here.
---
# Ignoring ESLint
When ESLint is detected in your project, Next.js fails your **production build** (`next build`) when errors are present.
If you'd like Next.js to dangerously produce production code even when your application has ESLint errors, you can disable the built-in linting step completely.
> Be sure you have configured ESLint to run in a separate part of your workflow (for example, in CI or a pre-commit hook).
Open `next.config.js` and enable the `ignoreDuringBuilds` option in the `eslint` config:
```js
module.exports = {
eslint: {
// Warning: Dangerously allow production builds to successfully complete even if
// your project has ESLint errors.
ignoreDuringBuilds: true,
},
}
```
## Related
<div class="card">
<a href="/docs/api-reference/next.config.js/introduction.md">
<b>Introduction to next.config.js:</b>
<small>Learn more about the configuration file used by Next.js.</small>
</a>
</div>
<div class="card">
<a href="/docs/basic-features/eslint.md">
<b>ESLint:</b>
<small>Get started with ESLint in Next.js.</small>
</a>
</div>

View File

@@ -26,7 +26,7 @@ module.exports = (phase, { defaultConfig }) => {
}
```
`phase` is the current context in which the configuration is loaded. You can see the [available phases](https://github.com/vercel/next.js/blob/canary/packages/next/next-server/lib/constants.ts#L1-L4). Phases can be imported from `next/constants`:
`phase` is the current context in which the configuration is loaded. You can see the available phases [here](https://github.com/vercel/next.js/blob/canary/packages/next/next-server/lib/constants.ts#L1-L4). Phases can be imported from `next/constants`:
```js
const { PHASE_DEVELOPMENT_SERVER } = require('next/constants')
@@ -44,7 +44,7 @@ module.exports = (phase, { defaultConfig }) => {
}
```
The commented lines are the place where you can put the configs allowed by `next.config.js`, which are [defined in this file](https://github.com/vercel/next.js/blob/canary/packages/next/next-server/server/config-shared.ts#L68).
The commented lines are the place where you can put the configs allowed by `next.config.js`, which are defined [here](https://github.com/vercel/next.js/blob/canary/packages/next/next-server/server/config-shared.ts#L68).
However, none of the configs are required, and it's not necessary to understand what each config does. Instead, search for the features you need to enable or modify in this section and they will show you what to do.

View File

@@ -79,7 +79,7 @@ module.exports = {
// and dynamic routes are checked
{
source: '/:path*',
destination: `https://my-old-site.com/:path*`,
destination: 'https://my-old-site.com',
},
],
}

View File

@@ -11,7 +11,7 @@ description: Enable AMP in a page, and control the way Next.js adds AMP to the p
</ul>
</details>
> AMP support is one of our advanced features, you can [read more about AMP here](/docs/advanced-features/amp-support/introduction.md).
> AMP support is one of our advanced features, you can read more about it [here](/docs/advanced-features/amp-support/introduction.md).
To enable AMP, add the following config to your page:

View File

@@ -14,12 +14,11 @@ description: Enable Image Optimization with the built-in Image component.
<details>
<summary><b>Version History</b></summary>
| Version | Changes |
| --------- | ------------------------------------------------------------------------------------------------- |
| `v11.0.0` | `src` prop support for static import.<br/>`placeholder` prop added.<br/>`blurDataURL` prop added. |
| `v10.0.5` | `loader` prop added. |
| `v10.0.1` | `layout` prop added. |
| `v10.0.0` | `next/image` introduced. |
| Version | Changes |
| --------- | ------------------------ |
| `v10.0.5` | `loader` prop added. |
| `v10.0.1` | `layout` prop added. |
| `v10.0.0` | `next/image` introduced. |
</details>
@@ -40,13 +39,17 @@ We can serve an optimized image like so:
```jsx
import Image from 'next/image'
import profilePic from '../public/me.png'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image src={profilePic} alt="Picture of the author" />
<Image
src="/me.png"
alt="Picture of the author"
width={500}
height={500}
/>
<p>Welcome to my homepage!</p>
</>
)
@@ -61,11 +64,7 @@ The `<Image />` component requires the following properties.
### src
Required and must be one of the following:
1. A statically imported image file, as in the example code above, or
2. A path string. This can be either an absolute external URL,
or an internal path depending on the [loader](#loader).
The path or URL to the source image. This is required.
When using an external URL, you must add it to
[domains](/docs/basic-features/image-optimization.md#domains) in
@@ -75,13 +74,13 @@ When using an external URL, you must add it to
The width of the image, in pixels. Must be an integer without a unit.
Required, except for statically imported images, or those with [`layout="fill"`](#layout).
Required unless [`layout="fill"`](#layout).
### height
The height of the image, in pixels. Must be an integer without a unit.
Required, except for statically imported images, or those with [`layout="fill"`](#layout).
Required unless [`layout="fill"`](#layout).
## Optional Props
@@ -133,7 +132,7 @@ const MyImage = (props) => {
return (
<Image
loader={myLoader}
src="me.png"
src="/me.png"
alt="Picture of the author"
width={500}
height={500}
@@ -163,21 +162,6 @@ When true, the image will be considered high priority and
Should only be used when the image is visible above the fold. Defaults to
`false`.
### placeholder
A placeholder to use while the image is loading, possible values are `blur` or `empty`. Defaults to `empty`.
When `blur`, the [`blurDataURL`](#blurdataurl) property will be used as the placeholder. If `src` is an object from a static import and the imported image is jpg, png, or webp, then `blurDataURL` will automatically be populated.
For dynamic images, you must provide the [`blurDataURL`](#blurdataurl) property. Solutions such as [Plaiceholder](https://github.com/joe-bell/plaiceholder) can help with `base64` generation.
When `empty`, there will be no placeholder while the image is loading, only empty space.
Try it out:
- [Demo the `blur` placeholder](https://image-component.nextjs.gallery/placeholder)
- [Demo the shimmer effect with `blurDataURL` prop](https://image-component.nextjs.gallery/shimmer)
## Advanced Props
In some cases, you may need more advanced usage. The `<Image />` component
@@ -212,22 +196,6 @@ When `eager`, load the image immediately.
[Learn more](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading)
### blurDataURL
A [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) to
be used as a placeholder image before the `src` image successfully loads. Only takes effect when combined
with [`placeholder="blur"`](#placeholder).
Must be a base64-encoded image. It will be enlarged and blurred, so a very small image (10px or
less) is recommended. Including larger images as placeholders may harm your application performance.
Try it out:
- [Demo the default `blurDataURL` prop](https://image-component.nextjs.gallery/placeholder)
- [Demo the shimmer effect with `blurDataURL` prop](https://image-component.nextjs.gallery/shimmer)
You can also [generate a solid color Data URL](https://png-pixel.com) to match the image.
### unoptimized
When true, the source image will be served as-is instead of changing quality,

View File

@@ -49,7 +49,6 @@ 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).
- `domainLocales`: `Array<{domain, defaultLocale, locales}>` - Any configured domain locales.
- `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.
- `isPreview`: `boolean` - Whether the application is currently in [preview mode](/docs/advanced-features/preview-mode.md).
@@ -113,8 +112,6 @@ export default function Page() {
}
```
> **Note:** When navigating to the same page in Next.js, the page's state **will not** be reset by default, as the top-level React component is the same. You can manually ensure the state is updated using `useEffect`.
Redirecting the user to `pages/login.js`, useful for pages behind [authentication](/docs/authentication):
```jsx

View File

@@ -29,8 +29,8 @@ export default function handler(req, res) {
For an API route to work, you need to export a function as default (a.k.a **request handler**), which then receives the following parameters:
- `req`: An instance of [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage), plus some [pre-built middlewares](/docs/api-routes/api-middlewares.md)
- `res`: An instance of [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse), plus some [helper functions](/docs/api-routes/response-helpers.md)
- `req`: An instance of [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage), plus some pre-built middlewares you can see [here](/docs/api-routes/api-middlewares.md)
- `res`: An instance of [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse), plus some helper functions you can see [here](/docs/api-routes/response-helpers.md)
To handle different HTTP methods in an API route, you can use `req.method` in your request handler, like so:

View File

@@ -48,7 +48,7 @@ const Profile = () => {
export default Profile
```
You can view this [example in action](https://next-with-iron-session.vercel.app/). Check out the [`with-iron-session`](https://github.com/vercel/next.js/tree/canary/examples/with-iron-session) example to see how it works.
You can view this example in action [here](https://next-with-iron-session.vercel.app/). Check out the [`with-iron-session`](https://github.com/vercel/next.js/tree/canary/examples/with-iron-session) example to see how it works.
### Authenticating Server-Rendered Pages
@@ -127,23 +127,77 @@ Both of these libraries support either authentication pattern. If you're interes
- [with-passport](https://github.com/vercel/next.js/tree/canary/examples/with-passport)
- [with-passport-and-next-connect](https://github.com/vercel/next.js/tree/canary/examples/with-passport-and-next-connect)
### Other Providers
To see examples with other authentication providers, check out the [examples folder](https://github.com/vercel/next.js/tree/canary/examples).
### Firebase
<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-firebase-authentication">with-firebase-authentication</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-magic">with-magic</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/auth0">auth0</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-supabase-auth-realtime-db">with-supabase-auth-realtime-db</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-userbase">with-userbase</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-supertokens">with-supertokens</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-nhost-auth-realtime-graphql">with-nhost-auth-realtime-graphql</a></li>
</ul>
</details>
When using Firebase Authentication, we recommend using the static generation pattern.
It is possible to use the Firebase Client SDK to generate an ID token and forward it directly to Firebase's REST API on the server to log-in. However, requests to Firebase might take some time to resolve, depending on your user's location.
You can either use [FirebaseUI](https://github.com/firebase/firebaseui-web-react) for a drop-in UI, or create your own with a [custom React hook](https://usehooks.com/useAuth/).
### Magic (Passwordless)
<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-magic">with-magic</a></li>
</ul>
</details>
[Magic](https://magic.link/), which uses [passwordless login](https://magic.link/), supports the static generation pattern. Similar to Firebase, a [unique identifier](https://w3c-ccg.github.io/did-primer/) has to be created on the client-side and then forwarded as a header to log-in. Then, Magic's Node SDK can be used to exchange the indentifier for a user's information.
### Auth0
<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/auth0">auth0</a></li>
</ul>
</details>
[Auth0](https://auth0.com/) can support both authentication patterns. You can also utilize [API routes](/docs/api-routes/introduction.md) for logging in/out and retrieving user information. After logging in using the [Auth0 SDK](https://github.com/auth0/nextjs-auth0), you can utilize static generation or `getServerSideProps` for server-side rendering.
### Supabase
<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-supabase-auth-realtime-db">with-supabase-auth-realtime-db</a></li>
</ul>
</details>
[Supabase](https://supabase.io/) is an open source Firebase alternative that supports many of its features, including authentication. It allows for row level security using JWT tokens and supports third party logins. Either authentication pattern is supported.
### Userbase
<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-userbase">with-userbase</a></li>
</ul>
</details>
[Userbase](https://userbase.com/) supports the static generation pattern for authentication. It's open source and allows for a high level of security with end-to-end encryption. You can learn more about it in their [official site](https://userbase.com/).
### SuperTokens
<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-supertokens">with-supertokens</a></li>
</ul>
</details>
[SuperTokens](https://supertokens.io) is a highly customizable, open-source solution split into modules (so you only use what you need).
SuperTokens currently supports credentials login, email verification, password reset flows, third-party logins, and cookie based sessions with rotating refresh tokens.
## Related
For more information on what to do next, we recommend the following sections:

View File

@@ -1,175 +0,0 @@
---
description: Next.js provides an integrated ESLint experience by default. These conformance rules help you use Next.js in the optimal way.
---
# ESLint
Since version **11.0.0**, Next.js provides an integrated [ESLint](https://eslint.org/) experience out of the box. Add `next lint` as a script to `package.json`:
```json
"scripts": {
"lint": "next lint"
}
```
Then run `npm run lint` or `yarn lint`:
```bash
yarn lint
```
If you don't already have ESLint configured in your application, you will be guided through the installation of the required packages.
```bash
yarn lint
# You'll see instructions like these:
#
# Please install eslint and eslint-config-next by running:
#
# yarn add --dev eslint eslint-config-next
#
# ...
```
If no ESLint configuration is present, Next.js will create an `.eslintrc` file in the root of your project and automatically configure it with the base configuration:
```js
{
"extends": "next"
}
```
You can now run `next lint` every time you want to run ESLint to catch errors.
> The default base configuration (`"extends": "next"`) can be updated at any time and will only be included if no ESLint configuration is present.
We recommend using an appropriate [integration](https://eslint.org/docs/user-guide/integrations#editors) to view warnings and errors directly in your code editor during development.
## Linting During Builds
Once ESLint has been set up, it will automatically run during every build (`next build`). Errors will fail the build, while warnings will not.
If you do not want ESLint to run as a build step, refer to the documentation for [Ignoring ESLint](/docs/api-reference/next.config.js/ignoring-eslint.md):
## Linting Custom Directories
By default, Next.js will run ESLint for all files in the `pages/`, `components/`, and `lib/` directories. However, you can specify which directories using the `dirs` option in the `eslint` config in `next.config.js` for production builds:
```js
module.exports = {
eslint: {
dirs: ['pages', 'utils'], // Only run ESLint on the 'pages' and 'utils' directories during production builds (next build)
},
}
```
Similarly, the `--dir` flag can be used for `next lint`:
```bash
yarn lint --dir pages --dir utils
```
## ESLint Plugin
Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/package/@next/eslint-plugin-next), making it easier to catch common issues and problems in a Next.js application. The full set of rules is as follows:
| | Rule | Description |
| :-: | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| ✔️ | [next/google-font-display](https://nextjs.org/docs/messages/google-font-display) | Enforce optional or swap font-display behavior with Google Fonts |
| ✔️ | [next/google-font-preconnect](https://nextjs.org/docs/messages/google-font-preconnect) | Enforce preconnect usage with Google Fonts |
| ✔️ | [next/link-passhref](https://nextjs.org/docs/messages/link-passhref) | Enforce passHref prop usage with custom Link components |
| ✔️ | [next/no-css-tags](https://nextjs.org/docs/messages/no-css-tags) | Prevent manual stylesheet tags |
| ✔️ | [next/no-document-import-in-page](https://nextjs.org/docs/messages/no-document-import-in-page) | Disallow importing next/document outside of pages/document.js |
| ✔️ | [next/no-head-import-in-document](https://nextjs.org/docs/messages/no-head-import-in-document) | Disallow importing next/head in pages/document.js |
| ✔️ | [next/no-html-link-for-pages](https://nextjs.org/docs/messages/no-html-link-for-pages) | Prohibit HTML anchor links to pages without a Link component |
| ✔️ | [next/no-img-element](https://nextjs.org/docs/messages/no-img-element) | Prohibit usage of HTML &lt;img&gt; element |
| ✔️ | [next/no-page-custom-font](https://nextjs.org/docs/messages/no-page-custom-font) | Prevent page-only custom fonts |
| ✔️ | [next/no-sync-scripts](https://nextjs.org/docs/messages/no-sync-scripts) | Forbid synchronous scripts |
| ✔️ | [next/no-title-in-document-head](https://nextjs.org/docs/messages/no-title-in-document-head) | Disallow using &lt;title&gt; with Head from next/document |
| ✔️ | [next/no-unwanted-polyfillio](https://nextjs.org/docs/messages/no-unwanted-polyfillio) | Prevent duplicate polyfills from Polyfill.io |
- ✔: Enabled in the recommended configuration
## Base Configuration
The Next.js base ESLint configuration is automatically generated when `next lint` is run for the first time:
```js
{
"extends": "next"
}
```
This configuration extends recommended rule sets from various ESLint plugins:
- [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-react)
- [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks)
- [`eslint-plugin-next`](https://www.npmjs.com/package/@next/eslint-plugin-next)
You can see the full details of the shareable configuration in the [`eslint-config-next`](https://www.npmjs.com/package/eslint-config-next) package.
## Disabling Rules
If you would like to modify or disable any rules provided by the supported plugins (`react`, `react-hooks`, `next`), you can directly change them using the `rules` property in your `.eslintrc`:
```js
{
"extends": "next",
"rules": {
"react/no-unescaped-entities": "off",
"@next/next/no-page-custom-font": "off",
}
}
```
> **Note**: If you need to also include a separate, custom ESLint configuration, it is highly recommended that `eslint-config-next` is extended last after other configurations. For example:
>
> ```
> {
> "extends": ["eslint:recommended", "next"]
> }
> ```
>
> The `next` configuration already handles setting default values for the `parser`, `plugins` and `settings` properties.
> There is no need to manually re-declare any of these properties unless you need a different configuration for your use case.
> If you include any other shareable configurations, you will need to make sure that these properties are not overwritten or modified.
### Core Web Vitals
A stricter `next/core-web-vitals` rule set can also be added in `.eslintrc`:
```
{
"extends": ["next", "next/core-web-vitals"]
}
```
`next/core-web-vitals` updates `eslint-plugin-next` to error on a number of rules that are warnings by default if they affect [Core Web Vitals](https://web.dev/vitals/).
> Both `next` and `next/core-web-vitals` entry points are automatically included for new applications built with [Create Next App](/docs/api-reference/create-next-app.md).
## Usage with Prettier
ESLint also contains code formatting rules, which can conflict with your existing [Prettier](https://prettier.io/) setup. We recommend including [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) in your ESLint config to make ESLint and Prettier work together.
```js
{
"extends": ["next", "prettier"]
}
```
## Migrating Existing Config
If you already have ESLint configured in your application, we recommend extending directly from the Next.js ESLint plugin instead of the shareable configuration.
```js
module.exports = {
extends: [
//...
'plugin:@next/next/recommended',
],
}
```
This eliminates any risk of collisions that can occur due to importing the same plugin or parser across multiple configurations.

View File

@@ -50,39 +50,6 @@ function Home() {
export default Home
```
## Image Imports
You can `import` images that live in your project. (Note that `require` is not supported—only `import`.)
With direct `import`s, `width`, `height`, and `blurDataURL` will be automatically provided to the image component. Alt text is still needed separately.
```js
import Image from 'next/image'
import profilePic from '../public/me.png'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src={profilePic}
alt="Picture of the author"
// width={500} automatically provided
// height={500} automatically provided
// blurDataURL="data:..." automatically provided
// Optionally allows to add a blurred version of the image while loading
// placeholder="blur"
/>
<p>Welcome to my homepage!</p>
</>
)
}
```
For dynamic or remote images, you'll have to provide [`width`](/docs/api-reference/next/image#width), [`height`](/docs/api-reference/next/image#height) and [`blurDataURL`](/docs/api-reference/next/image#blurdataurl) manually.
## Properties
[View all properties](/docs/api-reference/next/image.md) available to the `next/image` component.
## Configuration
@@ -171,22 +138,6 @@ module.exports = {
}
```
### Disable Static Imports
The default behavior allows you to import static files such as `import icon from './icon.png` and then pass that to the `src` property.
In some cases, you may wish to disable this feature if it conflicts with other plugins that expect the import to behave differently.
You can disable static image imports with the following configuration below.
```js
module.exports = {
images: {
disableStaticImages: true,
},
}
```
## Related
For more information on what to do next, we recommend the following sections:

View File

@@ -1,129 +0,0 @@
---
description: Next.js helps you optimize loading third-party scripts with the built-in next/script component.
---
# Script Component
<details>
<summary><b>Version History</b></summary>
| Version | Changes |
| --------- | ------------------------- |
| `v11.0.0` | `next/script` introduced. |
</details>
The Next.js Script component enables developers to set the loading priority of third-party scripts to save developer time and improve loading performance.
Websites often need third parties for things like analytics, ads, customer support widgets, and consent management. However, these scripts tend to be heavy on loading performance and can drag down the user experience. Developers often struggle to decide where to place them in an application for optimal loading.
With `next/script`, you can define the `strategy` property and Next.js will optimize loading for the script:
- `beforeInteractive`: For critical scripts that need to be fetched and executed **before** the page is interactive, such as bot detection and consent management. These scripts are injected into the initial HTML from the server and run before self-bundled JavaScript is executed.
- `afterInteractive` (**default**): For scripts that can fetch and execute **after** the page is interactive, such as tag managers and analytics. These scripts are injected on the client-side and will run after hydration.
- `lazyOnload` For scripts that can wait to load during idle time, such as chat support and social media widgets.
> **Note:** These loading strategies work the same for inline scripts wrapped with `<Script>`. See the inline scripts example below.
## Usage
Previously, you needed to define `script` tags inside the `Head` of your Next.js page.
```js
// Before
// pages/index.js
import Head from 'next/head'
function Home() {
return (
<>
<Head>
<script async src="https://www.google-analytics.com/analytics.js" />
</Head>
</>
)
}
```
With `next/script`, you no longer need to wrap scripts in `next/head`. Further, `next/script` should **not** be used in `pages/_document.js` as `next/script` has client-side functionality to ensure loading order. For example:
```js
// After
// pages/index.js
import Script from 'next/script'
function Home() {
return (
<>
<Script src="https://www.google-analytics.com/analytics.js" />
</>
)
}
```
## Examples
### Loading Polyfills
```js
import Script from 'next/script'
;<Script
src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver"
strategy="beforeInteractive"
/>
```
### Lazy-Loading
```js
import Script from 'next/script'
;<Script
src="https://connect.facebook.net/en_US/sdk.js"
strategy="lazyOnload"
/>
```
### Executing Code After Loading (`onLoad`)
```js
import Script from 'next/script'
;<Script
id="stripe-js"
src="https://js.stripe.com/v3/"
onLoad={() => {
this.setState({ stripe: window.Stripe('pk_test_12345') })
}}
/>
```
### Inline Scripts
```js
import Script from 'next/script'
<Script strategy="lazyOnload">
{`document.getElementById('banner').removeClass('hidden')`}
</Script>
// or
<Script
dangerouslySetInnerHTML={{
__html: `document.getElementById('banner').removeClass('hidden')`
}}
/>
```
### Forwarding Attributes
```js
import Script from 'next/script'
;<Script
src="https://www.google-analytics.com/analytics.js"
id="analytics"
nonce="XUENAJFW"
data-test="analytics"
/>
```

View File

@@ -11,23 +11,9 @@ description: Next.js supports TypeScript by default and has built-in types for p
</ul>
</details>
Next.js provides an integrated [TypeScript](https://www.typescriptlang.org/)
experience out of the box, similar to an IDE.
Next.js provides an integrated [TypeScript](https://www.typescriptlang.org/) experience out of the box, similar to an IDE.
## `create-next-app` support
You can create a TypeScript project with [`create-next-app`](https://nextjs.org/docs/api-reference/create-next-app) using the `--ts, --typescript` flag like so:
```
npx create-next-app --ts
# or
yarn create next-app --typescript
```
## Existing projects
To get started in an existing project, create an empty `tsconfig.json` file in
the root folder:
To get started, create an empty `tsconfig.json` file in the root of your project:
```bash
touch tsconfig.json
@@ -163,4 +149,4 @@ module.exports = nextConfig
Since `v10.2.1` Next.js supports [incremental type checking](https://www.typescriptlang.org/tsconfig#incremental) when enabled in your `tsconfig.json`, this can help speed up type checking in larger applications.
It is highly recommended to be on at least `v4.3.2` of TypeScript to experience the [best performance](https://devblogs.microsoft.com/typescript/announcing-typescript-4-3/#lazier-incremental) when leveraging this feature.
It is highly recommended to be on at least `v4.3.0-beta` of TypeScript to experience the best performance when leveraging this feature.

View File

@@ -6,7 +6,7 @@ description: Get started with Next.js in the official documentation, and learn m
Welcome to the Next.js documentation!
If you're new to Next.js we recommend that you start with the [learn course](https://nextjs.org/learn/basics/create-nextjs-app).
If you're new to Next.js we recommend that you start with the [learn course](https://nextjs.org/learn/basics/getting-started).
The interactive course with quizzes will guide you through everything you need to know to use Next.js.
@@ -55,8 +55,7 @@ Open `package.json` and add the following `scripts`:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
"start": "next start"
}
```
@@ -65,7 +64,6 @@ These scripts refer to the different stages of developing an application:
- `dev` - Runs [`next dev`](/docs/api-reference/cli.md#development) which starts Next.js in development mode
- `build` - Runs [`next build`](/docs/api-reference/cli.md#build) which builds the application for production usage
- `start` - Runs [`next start`](/docs/api-reference/cli.md#production) which starts a Next.js production server
- `lint` - Runs [`next lint`](/docs/api-reference/cli.md#lint) which sets up Next.js' built-in ESLint configuration
Next.js is built around the concept of [pages](/docs/basic-features/pages.md). A page is a [React Component](https://reactjs.org/docs/components-and-props.html) exported from a `.js`, `.jsx`, `.ts`, or `.tsx` file in the `pages` directory.

View File

@@ -37,10 +37,6 @@
"title": "Fast Refresh",
"path": "/docs/basic-features/fast-refresh.md"
},
{
"title": "ESLint",
"path": "/docs/basic-features/eslint.md"
},
{
"title": "TypeScript",
"path": "/docs/basic-features/typescript.md"
@@ -52,10 +48,6 @@
{
"title": "Supported Browsers and Features",
"path": "/docs/basic-features/supported-browsers-features.md"
},
{
"title": "Script",
"path": "/docs/basic-features/script.md"
}
]
},
@@ -208,10 +200,6 @@
{
"title": "Internationalized Routing",
"path": "/docs/advanced-features/i18n-routing.md"
},
{
"title": "Security Headers",
"path": "/docs/advanced-features/security-headers.md"
}
]
},
@@ -352,10 +340,6 @@
"title": "Configuring onDemandEntries",
"path": "/docs/api-reference/next.config.js/configuring-onDemandEntries.md"
},
{
"title": "Ignoring ESLint",
"path": "/docs/api-reference/next.config.js/ignoring-eslint.md"
},
{
"title": "Ignoring TypeScript Errors",
"path": "/docs/api-reference/next.config.js/ignoring-typescript-errors.md"

View File

@@ -236,4 +236,4 @@ If you've ejected Create React App, here are some things to consider:
## Learn More
You can learn more about Next.js by completing our [starter tutorial](https://nextjs.org/learn/basics/create-nextjs-app). If you have questions or if this guide didn't work for you, feel free to reach out to our community on [GitHub Discussions](https://github.com/vercel/next.js/discussions).
You can learn more about Next.js by completing our [starter tutorial](https://nextjs.org/learn/basics/getting-started). If you have questions or if this guide didn't work for you, feel free to reach out to our community on [GitHub Discussions](https://github.com/vercel/next.js/discussions).

View File

@@ -4,133 +4,6 @@ description: Learn how to upgrade Next.js.
# Upgrade Guide
## Upgrading from version 10 to 11
### Upgrade React version to latest
Most applications already use the latest version of React, with Next.js 11 the minimum React version has been updated to 17.0.2.
To upgrade you can run the following command:
```
npm install react@latest react-dom@latest
```
Or using `yarn`:
```
yarn add react@latest react-dom@latest
```
### Upgrade Next.js version to latest
To upgrade you can run the following command in the terminal:
```
npm install next@latest
```
or
```
yarn add next@latest
```
### Webpack 5
Webpack 5 is now the default for all Next.js applications. If you did not have custom webpack configuration your application is already using webpack 5. If you do have custom webpack configuration you can refer to the [Next.js webpack 5 documentation](https://nextjs.org/docs/messages/webpack5) for upgrading guidance.
### Cleaning the `distDir` is now a default
The build output directory (defaults to `.next`) is now cleared by default except for the Next.js caches. You can refer to [the cleaning `distDir` RFC](https://github.com/vercel/next.js/discussions/6009) for more information.
If your application was relying on this behavior previously you can disable the new default behavior by adding the `cleanDistDir: false` flag in `next.config.js`.
### `PORT` is now supported for `next dev` and `next start`
Next.js 11 supports the `PORT` environment variable to set the port the application has to run on. Using `-p`/`--port` is still recommended but if you were prohibited from using `-p` in any way you can now use `PORT` as an alternative:
Example:
```
PORT=4000 next start
```
### Remove `super.componentDidCatch()` from `pages/_app.js`
The `next/app` component's `componentDidCatch` has been deprecated since Next.js 9 as it's no longer needed and has since been a no-op, in Next.js 11 it has been removed.
If your `pages/_app.js` has a custom `componentDidCatch` method you can remove `super.componentDidCatch` as it is no longer needed.
### Remove `Container` from `pages/_app.js`
This export has been deprecated since Next.js 9 as it's no longer needed and has since been a no-op with a warning during development. In Next.js 11 it has been removed.
If your `pages/_app.js` imports `Container` from `next/app` you can remove `Container` as it has been removed. Learn more in [the documentation](https://nextjs.org/docs/messages/app-container-deprecated).
### Remove `props.url` usage from page components
This property has been deprecated since Next.js 4 and has since shown a warning during development. With the introduction of `getStaticProps` / `getServerSideProps` these methods already disallowed usage of `props.url`. In Next.js 11 it has been removed completely.
You can learn more in [the documentation](https://nextjs.org/docs/messages/url-deprecated).
### Remove `unsized` property on `next/image`
The `unsized` property on `next/image` was deprecated in Next.js 10.0.1. You can use `layout="fill"` instead. In Next.js 11 `unsized` was removed.
### Remove `modules` property on `next/dynamic`
The `modules` and `render` option for `next/dynamic` have been deprecated since Next.js 9.5 showing a warning that it has been deprecated. This was done in order to make `next/dynamic` close to `React.lazy` in API surface. In Next.js 11 the `modules` and `render` options have been removed.
This option hasn't been mentioned in the documentation since Next.js 8 so it's less likely that your application is using it.
If you application does use `modules` and `render` you can refer to [the documentation](https://nextjs.org/docs/messages/next-dynamic-modules).
### Remove `Head.rewind`
`Head.rewind` has been a no-op since Next.js 9.5, in Next.js 11 it was removed. You can safely remove your usage of `Head.rewind`.
### Moment.js locales excluded by default
Moment.js includes translations for a lot of locales by default. Next.js now automatically excludes these locales by default to optimize bundle size for applications using Moment.js.
To load a specific locale use this snippet:
```js
import moment from 'moment'
import 'moment/locale/ja'
moment.locale('ja')
```
You can opt-out of this new default by adding `excludeDefaultMomentLocales: false` to `next.config.js` if you do not want the new behavior, do note it's highly recommended to not disable this new optimization as it significantly reduces the size of Moment.js.
### Update usage of `router.events`
In case you're accessing `router.events` during rendering, in Next.js 11 `router.events` is no longer provided during pre-rendering. Ensure you're accessing `router.events` in `useEffect`:
```js
useEffect(() => {
const handleRouteChange = (url, { shallow }) => {
console.log(
`App is changing to ${url} ${
shallow ? 'with' : 'without'
} shallow routing`
)
}
router.events.on('routeChangeStart', handleRouteChange)
// If the component is unmounted, unsubscribe
// from the event with the `off` method:
return () => {
router.events.off('routeChangeStart', handleRouteChange)
}
}, [router])
```
If your application uses `router.router.events` which was an internal property that was not public please make sure to use `router.events` as well.
## React 16 to 17
React 17 introduced a new [JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) that brings a long-time Next.js feature to the wider React ecosystem: Not having to `import React from 'react'` when using JSX. When using React 17 Next.js will automatically use the new transform. This transform does not make the `React` variable global, which was an unintended side-effect of the previous Next.js implementation. A [codemod is available](/docs/advanced-features/codemods.md#add-missing-react-import) to automatically fix cases where you accidentally used `React` without importing it.
@@ -142,13 +15,7 @@ There were no breaking changes between version 9 and 10.
To upgrade run the following command:
```
npm install next@10
```
Or using `yarn`:
```
yarn add next@10
npm install next@latest
```
## Upgrading from version 8 to 9

View File

@@ -1,14 +0,0 @@
# Client-side Exception Occurred
#### Why This Error Occurred
In your production application a client-side error occurred that was not caught by an error boundary. Additional information should be visible in the console tab of your browser.
#### Possible Ways to Fix It
Add error boundaries in your React tree to gracefully handle client-side errors and render a fallback view when they occur.
### Useful Links
- [Error Boundaries Documentation](https://reactjs.org/docs/error-boundaries.html)
- [Custom Error Page Documentation](https://nextjs.org/docs/advanced-features/custom-error-page#more-advanced-error-page-customizing)

View File

@@ -1,33 +0,0 @@
# `future.webpack5` has been moved to `webpack5`
#### Why This Error Occurred
The `future.webpack5` option has been moved to `webpack5` in `next.config.js`.
#### Possible Ways to Fix It
If you had the value `true` you can remove the option as webpack 5 is now the default for all Next.js apps unless opted out.
If you had he value `false` you can update `next.config.js`:
Change `future.webpack5` to `webpack5`.
Current `next.config.js`:
```js
// next.config.js
module.exports = {
future: {
webpack5: false,
},
}
```
Updated `next.config.js`:
```js
// next.config.js
module.exports = {
webpack5: false,
}
```

View File

@@ -1,36 +0,0 @@
# Multiple children were passed to <Link>
#### Why This Error Occurred
In your application code multiple children were passed to `next/link` but only one child is supported:
For example:
```js
import Link from 'next/link'
export default function Home() {
return (
<Link href="/about">
<a>To About</a>
<a>Second To About</a>
</Link>
)
}
```
#### Possible Ways to Fix It
Make sure only one child is used when using `<Link>`:
```js
import Link from 'next/link'
export default function Home() {
return (
<Link href="/about">
<a>To About</a>
</Link>
)
}
```

View File

@@ -373,28 +373,7 @@
"path": "/errors/undefined-webpack-config.md"
},
{ "title": "url-deprecated", "path": "/errors/url-deprecated.md" },
{ "title": "webpack5", "path": "/errors/webpack5.md" },
{
"title": "client-side-exception-occurred",
"path": "/errors/client-side-exception-occurred.md"
},
{
"title": "future-webpack5-moved-to-webpack5",
"path": "/errors/future-webpack5-moved-to-webpack5.md"
},
{
"title": "link-multiple-children",
"path": "/errors/link-multiple-children.md"
},
{ "title": "no-img-element", "path": "/errors/no-img-element.md" },
{
"title": "non-dynamic-getstaticpaths-usage",
"path": "/errors/non-dynamic-getstaticpaths-usage.md"
},
{
"title": "placeholder-blur-data-url",
"path": "/errors/placeholder-blur-data-url.md"
}
{ "title": "webpack5", "path": "/errors/webpack5.md" }
]
}
]

View File

@@ -2,11 +2,11 @@
### Why This Error Occurred
`next/document` was imported in a page outside of `pages/_document.js` (or `pages/_document.tsx` if you are using TypeScript). This can cause unexpected issues in your application.
`next/document` was imported in a page outside of `pages/_document.js`. This can cause unexpected issues in your application.
### Possible Ways to Fix It
Only import and use `next/document` within `pages/_document.js` (or `pages/_document.tsx`) to override the default `Document` component:
Only import and use `next/document` within `pages/_document.js` to override the default `Document` component:
```jsx
// pages/_document.js

View File

@@ -9,7 +9,7 @@ An HTML `<img>` element was used to display an image. For better performance and
Import and use the `<Image />` component:
```jsx
import Image from 'next/image'
import { Image } from 'next/image'
function Home() {
return (

View File

@@ -11,7 +11,7 @@ A synchronous script was used which can impact your webpage's performance.
Use the Script component with the right loading strategy to defer loading of the script until necessary.
```jsx
import Script from 'next/script'
import Script from 'next/experimental-script'
const Home = () => {
return (
@@ -25,6 +25,8 @@ const Home = () => {
export default Home
```
Note: This is still an experimental feature and needs to be enabled via the `experimental.scriptLoader` flag in `next.config.js`.
### Useful Links
- [Efficiently load third-party JavaScript](https://web.dev/efficiently-load-third-party-javascript/)

View File

@@ -1,15 +0,0 @@
# `placeholder=blur` without `blurDataURL`
#### Why This Error Occurred
You are attempting use the `next/image` component with `placeholder=blur` property but no `blurDataURL` property.
The `blurDataURL` might be missing because your using a string for `src` instead of a static import.
Or `blurDataURL` might be missing because the static import is an unsupported image format. Only jpg, png, and webp are supported at this time.
#### Possible Ways to Fix It
- Add a [`blurDataURL`](https://nextjs.org/docs/api-reference/next/image#blurdataurl) property, the contents should be a small Data URL to represent the image
- Change the [`src`](https://nextjs.org/docs/api-reference/next/image#src) property to a static import with one of the supported file types: jpg, png, or webp
- Remove the [`placeholder`](https://nextjs.org/docs/api-reference/next/image#placeholder) property, effectively no blur effect

View File

@@ -17,4 +17,4 @@ Remove the plugin specified in the error message from your custom PostCSS config
#### How do I configure CSS Modules?
CSS Modules are supported in [Next.js' built-in CSS support](https://nextjs.org/docs/advanced-features/customizing-postcss-config).
You can [read more about how to use CSS Modules here](https://nextjs.org/docs/advanced-features/customizing-postcss-config).
You can [read more](https://nextjs.org/docs/advanced-features/customizing-postcss-config) about how to use them [here](https://nextjs.org/docs/advanced-features/customizing-postcss-config).

View File

@@ -39,7 +39,7 @@ module.exports = {
}
```
You can [read more about configuring PostCSS in Next.js here](https://nextjs.org/docs/advanced-features/customizing-postcss-config).
You can [read more](https://nextjs.org/docs/advanced-features/customizing-postcss-config) about configuring PostCSS in Next.js [here](https://nextjs.org/docs/advanced-features/customizing-postcss-config).
#### Common Errors

View File

@@ -5,7 +5,7 @@
Your project is using an old version of `react` or `react-dom` that does not
meet the suggested minimum version requirement.
Next.js suggests using, at a minimum, `react@17.0.2` and `react-dom@17.0.2`.
Next.js suggests using, at a minimum, `react@17.0.1` and `react-dom@17.0.1`.
Older versions of `react` and `react-dom` do work with Next.js, however, they do
not enable all of Next.js' features.
@@ -39,8 +39,8 @@ yarn add react@latest react-dom@latest
```json
{
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}
```

View File

@@ -10,7 +10,7 @@ The reason this is going away is that we want to make things very predictable an
#### Possible Ways to Fix It
https://nextjs.org/docs/advanced-features/codemods#url-to-withrouter
https://github.com/zeit/next-codemod#url-to-withrouter
Since Next 5 we provide a way to explicitly inject the Next.js router object into pages and all their descending components.
The `router` property that is injected will hold the same values as `url`, like `pathname`, `asPath`, and `query`.
@@ -33,4 +33,4 @@ export default withRouter(Page)
We provide a codemod (a code to code transformation) to automatically change the `url` property usages to `withRouter`.
You can find this codemod and instructions on how to run it here: https://nextjs.org/docs/advanced-features/codemods#url-to-withrouter
You can find this codemod and instructions on how to run it here: https://github.com/zeit/next-codemod#url-to-withrouter

View File

@@ -2,17 +2,17 @@
#### Why This Message Occurred
Next.js has adopted webpack 5 as the default for compilation. We've spent a lot of effort into ensuring the transition from webpack 4 to 5 will be as smooth as possible. For example Next.js now comes with both webpack 4 and 5 allowing you to adopt webpack 5 by adding a flag to your `next.config.js`:
Next.js will soon adopt webpack 5 as the default for compilation. We've spent a lot of effort into ensuring the transition from webpack 4 to 5 will be as smooth as possible. For example Next.js now comes with both webpack 4 and 5 allowing you to adopt webpack 5 by adding a flag to your `next.config.js`:
```js
module.exports = {
// Webpack 5 is enabled by default
// You can still use webpack 4 while upgrading to the latest version of Next.js by adding the "webpack5: false" flag
webpack5: false,
future: {
webpack5: true,
},
}
```
Using webpack 5 in your application has many benefits, notably:
Adopting webpack 5 in your application has many benefits, notably:
- Improved Disk Caching: `next build` is significantly faster on subsequent builds
- Improved Fast Refresh: Fast Refresh work is prioritized
@@ -22,13 +22,11 @@ Using webpack 5 in your application has many benefits, notably:
- Support for web workers using `new Worker(new URL("worker.js", import.meta.url))`
- Support for `exports`/`imports` field in `package.json`
In the past releases we have gradually rolled out webpack 5 to Next.js applications:
In upcoming releases we'll gradually roll out webpack 5 to applications that are compatible with webpack 5:
- In Next.js 10.2 we automatically opted-in applications without custom webpack configuration in `next.config.js`
- In Next.js 10.2 we automatically opted-in applications that do not have a `next.config.js`
- In Next.js 11 webpack 5 was enabled by default for all applications. You can still opt-out and use webpack 4 to help with backwards compatibility using `webpack5: false` in `next.config.js`
In the next major version webpack 4 support will be removed.
- In the next minor version we'll automatically opt-in applications without custom webpack configuration in `next.config.js`
- In the next minor version we'll automatically opt-in applications that do not have a `next.config.js`
- In the next major version we'll enable webpack 5 by default. You'll still be able to opt-out and use webpack 4 to help with backwards compatibility
#### Custom webpack configuration

View File

@@ -0,0 +1,21 @@
# activeClassName example
ReactRouter has a convenience property on the `Link` element to allow an author to set the _active_ className on a link. This example replicates that functionality using Next's own `Link`.
## 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/active-class-name&project-name=active-class-name&repository-name=active-class-name)
## 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 active-class-name active-class-name-app
# or
yarn create next-app --example active-class-name active-class-name-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)).

View File

@@ -0,0 +1,32 @@
import { useRouter } from 'next/router'
import PropTypes from 'prop-types'
import Link from 'next/link'
import React, { Children } from 'react'
const ActiveLink = ({ children, activeClassName, ...props }) => {
const { asPath } = useRouter()
const child = Children.only(children)
const childClassName = child.props.className || ''
// pages/index.js will be matched via props.href
// pages/about.js will be matched via props.href
// pages/[slug].js will be matched via props.as
const className =
asPath === props.href || asPath === props.as
? `${childClassName} ${activeClassName}`.trim()
: childClassName
return (
<Link {...props}>
{React.cloneElement(child, {
className: className || null,
})}
</Link>
)
}
ActiveLink.propTypes = {
activeClassName: PropTypes.string.isRequired,
}
export default ActiveLink

View File

@@ -0,0 +1,34 @@
import ActiveLink from './ActiveLink'
const Nav = () => (
<nav>
<style jsx>{`
.nav-link {
text-decoration: none;
}
.active:after {
content: ' (current page)';
}
`}</style>
<ul className="nav">
<li>
<ActiveLink activeClassName="active" href="/">
<a className="nav-link">Home</a>
</ActiveLink>
</li>
<li>
<ActiveLink activeClassName="active" href="/about">
<a className="nav-link">About</a>
</ActiveLink>
</li>
<li>
<ActiveLink activeClassName="active" href="/[slug]" as="/dynamic-route">
<a className="nav-link">Dynamic Route</a>
</ActiveLink>
</li>
</ul>
</nav>
)
export default Nav

View File

@@ -0,0 +1,16 @@
{
"name": "active-class-name",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"author": "Remy Sharp <remy@leftlogic.com>",
"dependencies": {
"next": "latest",
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"license": "MIT"
}

View File

@@ -0,0 +1,14 @@
import { useRouter } from 'next/router'
import Nav from '../components/Nav'
const SlugPage = () => {
const { asPath } = useRouter()
return (
<>
<Nav />
<p>Hello, I'm the {asPath} page</p>
</>
)
}
export default SlugPage

View File

@@ -0,0 +1,10 @@
import Nav from '../components/Nav'
const AboutPage = () => (
<>
<Nav />
<p>Hello, I'm the about page</p>
</>
)
export default AboutPage

View File

@@ -0,0 +1,10 @@
import Nav from '../components/Nav'
const IndexPage = () => (
<>
<Nav />
<p>Hello, I'm the index page</p>
</>
)
export default IndexPage

34
nextjs/examples/amp-first/.gitignore vendored Normal file
View File

@@ -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

View File

@@ -0,0 +1,79 @@
# AMP First Boilerplate ⚡
This example sets up the boilerplate for an AMP First Site. You can see a live version [here](https://my-next-app.sebastianbenz.vercel.app). The boilerplate includes the following features:
- AMP Extension helpers (`amp-state`, `amp-script`, ...)
- AMP Serviceworker integration
- App manifest
- Offline page
## 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/amp-first&project-name=amp-first&repository-name=amp-first)
## 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 amp-first amp-first-app
# or
yarn create next-app --example amp-first amp-first-app
```
Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits. You will also see AMP validation errors in the console.
## Todo
Things you need to do after installing the boilerplate:
1. Update your app manifest in [`public/manifest.json`](public/manifest.json) with your app-specific data (`theme_color`, `background_color`, `name`, `short_name`).
2. Update the `THEME_COLOR` variable defined in [`components/Layout.js`](components/Layout.js).
3. Update favicon and icons in [`public/favicon.ico`](public/favicon.ico) and [`public/static/images/icons-*.png`](public/static/images).
4. Set the default language in [`pages/_document.js`](pages/_document.js).
5. Review the AMP Serviceworker implementation in [`public/serviceworker.js`](public/serviceworker.js).
## Tips & Tricks
- **Using AMP Components:** you can import AMP components using `next/head`. Checkout `components/amp/AmpCustomElement` for a simple way to import AMP components. Once the component is imported, you can use it like any other HTML element.
- **amp-bind & amp-state:** it's no problem to use `amp-bind` and `amp-state` with Next.js. There are two things to be aware of:
1. The `[...]` binding syntax, e.g. `[text]="myStateVariable"`, is not supported in JSX. Use `data-amp-bind-text="myStateVariable"` instead.
2. Initializing `amp-state` via JSON string is not supported in JSX:
```html
<amp-state id="myState">
<script type="application/json">
{
"foo": "bar"
}
</script>
</amp-state>
```
Instead you need to use `dangerouslySetInnerHTML` to initialize the string. can use the [`/components/amp/AmpState.js`](components/amp/AmpState.js) component to see how it works. The same approach works for `amp-access` and `amp-consent` as well:
```html
<AmpState id="message" value={ message: 'Hello World' }/>
```
- **amp-list & amp-mustache:** mustache templates conflict with JSX and it's template literals need to be escaped. A simple approach is to escape them via back ticks: `` src={`{{imageUrl}}`} ``.
- **amp-script:** you can use [amp-script](https://amp.dev/documentation/components/amp-script/) to add custom JavaScript to your AMP pages. The boilerplate includes a helper [`components/amp/AmpScript.js`](components/amp/AmpScript.js) to simplify using `amp-script`. The helper also supports embedding inline scripts. Good to know: Next.js uses [AMP Optimizer](https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer) under the hood, which automatically adds the needed script hashes for [inline amp-scripts](https://amp.dev/documentation/components/amp-script/#load-javascript-from-a-local-element).
## Deployment
For production builds, you need to run (the app will be build into the `.next` folder):
```shell
$ yarn build
```
To start the application in production mode, run:
```shell
$ yarn start
```
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)).

View File

@@ -0,0 +1,54 @@
import PropTypes from 'prop-types'
import NextHead from 'next/head'
import { AmpIncludeAmpInstallServiceworker } from './amp/AmpCustomElement'
// Your app's theme color
const THEME_COLOR = '#005af0'
/**
* A sample page layout installing the AMP Serviceworker by default.
*
* @param {Props} props
*/
const Layout = (props) => (
<>
<NextHead>
<title>{props.title || ''}</title>
<meta name="description" content={props.description || ''} />
<meta name="theme-color" content={THEME_COLOR} />
<link rel="icon" sizes="192x192" href="/static/images/icons-192.png" />
<link rel="apple-touch-icon" href="/static/images/icons-192.png" />
<link rel="icon" href="/static/favicon.ico" />
<link rel="manifest" href="/manifest.json" />
</NextHead>
{props.children}
<AmpIncludeAmpInstallServiceworker />
<amp-install-serviceworker
src="/serviceworker.js"
data-iframe-src="/install-serviceworker.html"
layout="nodisplay"
/>
<style jsx global>{`
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol';
min-height: 100vh;
scroll-behavior: smooth;
text-rendering: optimizeSpeed;
line-height: 1.5;
}
`}</style>
</>
)
Layout.propTypes = {
title: PropTypes.string,
description: PropTypes.string,
}
export default Layout

View File

@@ -0,0 +1,531 @@
/**
* @file An AMP Component import helper. This file is auto-generated using
* https://www.npmjs.com/package/@ampproject/toolbox-validator-rules.
*/
import React from 'react'
import Head from 'next/head'
export function AmpIncludeCustomElement(props) {
return (
<Head>
<script
async
custom-element={props.name}
src={
'https://cdn.ampproject.org/v0/' +
props.name +
'-' +
props.version +
'.js'
}
key={props.name}
/>
</Head>
)
}
export function AmpIncludeCustomTemplate(props) {
return (
<Head>
<script
async
custom-template={props.name}
src={
'https://cdn.ampproject.org/v0/' +
props.name +
'-' +
props.version +
'.js'
}
key={props.name}
/>
</Head>
)
}
export function AmpIncludeAmp3dGltf() {
return <AmpIncludeCustomElement name="amp-3d-gltf" version="0.1" />
}
export function AmpIncludeAmp3qPlayer() {
return <AmpIncludeCustomElement name="amp-3q-player" version="0.1" />
}
export function AmpIncludeAmpAccessLaterpay() {
return <AmpIncludeCustomElement name="amp-access-laterpay" version="0.2" />
}
export function AmpIncludeAmpAccessPoool() {
return <AmpIncludeCustomElement name="amp-access-poool" version="0.1" />
}
export function AmpIncludeAmpAccessScroll() {
return <AmpIncludeCustomElement name="amp-access-scroll" version="0.1" />
}
export function AmpIncludeAmpAccess() {
return <AmpIncludeCustomElement name="amp-access" version="0.1" />
}
export function AmpIncludeAmpAccordion() {
return <AmpIncludeCustomElement name="amp-accordion" version="0.1" />
}
export function AmpIncludeAmpActionMacro() {
return <AmpIncludeCustomElement name="amp-action-macro" version="0.1" />
}
export function AmpIncludeAmpAdCustom() {
return <AmpIncludeCustomElement name="amp-ad-custom" version="0.1" />
}
export function AmpIncludeAmpAd() {
return <AmpIncludeCustomElement name="amp-ad" version="0.1" />
}
export function AmpIncludeAmpAddthis() {
return <AmpIncludeCustomElement name="amp-addthis" version="0.1" />
}
export function AmpIncludeAmpAnalytics() {
return <AmpIncludeCustomElement name="amp-analytics" version="0.1" />
}
export function AmpIncludeAmpAnim() {
return <AmpIncludeCustomElement name="amp-anim" version="0.1" />
}
export function AmpIncludeAmpAnimation() {
return <AmpIncludeCustomElement name="amp-animation" version="0.1" />
}
export function AmpIncludeAmpApesterMedia() {
return <AmpIncludeCustomElement name="amp-apester-media" version="0.1" />
}
export function AmpIncludeAmpAppBanner() {
return <AmpIncludeCustomElement name="amp-app-banner" version="0.1" />
}
export function AmpIncludeAmpAudio() {
return <AmpIncludeCustomElement name="amp-audio" version="0.1" />
}
export function AmpIncludeAmpAutoAds() {
return <AmpIncludeCustomElement name="amp-auto-ads" version="0.1" />
}
export function AmpIncludeAmpAutocomplete() {
return <AmpIncludeCustomElement name="amp-autocomplete" version="0.1" />
}
export function AmpIncludeAmpBaseCarousel() {
return <AmpIncludeCustomElement name="amp-base-carousel" version="0.1" />
}
export function AmpIncludeAmpBeopinion() {
return <AmpIncludeCustomElement name="amp-beopinion" version="0.1" />
}
export function AmpIncludeAmpBind() {
return <AmpIncludeCustomElement name="amp-bind" version="0.1" />
}
export function AmpIncludeAmpBodymovinAnimation() {
return (
<AmpIncludeCustomElement name="amp-bodymovin-animation" version="0.1" />
)
}
export function AmpIncludeAmpBridPlayer() {
return <AmpIncludeCustomElement name="amp-brid-player" version="0.1" />
}
export function AmpIncludeAmpBrightcove() {
return <AmpIncludeCustomElement name="amp-brightcove" version="0.1" />
}
export function AmpIncludeAmpBysideContent() {
return <AmpIncludeCustomElement name="amp-byside-content" version="0.1" />
}
export function AmpIncludeAmpCallTracking() {
return <AmpIncludeCustomElement name="amp-call-tracking" version="0.1" />
}
export function AmpIncludeAmpCarousel() {
return <AmpIncludeCustomElement name="amp-carousel" version="0.2" />
}
export function AmpIncludeAmpConnatixPlayer() {
return <AmpIncludeCustomElement name="amp-connatix-player" version="0.1" />
}
export function AmpIncludeAmpConsent() {
return <AmpIncludeCustomElement name="amp-consent" version="0.1" />
}
export function AmpIncludeAmpDailymotion() {
return <AmpIncludeCustomElement name="amp-dailymotion" version="0.1" />
}
export function AmpIncludeAmpDateCountdown() {
return <AmpIncludeCustomElement name="amp-date-countdown" version="0.1" />
}
export function AmpIncludeAmpDateDisplay() {
return <AmpIncludeCustomElement name="amp-date-display" version="0.1" />
}
export function AmpIncludeAmpDatePicker() {
return <AmpIncludeCustomElement name="amp-date-picker" version="0.1" />
}
export function AmpIncludeAmpDelightPlayer() {
return <AmpIncludeCustomElement name="amp-delight-player" version="0.1" />
}
export function AmpIncludeAmpDynamicCssClasses() {
return (
<AmpIncludeCustomElement name="amp-dynamic-css-classes" version="0.1" />
)
}
export function AmpIncludeAmpEmbedlyCard() {
return <AmpIncludeCustomElement name="amp-embedly-card" version="0.1" />
}
export function AmpIncludeAmpExperiment() {
return <AmpIncludeCustomElement name="amp-experiment" version="1.0" />
}
export function AmpIncludeAmpFacebookComments() {
return <AmpIncludeCustomElement name="amp-facebook-comments" version="0.1" />
}
export function AmpIncludeAmpFacebookLike() {
return <AmpIncludeCustomElement name="amp-facebook-like" version="0.1" />
}
export function AmpIncludeAmpFacebookPage() {
return <AmpIncludeCustomElement name="amp-facebook-page" version="0.1" />
}
export function AmpIncludeAmpFacebook() {
return <AmpIncludeCustomElement name="amp-facebook" version="0.1" />
}
export function AmpIncludeAmpFitText() {
return <AmpIncludeCustomElement name="amp-fit-text" version="0.1" />
}
export function AmpIncludeAmpFont() {
return <AmpIncludeCustomElement name="amp-font" version="0.1" />
}
export function AmpIncludeAmpForm() {
return <AmpIncludeCustomElement name="amp-form" version="0.1" />
}
export function AmpIncludeAmpFxCollection() {
return <AmpIncludeCustomElement name="amp-fx-collection" version="0.1" />
}
export function AmpIncludeAmpFxFlyingCarpet() {
return <AmpIncludeCustomElement name="amp-fx-flying-carpet" version="0.1" />
}
export function AmpIncludeAmpGeo() {
return <AmpIncludeCustomElement name="amp-geo" version="0.1" />
}
export function AmpIncludeAmpGfycat() {
return <AmpIncludeCustomElement name="amp-gfycat" version="0.1" />
}
export function AmpIncludeAmpGist() {
return <AmpIncludeCustomElement name="amp-gist" version="0.1" />
}
export function AmpIncludeAmpGoogleDocumentEmbed() {
return (
<AmpIncludeCustomElement name="amp-google-document-embed" version="0.1" />
)
}
export function AmpIncludeAmpHulu() {
return <AmpIncludeCustomElement name="amp-hulu" version="0.1" />
}
export function AmpIncludeAmpIframe() {
return <AmpIncludeCustomElement name="amp-iframe" version="0.1" />
}
export function AmpIncludeAmpImaVideo() {
return <AmpIncludeCustomElement name="amp-ima-video" version="0.1" />
}
export function AmpIncludeAmpImageLightbox() {
return <AmpIncludeCustomElement name="amp-image-lightbox" version="0.1" />
}
export function AmpIncludeAmpImageSlider() {
return <AmpIncludeCustomElement name="amp-image-slider" version="0.1" />
}
export function AmpIncludeAmpImgur() {
return <AmpIncludeCustomElement name="amp-imgur" version="0.1" />
}
export function AmpIncludeAmpInputmask() {
return <AmpIncludeCustomElement name="amp-inputmask" version="0.1" />
}
export function AmpIncludeAmpInstagram() {
return <AmpIncludeCustomElement name="amp-instagram" version="0.1" />
}
export function AmpIncludeAmpInstallServiceworker() {
return (
<AmpIncludeCustomElement name="amp-install-serviceworker" version="0.1" />
)
}
export function AmpIncludeAmpIzlesene() {
return <AmpIncludeCustomElement name="amp-izlesene" version="0.1" />
}
export function AmpIncludeAmpJwplayer() {
return <AmpIncludeCustomElement name="amp-jwplayer" version="0.1" />
}
export function AmpIncludeAmpKalturaPlayer() {
return <AmpIncludeCustomElement name="amp-kaltura-player" version="0.1" />
}
export function AmpIncludeAmpLightboxGallery() {
return <AmpIncludeCustomElement name="amp-lightbox-gallery" version="0.1" />
}
export function AmpIncludeAmpLightbox() {
return <AmpIncludeCustomElement name="amp-lightbox" version="0.1" />
}
export function AmpIncludeAmpLinkRewriter() {
return <AmpIncludeCustomElement name="amp-link-rewriter" version="0.1" />
}
export function AmpIncludeAmpList() {
return (
<>
<AmpIncludeAmpMustache />
<AmpIncludeCustomElement name="amp-list" version="0.1" />
</>
)
}
export function AmpIncludeAmpLiveList() {
return <AmpIncludeCustomElement name="amp-live-list" version="0.1" />
}
export function AmpIncludeAmpMathml() {
return <AmpIncludeCustomElement name="amp-mathml" version="0.1" />
}
export function AmpIncludeAmpMegaphone() {
return <AmpIncludeCustomElement name="amp-megaphone" version="0.1" />
}
export function AmpIncludeAmpMinuteMediaPlayer() {
return (
<AmpIncludeCustomElement name="amp-minute-media-player" version="0.1" />
)
}
export function AmpIncludeAmpMowplayer() {
return <AmpIncludeCustomElement name="amp-mowplayer" version="0.1" />
}
export function AmpIncludeAmpMustache() {
return <AmpIncludeCustomTemplate name="amp-mustache" version="0.2" />
}
export function AmpIncludeAmpNextPage() {
return <AmpIncludeCustomElement name="amp-next-page" version="0.1" />
}
export function AmpIncludeAmpNexxtvPlayer() {
return <AmpIncludeCustomElement name="amp-nexxtv-player" version="0.1" />
}
export function AmpIncludeAmpO2Player() {
return <AmpIncludeCustomElement name="amp-o2-player" version="0.1" />
}
export function AmpIncludeAmpOoyalaPlayer() {
return <AmpIncludeCustomElement name="amp-ooyala-player" version="0.1" />
}
export function AmpIncludeAmpOrientationObserver() {
return (
<AmpIncludeCustomElement name="amp-orientation-observer" version="0.1" />
)
}
export function AmpIncludeAmpPanZoom() {
return <AmpIncludeCustomElement name="amp-pan-zoom" version="0.1" />
}
export function AmpIncludeAmpPinterest() {
return <AmpIncludeCustomElement name="amp-pinterest" version="0.1" />
}
export function AmpIncludeAmpPlaybuzz() {
return <AmpIncludeCustomElement name="amp-playbuzz" version="0.1" />
}
export function AmpIncludeAmpPositionObserver() {
return <AmpIncludeCustomElement name="amp-position-observer" version="0.1" />
}
export function AmpIncludeAmpPowrPlayer() {
return <AmpIncludeCustomElement name="amp-powr-player" version="0.1" />
}
export function AmpIncludeAmpReachPlayer() {
return <AmpIncludeCustomElement name="amp-reach-player" version="0.1" />
}
export function AmpIncludeAmpRecaptchaInput() {
return <AmpIncludeCustomElement name="amp-recaptcha-input" version="0.1" />
}
export function AmpIncludeAmpReddit() {
return <AmpIncludeCustomElement name="amp-reddit" version="0.1" />
}
export function AmpIncludeAmpRiddleQuiz() {
return <AmpIncludeCustomElement name="amp-riddle-quiz" version="0.1" />
}
export function AmpIncludeAmpScript() {
return <AmpIncludeCustomElement name="amp-script" version="0.1" />
}
export function AmpIncludeAmpSelector() {
return <AmpIncludeCustomElement name="amp-selector" version="0.1" />
}
export function AmpIncludeAmpSidebar() {
return <AmpIncludeCustomElement name="amp-sidebar" version="0.1" />
}
export function AmpIncludeAmpSkimlinks() {
return <AmpIncludeCustomElement name="amp-skimlinks" version="0.1" />
}
export function AmpIncludeAmpSlides() {
return <AmpIncludeCustomElement name="amp-slides" version="0.1" />
}
export function AmpIncludeAmpSmartlinks() {
return <AmpIncludeCustomElement name="amp-smartlinks" version="0.1" />
}
export function AmpIncludeAmpSocialShare() {
return <AmpIncludeCustomElement name="amp-social-share" version="0.1" />
}
export function AmpIncludeAmpSoundcloud() {
return <AmpIncludeCustomElement name="amp-soundcloud" version="0.1" />
}
export function AmpIncludeAmpSpringboardPlayer() {
return <AmpIncludeCustomElement name="amp-springboard-player" version="0.1" />
}
export function AmpIncludeAmpStickyAd() {
return <AmpIncludeCustomElement name="amp-sticky-ad" version="1.0" />
}
export function AmpIncludeAmpStoryAutoAds() {
return <AmpIncludeCustomElement name="amp-story-auto-ads" version="0.1" />
}
export function AmpIncludeAmpStory() {
return <AmpIncludeCustomElement name="amp-story" version="1.0" />
}
export function AmpIncludeAmpSubscriptions() {
return <AmpIncludeCustomElement name="amp-subscriptions" version="0.1" />
}
export function AmpIncludeAmpSubscriptionsGoogle() {
return (
<AmpIncludeCustomElement name="amp-subscriptions-google" version="0.1" />
)
}
export function AmpIncludeAmpTimeago() {
return <AmpIncludeCustomElement name="amp-timeago" version="0.1" />
}
export function AmpIncludeAmpTruncateText() {
return <AmpIncludeCustomElement name="amp-truncate-text" version="0.1" />
}
export function AmpIncludeAmpTwitter() {
return <AmpIncludeCustomElement name="amp-twitter" version="0.1" />
}
export function AmpIncludeAmpUserLocation() {
return <AmpIncludeCustomElement name="amp-user-location" version="0.1" />
}
export function AmpIncludeAmpUserNotification() {
return <AmpIncludeCustomElement name="amp-user-notification" version="0.1" />
}
export function AmpIncludeAmpVideoDocking() {
return <AmpIncludeCustomElement name="amp-video-docking" version="0.1" />
}
export function AmpIncludeAmpVideoIframe() {
return <AmpIncludeCustomElement name="amp-video-iframe" version="0.1" />
}
export function AmpIncludeAmpVideo() {
return <AmpIncludeCustomElement name="amp-video" version="0.1" />
}
export function AmpIncludeAmpVimeo() {
return <AmpIncludeCustomElement name="amp-vimeo" version="0.1" />
}
export function AmpIncludeAmpVine() {
return <AmpIncludeCustomElement name="amp-vine" version="0.1" />
}
export function AmpIncludeAmpViqeoPlayer() {
return <AmpIncludeCustomElement name="amp-viqeo-player" version="0.1" />
}
export function AmpIncludeAmpVk() {
return <AmpIncludeCustomElement name="amp-vk" version="0.1" />
}
export function AmpIncludeAmpWebPush() {
return <AmpIncludeCustomElement name="amp-web-push" version="0.1" />
}
export function AmpIncludeAmpWistiaPlayer() {
return <AmpIncludeCustomElement name="amp-wistia-player" version="0.1" />
}
export function AmpIncludeAmpYotpo() {
return <AmpIncludeCustomElement name="amp-yotpo" version="0.1" />
}
export function AmpIncludeAmpYoutube() {
return <AmpIncludeCustomElement name="amp-youtube" version="0.1" />
}

View File

@@ -0,0 +1,54 @@
import PropTypes from 'prop-types'
import React from 'react'
import { AmpIncludeAmpScript } from './AmpCustomElement'
/**
* Embeds an AMP Script by either linking to a JS `src` file or embedding inline
* AMP Script via the `script` property. The inline script hash will automatically
* be generated by AMP Optimizer.
*
* @param {Props} props
*/
export default function AmpScript(props) {
return (
<>
<AmpIncludeAmpScript />
<amp-script
layout={props.layout}
width={props.width}
height={props.height}
script={props.id}
src={props.src}
>
{props.children}
</amp-script>
{props.script && (
<script
id={props.id}
type="text/plain"
target="amp-script"
dangerouslySetInnerHTML={{
__html: generateInlineScript(props.script),
}}
/>
)}
</>
)
}
function generateInlineScript(script) {
if (typeof script === 'function') {
return `${script.toString()}()`
}
return String(script)
}
AmpScript.propTypes = {
id: PropTypes.string,
children: PropTypes.node.isRequired,
layout: PropTypes.string.isRequired,
width: PropTypes.string,
height: PropTypes.string,
script: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
src: PropTypes.string,
}

View File

@@ -0,0 +1,33 @@
import PropTypes from 'prop-types'
import React from 'react'
import { AmpIncludeAmpBind } from './AmpCustomElement'
/**
* Renders an amp-state element, by either adding local state via `value`
* or remote state via the `src` property.
*
* @param {Props} props
*/
export default function AmpState(props) {
return (
<>
<AmpIncludeAmpBind />
<amp-state id={props.id} src={props.src}>
{props.children && (
<script
type="application/json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(props.children),
}}
/>
)}
</amp-state>
</>
)
}
AmpState.propTypes = {
id: PropTypes.string.isRequired,
children: PropTypes.any,
src: PropTypes.string,
}

View File

@@ -0,0 +1,15 @@
{
"name": "amp-first",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "^16.10.2",
"react-dom": "^16.10.2"
},
"license": "MIT"
}

View File

@@ -0,0 +1,25 @@
// _document is only rendered on the server side and not on the client side
// Event handlers like onClick can't be added to this file
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument

View File

@@ -0,0 +1,253 @@
import Layout from '../components/Layout'
import AmpState from '../components/amp/AmpState'
import AmpScript from '../components/amp/AmpScript'
import {
AmpIncludeAmpList,
AmpIncludeAmpCarousel,
} from '../components/amp/AmpCustomElement'
export const config = { amp: true }
const Home = (props) => (
<>
<Layout
title="Welcome to AMP"
description="Learn how to build an AMP First with Next.js."
>
<main>
<h1 className="title">Welcome to AMP </h1>
<p className="description">
To get started, edit <code>pages/index.js</code> and save to reload.
</p>
<section className="hero">
<a href="https://nextjs.org/learn/basics/getting-started">
<h3>Getting Started &rarr;</h3>
<p>Learn more about Next</p>
</a>
<a href="https://nextjs.org/docs/advanced-features/amp-support/introduction">
<h3>AMP Support in Next.js &rarr;</h3>
<p>Learn how to build AMP sites with Next.js</p>
</a>
<a href="https://amp.dev/documentation/components/?format=websites">
<h3>AMP Components &rarr;</h3>
<p>See which components are available.</p>
</a>
</section>
<section>
<h3>Using AMP Components</h3>
<p>
You can import AMP components using <code>next/head</code>. Checkout{' '}
<code>components/amp/AmpCustomElement</code> for a simple way to
import AMP components. Once the component is imported, you can use
it like any other HTML element.
</p>
<AmpIncludeAmpCarousel />
<amp-carousel
type="slides"
width="800"
height="300"
layout="responsive"
>
<amp-img
src="https://unsplash.it/800/300?id=123"
layout="fill"
alt="demo image"
/>
<amp-img
src="https://unsplash.it/800/300?id=124"
layout="fill"
alt="demo image"
/>
<amp-img
src="https://unsplash.it/800/300?id=125"
layout="fill"
alt="demo image"
/>
</amp-carousel>
</section>
<section>
<h3>amp-bind & amp-state</h3>
<p>
It's no problem to use <code>amp-bind</code> and{' '}
<code>amp-state</code> with Next.js. There are two things to be
aware of:
<ol>
<li>
The <code>[...]</code> binding syntax{' '}
<code>[text]="myStateVariable"</code>is not supported in JSX.
Use <code>data-amp-bind-text="myStateVariable"</code> instead.
</li>
<li>
Initializing <code>amp-state</code> via JSON string is not
supported in JSX:
<pre>{`<amp-state id="myState">
<script type="application/json">
{
"message": "Hello World"
}
</script>
</amp-state>`}</pre>
Instead you need to use <code>dangerouslySetInnerHTML</code> to
initialize the string. can use the{' '}
<code>/components/amp/AmpState.js</code> component to see how it
works. The same approach works for <code>amp-access</code> and{' '}
<code>amp-consent</code> as well
</li>
</ol>
Demo:
</p>
<AmpState id="myState">
{{
message: 'Hello World',
}}
</AmpState>
<button
on="tap:AMP.setState({
greeting: myState.message
})"
>
Click
</button>
<span data-amp-bind-text="greeting" />
</section>
<section>
<h3>amp-list & amp-mustache</h3>
<p>
Mustache templates conflict with JSX and it's template literals need
to be escaped. A simple approach is to escape them via back ticks:{' '}
<code>src=&#123;`&#123;&#123;imageUrl&#125;&#125;`&#125;</code>.
</p>
<AmpIncludeAmpList />
<amp-list
src="https://amp.dev/documentation/examples/api/photo-stream"
layout="fixed-height"
height="64"
binding="no"
>
<template type="amp-mustache">
<amp-img
src={`{{imageUrl}}`}
width="64"
height="64"
alt="demo image"
/>
</template>
</amp-list>
</section>
<section>
<h3>amp-script</h3>
<p>
Checkout the{' '}
<a href="https://amp.dev/documentation/components/amp-script/">
amp-script
</a>{' '}
helper here: <code>components/amp/AmpScript.js</code> for embedding
custom JavaScript.
</p>
<AmpScript
layout="container"
src={`${props.host}/static/amp-script/hello.js`}
>
<button>Hello amp-script!</button>
</AmpScript>
<p>
The helper also supports embedding inline scripts. Good to know:
Next.js uses{' '}
<a href="https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer">
AMP Optimizer
</a>{' '}
under the hood, which automatically adds the needed script hashes
for{' '}
<a href="https://amp.dev/documentation/components/amp-script/#load-javascript-from-a-local-element">
inline amp-scripts
</a>
.
</p>
<AmpScript
id="hello-world"
layout="fixed-height"
height="64"
script="
const btn = document.querySelector('button');
btn.addEventListener('click', () => {
document.body.textContent = 'Hello World!'
})"
>
<button>Hello amp-script!</button>
</AmpScript>
</section>
</main>
</Layout>
<style jsx>{`
code,
pre {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo,
Courier, monospace;
background: #f2f2f2;
padding: 2px 3px;
font-size: 13px;
}
main {
margin: 0 auto;
max-width: 800px;
}
main > * + * {
margin: 4rem 0.5rem;
}
.title {
text-align: center;
padding-top: 4rem;
}
.hero {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
grid-gap: 1rem;
}
.hero > a {
display: block;
padding: 1rem;
text-align: left;
text-decoration: none;
background-color: #005af0;
}
.hero h3 {
margin: 0;
color: #067df7;
color: #fff;
}
.hero p {
margin: 0;
color: #fff;
}
`}</style>
</>
)
// amp-script requires absolute URLs, so we create a property `host` which we can use to calculate the script URL.
export async function getServerSideProps({ req }) {
// WARNING: This is a generally unsafe application unless you're deploying to a managed platform like Vercel.
// Be sure your load balancer is configured to not allow spoofed host headers.
return { props: { host: `${getProtocol(req)}://${req.headers.host}` } }
}
function getProtocol(req) {
if (req.connection.encrypted) {
return 'https'
}
const forwardedProto = req.headers['x-forwarded-proto']
if (forwardedProto) {
return forwardedProto.split(/\s*,\s*/)[0]
}
return 'http'
}
export default Home

View File

@@ -0,0 +1,12 @@
import Layout from '../components/Layout'
export const config = { amp: true }
const Home = () => (
<Layout title="Offline" description="No internet connection.">
<h1>Offline</h1>
<p>Please try again later.</p>
</Layout>
)
export default Home

View File

@@ -0,0 +1,7 @@
<!DOCTYPE html>
<title>installing service worker</title>
<script type="text/javascript">
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/serviceworker.js')
}
</script>

Some files were not shown because too many files have changed in this diff Show More