Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4068b4493e | ||
|
|
0448535ef0 | ||
|
|
0df6aef3a3 | ||
|
|
5ba2989592 | ||
|
|
9240d86ed6 | ||
|
|
27e0dacdaf | ||
|
|
8dc1cd3ca8 | ||
|
|
413bc01676 | ||
|
|
7c025e9bd7 | ||
|
|
24e51c7ae5 | ||
|
|
b2f84f1224 | ||
|
|
8df18f24ad | ||
|
|
d480d84e46 | ||
|
|
f0a9fbeb14 | ||
|
|
fe8179b595 | ||
|
|
6eaed7a3b2 | ||
|
|
69e97017b1 | ||
|
|
1aa2d79ef4 | ||
|
|
194a3720ce | ||
|
|
e21b22d672 | ||
|
|
b634fe9587 | ||
|
|
9b35fcd018 | ||
|
|
d16ed02a50 | ||
|
|
bdec5cffbf | ||
|
|
be430e093d | ||
|
|
3deb0045f4 | ||
|
|
c19e71624e | ||
|
|
b6fcba1c01 | ||
|
|
dbdb6a4199 | ||
|
|
c151b3571e | ||
|
|
6198025ce5 | ||
|
|
c9dba04f56 | ||
|
|
a2c6c9ce23 | ||
|
|
b09c188113 | ||
|
|
cdd71af1cf | ||
|
|
54647d0054 | ||
|
|
1e39604ae1 | ||
|
|
2f890b72ca | ||
|
|
2a9125def5 | ||
|
|
2111ca6fae | ||
|
|
a640b1112f | ||
|
|
0243df5b6a | ||
|
|
4256f48fa6 | ||
|
|
1c256c9c11 | ||
|
|
e392a37985 | ||
|
|
e2b6dd2779 | ||
|
|
e4e3e757bc | ||
|
|
18438fb45c | ||
|
|
b80cf675b6 | ||
|
|
4db0f32156 | ||
|
|
a63e234ca4 | ||
|
|
5f2bf3ae55 | ||
|
|
da39eca564 | ||
|
|
9fc358b0df | ||
|
|
6e7111397f | ||
|
|
fc66d61f0c | ||
|
|
026d3d84a1 | ||
|
|
bd43af1ba5 | ||
|
|
86be2c122e | ||
|
|
e2a54b5904 | ||
|
|
2c3afcf407 | ||
|
|
f478f83e9d | ||
|
|
4e9968a2db | ||
|
|
5d0998ab84 | ||
|
|
b3f1598212 | ||
|
|
503ec19c66 | ||
|
|
f20d7cf8ec | ||
|
|
81118cd6a0 |
@@ -357,7 +357,8 @@
|
||||
"contributions": [
|
||||
"test",
|
||||
"code",
|
||||
"review"
|
||||
"review",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2411,7 +2412,8 @@
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1384885?v=4",
|
||||
"profile": "www.usertrack.net",
|
||||
"contributions": [
|
||||
"doc"
|
||||
"doc",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2741,7 +2743,9 @@
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6707308?v=4",
|
||||
"profile": "https://github.com/swinner2",
|
||||
"contributions": [
|
||||
"code"
|
||||
"code",
|
||||
"test",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2789,6 +2793,83 @@
|
||||
"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,
|
||||
|
||||
@@ -29,15 +29,14 @@ 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/with-eslint/**
|
||||
/nextjs/examples/with-typescript-eslint-jest/**
|
||||
/nextjs/examples/with-kea/**
|
||||
/nextjs/examples/**
|
||||
/nextjs/packages/next/bundles/webpack/packages/*.runtime.js
|
||||
/nextjs/packages/next/compiled/**/*
|
||||
/nextjs/packages/react-refresh-utils/**/*.js
|
||||
|
||||
13
.eslintrc.js
13
.eslintrc.js
@@ -80,6 +80,19 @@ 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: {
|
||||
|
||||
4
.github/workflows/compressed.yml
vendored
4
.github/workflows/compressed.yml
vendored
@@ -1,11 +1,11 @@
|
||||
name: CI
|
||||
name: Size Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, canary]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.head_ref }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
115
.github/workflows/main.yml
vendored
115
.github/workflows/main.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
types: [opened, synchronize]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.head_ref }}
|
||||
group: ${{ github.workflow }}-${{ github.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-v10-${{ hashFiles('yarn.lock') }}
|
||||
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ runner.node_version}}-yarn-v10-
|
||||
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
|
||||
- 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-v10-${{ hashFiles('yarn.lock') }}
|
||||
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ runner.node_version}}-yarn-v10-
|
||||
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
|
||||
- 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-v10-${{ hashFiles('yarn.lock') }}
|
||||
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ runner.node_version}}-yarn-v10-
|
||||
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
|
||||
- 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]
|
||||
group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
|
||||
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 }}/10 -c 3
|
||||
- run: xvfb-run node run-tests.js --timings -g ${{ matrix.group }}/20 -c 3
|
||||
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||
|
||||
testElectron:
|
||||
@@ -308,95 +308,6 @@ 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:
|
||||
@@ -406,7 +317,7 @@ jobs:
|
||||
needs: build
|
||||
env:
|
||||
HEADLESS: true
|
||||
BROWSERNAME: "firefox"
|
||||
BROWSER_NAME: "firefox"
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
steps:
|
||||
- uses: actions/cache@v2
|
||||
@@ -415,7 +326,7 @@ jobs:
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}
|
||||
- run: node run-tests.js test/integration/production/test/index.test.js
|
||||
- run: node run-tests.js -c 1 test/integration/production/test/index.test.js
|
||||
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||
|
||||
testSafari:
|
||||
@@ -427,7 +338,7 @@ jobs:
|
||||
needs: build
|
||||
env:
|
||||
BROWSERSTACK: true
|
||||
BROWSERNAME: "safari"
|
||||
BROWSER_NAME: "safari"
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
SKIP_LOCAL_SELENIUM_SERVER: true
|
||||
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
|
||||
@@ -439,7 +350,7 @@ jobs:
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}
|
||||
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js test/integration/production/test/index.test.js'
|
||||
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js -c 1 test/integration/production/test/index.test.js'
|
||||
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||
|
||||
testSafariOld:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -30,3 +30,4 @@ examples/auth2
|
||||
db.sqlite-journal
|
||||
test/integration/**/db.json
|
||||
test/**/*/out
|
||||
.blitz**
|
||||
|
||||
@@ -13,10 +13,14 @@
|
||||
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. Resolve all merge conflicts and complete merge
|
||||
5. `git push`
|
||||
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. 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
|
||||
@@ -25,4 +29,7 @@
|
||||
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. Any doc updates?
|
||||
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`
|
||||
|
||||
18
README.md
18
README.md
@@ -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-296-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-304-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></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>
|
||||
</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></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="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></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://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,6 +626,16 @@ 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: 12 KiB After Width: | Height: | Size: 30 KiB |
@@ -1,6 +1,7 @@
|
||||
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>>
|
||||
@@ -25,14 +26,7 @@ export function Form<S extends z.ZodType<any, any>>({
|
||||
return (
|
||||
<FinalForm
|
||||
initialValues={initialValues}
|
||||
validate={(values) => {
|
||||
if (!schema) return
|
||||
try {
|
||||
schema.parse(values)
|
||||
} catch (error) {
|
||||
return error.formErrors.fieldErrors
|
||||
}
|
||||
}}
|
||||
validate={validateZodSchema(schema)}
|
||||
onSubmit={onSubmit}
|
||||
render={({handleSubmit, submitting, submitError}) => (
|
||||
<form onSubmit={handleSubmit} className="form" {...props}>
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
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}
|
||||
resetKeys={[router.asPath]}
|
||||
onReset={reset}
|
||||
>
|
||||
<ErrorBoundary FallbackComponent={RootErrorFallback} onReset={reset}>
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
</ErrorBoundary>
|
||||
<ReactQueryDevtools />
|
||||
|
||||
@@ -10,7 +10,14 @@ import {Routes} from ".blitz"
|
||||
export const EditProject = () => {
|
||||
const router = useRouter()
|
||||
const projectId = useParam("projectId", "number")
|
||||
const [project, {setQueryData}] = useQuery(getProject, {id: projectId})
|
||||
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 [updateProjectMutation] = useMutation(updateProject)
|
||||
|
||||
return (
|
||||
|
||||
@@ -23,7 +23,7 @@ const NewProjectPage: BlitzPage = () => {
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const project = await createProjectMutation(values)
|
||||
router.push(`/projects/${project.id}`)
|
||||
router.push(Routes.ShowProjectPage({projectId: project.id}))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return {
|
||||
|
||||
@@ -12,16 +12,8 @@ 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 {
|
||||
|
||||
@@ -29,17 +29,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "2.24.1",
|
||||
"blitz": "0.37.0",
|
||||
"blitz": "0.38.3-canary.1",
|
||||
"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-01be61c12",
|
||||
"react-dom": "18.0.0-alpha-01be61c12",
|
||||
"react-error-boundary": "3.1.1",
|
||||
"react-final-form": "6.5.2",
|
||||
"zod": "3.0.2"
|
||||
"react": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-final-form": "6.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/skip-test": "2.6.0",
|
||||
@@ -50,7 +48,7 @@
|
||||
"@types/passport-github2": "1.2.4",
|
||||
"@types/passport-twitter": "1.0.36",
|
||||
"@types/preview-email": "2.0.0",
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react": "17.0.13",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "6.2.1",
|
||||
"eslint": "7.21.0",
|
||||
@@ -59,8 +57,7 @@
|
||||
"prettier": "2.2.1",
|
||||
"pretty-quick": "3.1.0",
|
||||
"preview-email": "3.0.3",
|
||||
"start-server-and-test": "1.11.7",
|
||||
"typescript": "4.1.5"
|
||||
"start-server-and-test": "1.11.7"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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>> = {
|
||||
@@ -24,14 +25,7 @@ export function Form<S extends z.ZodType<any, any>>({
|
||||
return (
|
||||
<FinalForm
|
||||
initialValues={initialValues}
|
||||
validate={(values) => {
|
||||
if (!schema) return
|
||||
try {
|
||||
schema.parse(values)
|
||||
} catch (error) {
|
||||
return error.formErrors.fieldErrors
|
||||
}
|
||||
}}
|
||||
validate={validateZodSchema(schema)}
|
||||
onSubmit={onSubmit}
|
||||
render={({handleSubmit, submitting, submitError}) => (
|
||||
<form onSubmit={handleSubmit} className="form" {...props}>
|
||||
|
||||
@@ -1,31 +1,26 @@
|
||||
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}
|
||||
resetKeys={[router.asPath]}
|
||||
onReset={reset}
|
||||
>
|
||||
<ErrorBoundary FallbackComponent={RootErrorFallback} onReset={reset}>
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
function RootErrorFallback({error, resetErrorBoundary}: FallbackProps) {
|
||||
function RootErrorFallback({error, resetErrorBoundary}: ErrorFallbackProps) {
|
||||
if (error instanceof AuthenticationError) {
|
||||
return <LoginForm onSuccess={resetErrorBoundary} />
|
||||
} else if (error instanceof AuthorizationError) {
|
||||
|
||||
@@ -31,22 +31,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "2.24.1",
|
||||
"blitz": "0.37.0",
|
||||
"blitz": "0.38.3-canary.1",
|
||||
"final-form": "4.20.1",
|
||||
"prisma": "2.24.1",
|
||||
"react": "18.0.0-alpha-01be61c12",
|
||||
"react-dom": "18.0.0-alpha-01be61c12",
|
||||
"react-error-boundary": "3.1.1",
|
||||
"react": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-final-form": "6.5.2",
|
||||
"secure-password": "4.0.0",
|
||||
"typescript": "4.1.5",
|
||||
"zod": "3.0.2"
|
||||
"secure-password": "4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/skip-test": "2.6.0",
|
||||
"@testing-library/react": "11.2.5",
|
||||
"@testing-library/react-hooks": "^4.0.1",
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react": "17.0.13",
|
||||
"@types/secure-password": "3.1.0",
|
||||
"cypress": "6.2.1",
|
||||
"eslint": "7.21.0",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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>> = {
|
||||
@@ -24,14 +25,7 @@ export function Form<S extends z.ZodType<any, any>>({
|
||||
return (
|
||||
<FinalForm
|
||||
initialValues={initialValues}
|
||||
validate={(values) => {
|
||||
if (!schema) return
|
||||
try {
|
||||
schema.parse(values)
|
||||
} catch (error) {
|
||||
return error.formErrors.fieldErrors
|
||||
}
|
||||
}}
|
||||
validate={validateZodSchema(schema)}
|
||||
onSubmit={onSubmit}
|
||||
render={({ handleSubmit, submitting, submitError }) => (
|
||||
<form onSubmit={handleSubmit} className="form" {...props}>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { AppProps, ErrorComponent, useRouter, useQueryErrorResetBoundary } from "blitz"
|
||||
import { ErrorBoundary, FallbackProps } from "react-error-boundary"
|
||||
import {
|
||||
AppProps,
|
||||
ErrorBoundary,
|
||||
ErrorFallbackProps,
|
||||
ErrorComponent,
|
||||
useQueryErrorResetBoundary,
|
||||
} from "blitz"
|
||||
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}
|
||||
resetKeys={[router.asPath]}
|
||||
onReset={reset}
|
||||
>
|
||||
<ErrorBoundary FallbackComponent={RootErrorFallback} onReset={reset}>
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
function RootErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
function RootErrorFallback({ error, resetErrorBoundary }: ErrorFallbackProps) {
|
||||
if (error?.name === "AuthenticationError") {
|
||||
return <LoginForm onSuccess={resetErrorBoundary} />
|
||||
} else if (error?.name === "AuthorizationError") {
|
||||
|
||||
@@ -28,33 +28,29 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"blitz": "0.37.0",
|
||||
"blitz": "0.38.3-canary.1",
|
||||
"final-form": "4.20.1",
|
||||
"graphql": "15.5.0",
|
||||
"graphql-request": "3.4.0",
|
||||
"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"
|
||||
"react": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-final-form": "6.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/react": "11.2.5",
|
||||
"@testing-library/react-hooks": "^4.0.1",
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react": "17.0.13",
|
||||
"@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",
|
||||
"typescript": "4.1.5"
|
||||
"start-server-and-test": "1.11.7"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -26,27 +26,26 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"blitz": "0.37.0",
|
||||
"blitz": "0.38.3-canary.1",
|
||||
"knex": "0.21.16",
|
||||
"react": "18.0.0-alpha-01be61c12",
|
||||
"react-dom": "18.0.0-alpha-01be61c12",
|
||||
"react": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"sqlite3": "5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react": "17.0.13",
|
||||
"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",
|
||||
"typescript": "4.1.5"
|
||||
"pretty-quick": "3.1.0"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "2.24.1",
|
||||
"blitz": "0.37.0",
|
||||
"blitz": "0.38.3-canary.1",
|
||||
"prisma": "2.24.1",
|
||||
"react": "18.0.0-alpha-01be61c12",
|
||||
"react-dom": "18.0.0-alpha-01be61c12"
|
||||
"react": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-dom": "18.0.0-alpha-ed6c091fe-20210701"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "~10.1.0",
|
||||
@@ -44,14 +44,13 @@
|
||||
"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",
|
||||
"typescript": "4.1.5"
|
||||
"pretty-quick": "3.1.0"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
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}
|
||||
resetKeys={[router.asPath]}
|
||||
onReset={reset}
|
||||
>
|
||||
<ErrorBoundary FallbackComponent={RootErrorFallback} onReset={reset}>
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
</ErrorBoundary>
|
||||
)
|
||||
|
||||
@@ -33,19 +33,16 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "2.24.1",
|
||||
"blitz": "0.37.0",
|
||||
"blitz": "0.38.3-canary.1",
|
||||
"final-form": "4.20.1",
|
||||
"prisma": "2.24.1",
|
||||
"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"
|
||||
"react": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-final-form": "6.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/preview-email": "2.0.0",
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react": "17.0.13",
|
||||
"eslint": "7.21.0",
|
||||
"husky": "5.1.2",
|
||||
"lint-staged": "10.5.4",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ["blitz"],
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import {AppProps, ErrorComponent, useQueryErrorResetBoundary} from "blitz"
|
||||
import {ErrorBoundary} from "react-error-boundary"
|
||||
import {AppProps, ErrorBoundary, ErrorComponent, useQueryErrorResetBoundary} from "blitz"
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window["DEBUG_BLITZ"] = 1
|
||||
|
||||
@@ -21,19 +21,16 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "2.24.1",
|
||||
"blitz": "0.37.0",
|
||||
"blitz": "0.38.3-canary.1",
|
||||
"final-form": "4.20.1",
|
||||
"prisma": "2.24.1",
|
||||
"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"
|
||||
"react": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
|
||||
"react-final-form": "6.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react": "17.0.13",
|
||||
"cypress": "6.2.1",
|
||||
"eslint-plugin-cypress": "~2.11.2",
|
||||
"start-server-and-test": "1.11.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "0.37.0",
|
||||
"version": "0.38.3-canary.1",
|
||||
"packages": ["packages/*"],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
|
||||
4
nextjs/.alexignore
Normal file
4
nextjs/.alexignore
Normal file
@@ -0,0 +1,4 @@
|
||||
CODE_OF_CONDUCT.md
|
||||
docs/
|
||||
errors/
|
||||
examples/
|
||||
@@ -1,8 +1,8 @@
|
||||
FROM node:10-buster
|
||||
FROM node:14-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/zeit/next-stats-action"
|
||||
LABEL repository="https://github.com/vercel/next-stats-action"
|
||||
|
||||
COPY . /next-stats
|
||||
|
||||
|
||||
54
nextjs/.github/workflows/build_test_deploy.yml
vendored
54
nextjs/.github/workflows/build_test_deploy.yml
vendored
@@ -156,15 +156,15 @@ jobs:
|
||||
steps:
|
||||
- run: exit 0
|
||||
|
||||
testFutureDependencies:
|
||||
name: Webpack 5 (Basic, Production, Acceptance)
|
||||
testLegacyWebpack:
|
||||
name: Webpack 4 (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
|
||||
NEXT_PRIVATE_TEST_WEBPACK4_MODE: 1
|
||||
|
||||
steps:
|
||||
- uses: actions/cache@v2
|
||||
@@ -174,50 +174,16 @@ jobs:
|
||||
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
|
||||
- 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
|
||||
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
|
||||
BROWSERNAME: 'firefox'
|
||||
BROWSER_NAME: 'firefox'
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
steps:
|
||||
- uses: actions/cache@v2
|
||||
@@ -226,7 +192,7 @@ jobs:
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}
|
||||
- run: node run-tests.js test/integration/production/test/index.test.js
|
||||
- run: node run-tests.js -c 1 test/integration/production/test/index.test.js
|
||||
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||
|
||||
testSafari:
|
||||
@@ -235,7 +201,7 @@ jobs:
|
||||
needs: build
|
||||
env:
|
||||
BROWSERSTACK: true
|
||||
BROWSERNAME: 'safari'
|
||||
BROWSER_NAME: 'safari'
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
SKIP_LOCAL_SELENIUM_SERVER: true
|
||||
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
|
||||
@@ -247,7 +213,7 @@ jobs:
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}
|
||||
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js test/integration/production/test/index.test.js'
|
||||
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js -c 1 test/integration/production/test/index.test.js'
|
||||
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||
|
||||
testSafariOld:
|
||||
@@ -257,7 +223,7 @@ jobs:
|
||||
env:
|
||||
BROWSERSTACK: true
|
||||
LEGACY_SAFARI: true
|
||||
BROWSERNAME: 'safari'
|
||||
BROWSER_NAME: 'safari'
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
SKIP_LOCAL_SELENIUM_SERVER: true
|
||||
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
|
||||
@@ -269,7 +235,7 @@ jobs:
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}
|
||||
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js test/integration/production-nav/test/index.test.js'
|
||||
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js -c 1 test/integration/production-nav/test/index.test.js'
|
||||
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
|
||||
|
||||
publishRelease:
|
||||
|
||||
1
nextjs/.github/workflows/test_react_next.yml
vendored
1
nextjs/.github/workflows/test_react_next.yml
vendored
@@ -26,6 +26,7 @@ jobs:
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
HEADLESS: true
|
||||
NEXT_PRIVATE_SKIP_SIZE_TESTS: true
|
||||
NEXT_PRIVATE_REACT_ROOT: 1
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = git@github.com:blitz-js/next.js.git
|
||||
branch = canary
|
||||
commit = 9d5938e8f444bfd2bb5e6cb69f48a868386a9e05
|
||||
parent = c5b461c641f1764f8ba71f1e4d7c5cca0b405a28
|
||||
commit = 4be32b7a54fa68dfcf66d4a5cc7744409c409c7f
|
||||
parent = 194a3720ce56aa3fabace4b07c5faeac1121b8d6
|
||||
method = merge
|
||||
cmdver = 0.4.3
|
||||
|
||||
@@ -117,13 +117,13 @@ stages:
|
||||
vmImage: 'windows-2019'
|
||||
strategy:
|
||||
matrix:
|
||||
node-10-1:
|
||||
nodejs-1:
|
||||
group: 1/4
|
||||
node-10-2:
|
||||
nodejs-2:
|
||||
group: 2/4
|
||||
node-10-3:
|
||||
nodejs-3:
|
||||
group: 3/4
|
||||
node-10-4:
|
||||
nodejs-4:
|
||||
group: 4/4
|
||||
steps:
|
||||
- checkout: none
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const http = require('http')
|
||||
const fs = require('fs')
|
||||
import { createServer } from 'http'
|
||||
import { writeFileSync } from 'fs'
|
||||
|
||||
const PORT = 9411
|
||||
const HOST = '0.0.0.0'
|
||||
@@ -53,11 +53,11 @@ const main = () => {
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
console.log(`\nSaving to ${outFile}...`)
|
||||
fs.writeFileSync(outFile, JSON.stringify(traces, null, 2))
|
||||
writeFileSync(outFile, JSON.stringify(traces, null, 2))
|
||||
process.exit()
|
||||
})
|
||||
|
||||
const server = http.createServer(onRequest)
|
||||
const server = createServer(onRequest)
|
||||
server.listen(PORT, HOST, onReady)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"bench:recursive-copy": "node recursive-copy/run"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": "7.0.1",
|
||||
"recursive-copy": "2.0.10"
|
||||
"fs-extra": "10.0.0",
|
||||
"recursive-copy": "2.0.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const { join } = require('path')
|
||||
const { promisify } = require('util')
|
||||
const globMod = require('glob')
|
||||
import { join } from 'path'
|
||||
import { promisify } from 'util'
|
||||
import globMod from 'glob'
|
||||
|
||||
const glob = promisify(globMod)
|
||||
const resolveDataDir = join(__dirname, 'fixtures', '**/*')
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { join } = require('path')
|
||||
const { recursiveReadDir } = require('next/dist/lib/recursive-readdir')
|
||||
import { join } from 'path'
|
||||
import { recursiveReadDir } from 'next/dist/lib/recursive-readdir'
|
||||
const resolveDataDir = join(__dirname, 'fixtures')
|
||||
|
||||
async function test() {
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
const { join } = require('path')
|
||||
const fs = require('fs-extra')
|
||||
|
||||
const recursiveCopyNpm = require('recursive-copy')
|
||||
|
||||
const {
|
||||
recursiveCopy: recursiveCopyCustom,
|
||||
} = require('next/dist/lib/recursive-copy')
|
||||
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 fixturesDir = join(__dirname, 'fixtures')
|
||||
const srcDir = join(fixturesDir, 'src')
|
||||
const destDir = join(fixturesDir, 'dest')
|
||||
|
||||
const createSrcFolder = async () => {
|
||||
await fs.ensureDir(srcDir)
|
||||
await ensureDir(srcDir)
|
||||
|
||||
const files = new Array(100)
|
||||
.fill(undefined)
|
||||
@@ -20,7 +16,7 @@ const createSrcFolder = async () => {
|
||||
join(srcDir, `folder${i % 5}`, `folder${i + (1 % 5)}`, `file${i}`)
|
||||
)
|
||||
|
||||
await Promise.all(files.map((file) => fs.outputFile(file, 'hello')))
|
||||
await Promise.all(files.map((file) => outputFile(file, 'hello')))
|
||||
}
|
||||
|
||||
async function run(fn) {
|
||||
@@ -38,7 +34,7 @@ async function run(fn) {
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const t = await test()
|
||||
await fs.remove(destDir)
|
||||
await remove(destDir)
|
||||
ts.push(t)
|
||||
}
|
||||
|
||||
@@ -57,7 +53,7 @@ async function main() {
|
||||
console.log('test recursive-copy custom implementation')
|
||||
await run(recursiveCopyCustom)
|
||||
|
||||
await fs.remove(fixturesDir)
|
||||
await remove(fixturesDir)
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { join } = require('path')
|
||||
const { recursiveDelete } = require('next/dist/lib/recursive-delete')
|
||||
import { join } from 'path'
|
||||
import { recursiveDelete } from 'next/dist/lib/recursive-delete'
|
||||
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`)
|
||||
|
||||
async function test() {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const { join } = require('path')
|
||||
const { promisify } = require('util')
|
||||
const rimrafMod = require('rimraf')
|
||||
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`, '**/*')
|
||||
import { join } from 'path'
|
||||
import { promisify } from 'util'
|
||||
import rimrafMod from 'rimraf'
|
||||
|
||||
const rimraf = promisify(rimrafMod)
|
||||
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`, '**/*')
|
||||
|
||||
async function test() {
|
||||
const time = process.hrtime()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contributing to Next.js
|
||||
|
||||
Our Commitment to Open Source can be found [here](https://vercel.com/oss).
|
||||
Read about our [Commitment to Open Source](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 just one test in the `production` test suite:
|
||||
Running one test in the `production` test suite:
|
||||
|
||||
```sh
|
||||
yarn testonly --testPathPattern "production" -t "should allow etag header support"
|
||||
@@ -124,12 +124,19 @@ When you add an example to the [examples](examples) directory, don’t 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 can’t 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/):
|
||||
|
||||
[](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):
|
||||
|
||||
@@ -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 the custom types described [here](https://stackoverflow.com/a/50601125).
|
||||
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).
|
||||
|
||||
@@ -17,6 +17,14 @@ 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`
|
||||
|
||||
@@ -52,6 +52,9 @@ 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,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -175,7 +175,7 @@ export function reportWebVitals(metric) {
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> Read more about sending results to Google Analytics [here](https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics).
|
||||
> Read more about [sending results to Google Analytics](https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics).
|
||||
|
||||
## TypeScript
|
||||
|
||||
|
||||
139
nextjs/docs/advanced-features/security-headers.md
Normal file
139
nextjs/docs/advanced-features/security-headers.md
Normal file
@@ -0,0 +1,139 @@
|
||||
---
|
||||
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>
|
||||
@@ -21,7 +21,7 @@ Usage
|
||||
$ next <command>
|
||||
|
||||
Available commands
|
||||
build, start, export, dev, telemetry
|
||||
build, start, export, dev, lint, telemetry
|
||||
|
||||
Options
|
||||
--version, -v Version number
|
||||
@@ -74,6 +74,20 @@ 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.
|
||||
@@ -84,6 +98,27 @@ 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.
|
||||
|
||||
@@ -12,13 +12,22 @@ 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 to run `yarn create next-app`
|
||||
- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend running `yarn create next-app`
|
||||
|
||||
### Why use Create Next App?
|
||||
|
||||
|
||||
@@ -24,9 +24,21 @@ 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).
|
||||
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:
|
||||
|
||||
Asset prefix support does not influence the following paths:
|
||||
```
|
||||
/_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:
|
||||
|
||||
- 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.
|
||||
|
||||
@@ -373,3 +373,14 @@ 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>
|
||||
|
||||
39
nextjs/docs/api-reference/next.config.js/ignoring-eslint.md
Normal file
39
nextjs/docs/api-reference/next.config.js/ignoring-eslint.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
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>
|
||||
@@ -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 [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`:
|
||||
`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`:
|
||||
|
||||
```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 [here](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 in this file](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.
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ module.exports = {
|
||||
// and dynamic routes are checked
|
||||
{
|
||||
source: '/:path*',
|
||||
destination: 'https://my-old-site.com',
|
||||
destination: `https://my-old-site.com/:path*`,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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 it [here](/docs/advanced-features/amp-support/introduction.md).
|
||||
> AMP support is one of our advanced features, you can [read more about AMP here](/docs/advanced-features/amp-support/introduction.md).
|
||||
|
||||
To enable AMP, add the following config to your page:
|
||||
|
||||
|
||||
@@ -14,11 +14,12 @@ description: Enable Image Optimization with the built-in Image component.
|
||||
<details>
|
||||
<summary><b>Version History</b></summary>
|
||||
|
||||
| Version | Changes |
|
||||
| --------- | ------------------------ |
|
||||
| `v10.0.5` | `loader` prop added. |
|
||||
| `v10.0.1` | `layout` prop added. |
|
||||
| `v10.0.0` | `next/image` introduced. |
|
||||
| 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. |
|
||||
|
||||
</details>
|
||||
|
||||
@@ -39,17 +40,13 @@ 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="/me.png"
|
||||
alt="Picture of the author"
|
||||
width={500}
|
||||
height={500}
|
||||
/>
|
||||
<Image src={profilePic} alt="Picture of the author" />
|
||||
<p>Welcome to my homepage!</p>
|
||||
</>
|
||||
)
|
||||
@@ -64,7 +61,11 @@ The `<Image />` component requires the following properties.
|
||||
|
||||
### src
|
||||
|
||||
The path or URL to the source image. This is required.
|
||||
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).
|
||||
|
||||
When using an external URL, you must add it to
|
||||
[domains](/docs/basic-features/image-optimization.md#domains) in
|
||||
@@ -74,13 +75,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 unless [`layout="fill"`](#layout).
|
||||
Required, except for statically imported images, or those with [`layout="fill"`](#layout).
|
||||
|
||||
### height
|
||||
|
||||
The height of the image, in pixels. Must be an integer without a unit.
|
||||
|
||||
Required unless [`layout="fill"`](#layout).
|
||||
Required, except for statically imported images, or those with [`layout="fill"`](#layout).
|
||||
|
||||
## Optional Props
|
||||
|
||||
@@ -132,7 +133,7 @@ const MyImage = (props) => {
|
||||
return (
|
||||
<Image
|
||||
loader={myLoader}
|
||||
src="/me.png"
|
||||
src="me.png"
|
||||
alt="Picture of the author"
|
||||
width={500}
|
||||
height={500}
|
||||
@@ -162,6 +163,21 @@ 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
|
||||
@@ -196,6 +212,22 @@ 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,
|
||||
|
||||
@@ -49,6 +49,7 @@ The following is the definition of the `router` object returned by both [`useRou
|
||||
- `locale`: `String` - The active locale (if enabled).
|
||||
- `locales`: `String[]` - All supported locales (if enabled).
|
||||
- `defaultLocale`: `String` - The current default locale (if enabled).
|
||||
- `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).
|
||||
|
||||
@@ -112,6 +113,8 @@ 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
|
||||
|
||||
@@ -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 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)
|
||||
- `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)
|
||||
|
||||
To handle different HTTP methods in an API route, you can use `req.method` in your request handler, like so:
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ const Profile = () => {
|
||||
export default Profile
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
### Authenticating Server-Rendered Pages
|
||||
|
||||
@@ -127,77 +127,23 @@ 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)
|
||||
|
||||
### Firebase
|
||||
### Other Providers
|
||||
|
||||
To see examples with other authentication providers, check out the [examples folder](https://github.com/vercel/next.js/tree/canary/examples).
|
||||
|
||||
<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>
|
||||
</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>
|
||||
<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>
|
||||
|
||||
[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:
|
||||
|
||||
175
nextjs/docs/basic-features/eslint.md
Normal file
175
nextjs/docs/basic-features/eslint.md
Normal file
@@ -0,0 +1,175 @@
|
||||
---
|
||||
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 <img> 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 <title> 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.
|
||||
@@ -50,6 +50,39 @@ 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
|
||||
@@ -138,6 +171,22 @@ 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:
|
||||
|
||||
129
nextjs/docs/basic-features/script.md
Normal file
129
nextjs/docs/basic-features/script.md
Normal file
@@ -0,0 +1,129 @@
|
||||
---
|
||||
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"
|
||||
/>
|
||||
```
|
||||
@@ -11,9 +11,23 @@ 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.
|
||||
|
||||
To get started, create an empty `tsconfig.json` file in the root of your project:
|
||||
## `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:
|
||||
|
||||
```bash
|
||||
touch tsconfig.json
|
||||
@@ -149,4 +163,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.0-beta` of TypeScript to experience the best performance when leveraging this feature.
|
||||
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.
|
||||
|
||||
@@ -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/getting-started).
|
||||
If you're new to Next.js we recommend that you start with the [learn course](https://nextjs.org/learn/basics/create-nextjs-app).
|
||||
|
||||
The interactive course with quizzes will guide you through everything you need to know to use Next.js.
|
||||
|
||||
@@ -55,7 +55,8 @@ Open `package.json` and add the following `scripts`:
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -64,6 +65,7 @@ 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.
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
"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"
|
||||
@@ -48,6 +52,10 @@
|
||||
{
|
||||
"title": "Supported Browsers and Features",
|
||||
"path": "/docs/basic-features/supported-browsers-features.md"
|
||||
},
|
||||
{
|
||||
"title": "Script",
|
||||
"path": "/docs/basic-features/script.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -200,6 +208,10 @@
|
||||
{
|
||||
"title": "Internationalized Routing",
|
||||
"path": "/docs/advanced-features/i18n-routing.md"
|
||||
},
|
||||
{
|
||||
"title": "Security Headers",
|
||||
"path": "/docs/advanced-features/security-headers.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -340,6 +352,10 @@
|
||||
"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"
|
||||
|
||||
@@ -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/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).
|
||||
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).
|
||||
|
||||
@@ -4,6 +4,133 @@ 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.
|
||||
@@ -15,7 +142,13 @@ There were no breaking changes between version 9 and 10.
|
||||
To upgrade run the following command:
|
||||
|
||||
```
|
||||
npm install next@latest
|
||||
npm install next@10
|
||||
```
|
||||
|
||||
Or using `yarn`:
|
||||
|
||||
```
|
||||
yarn add next@10
|
||||
```
|
||||
|
||||
## Upgrading from version 8 to 9
|
||||
|
||||
14
nextjs/errors/client-side-exception-occurred.md
Normal file
14
nextjs/errors/client-side-exception-occurred.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# 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)
|
||||
33
nextjs/errors/future-webpack5-moved-to-webpack5.md
Normal file
33
nextjs/errors/future-webpack5-moved-to-webpack5.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# `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,
|
||||
}
|
||||
```
|
||||
36
nextjs/errors/link-multiple-children.md
Normal file
36
nextjs/errors/link-multiple-children.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# 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>
|
||||
)
|
||||
}
|
||||
```
|
||||
@@ -373,7 +373,28 @@
|
||||
"path": "/errors/undefined-webpack-config.md"
|
||||
},
|
||||
{ "title": "url-deprecated", "path": "/errors/url-deprecated.md" },
|
||||
{ "title": "webpack5", "path": "/errors/webpack5.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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
### Why This Error Occurred
|
||||
|
||||
`next/document` was imported in a page outside of `pages/_document.js`. This can cause unexpected issues in your application.
|
||||
`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.
|
||||
|
||||
### Possible Ways to Fix It
|
||||
|
||||
Only import and use `next/document` within `pages/_document.js` to override the default `Document` component:
|
||||
Only import and use `next/document` within `pages/_document.js` (or `pages/_document.tsx`) to override the default `Document` component:
|
||||
|
||||
```jsx
|
||||
// pages/_document.js
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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/experimental-script'
|
||||
import Script from 'next/script'
|
||||
|
||||
const Home = () => {
|
||||
return (
|
||||
@@ -25,8 +25,6 @@ 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/)
|
||||
|
||||
15
nextjs/errors/placeholder-blur-data-url.md
Normal file
15
nextjs/errors/placeholder-blur-data-url.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# `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
|
||||
@@ -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](https://nextjs.org/docs/advanced-features/customizing-postcss-config) about how to use them [here](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).
|
||||
|
||||
@@ -39,7 +39,7 @@ module.exports = {
|
||||
}
|
||||
```
|
||||
|
||||
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).
|
||||
You can [read more about configuring PostCSS in Next.js here](https://nextjs.org/docs/advanced-features/customizing-postcss-config).
|
||||
|
||||
#### Common Errors
|
||||
|
||||
|
||||
@@ -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.1` and `react-dom@17.0.1`.
|
||||
Next.js suggests using, at a minimum, `react@17.0.2` and `react-dom@17.0.2`.
|
||||
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.1",
|
||||
"react-dom": "^17.0.1"
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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://github.com/zeit/next-codemod#url-to-withrouter
|
||||
https://nextjs.org/docs/advanced-features/codemods#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://github.com/zeit/next-codemod#url-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
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
#### Why This Message Occurred
|
||||
|
||||
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`:
|
||||
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`:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
future: {
|
||||
webpack5: true,
|
||||
},
|
||||
// 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,
|
||||
}
|
||||
```
|
||||
|
||||
Adopting webpack 5 in your application has many benefits, notably:
|
||||
Using 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,11 +22,13 @@ Adopting 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 upcoming releases we'll gradually roll out webpack 5 to applications that are compatible with webpack 5:
|
||||
In the past releases we have gradually rolled out webpack 5 to Next.js applications:
|
||||
|
||||
- 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
|
||||
- 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.
|
||||
|
||||
#### Custom webpack configuration
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# 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):
|
||||
|
||||
[](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)).
|
||||
@@ -1,32 +0,0 @@
|
||||
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
|
||||
@@ -1,34 +0,0 @@
|
||||
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
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
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
|
||||
@@ -1,10 +0,0 @@
|
||||
import Nav from '../components/Nav'
|
||||
|
||||
const AboutPage = () => (
|
||||
<>
|
||||
<Nav />
|
||||
<p>Hello, I'm the about page</p>
|
||||
</>
|
||||
)
|
||||
|
||||
export default AboutPage
|
||||
@@ -1,10 +0,0 @@
|
||||
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
34
nextjs/examples/amp-first/.gitignore
vendored
@@ -1,34 +0,0 @@
|
||||
# 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
|
||||
@@ -1,79 +0,0 @@
|
||||
# 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):
|
||||
|
||||
[](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)).
|
||||
@@ -1,54 +0,0 @@
|
||||
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
|
||||
@@ -1,531 +0,0 @@
|
||||
/**
|
||||
* @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" />
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
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,
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
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,
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// _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
|
||||
@@ -1,253 +0,0 @@
|
||||
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 →</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 →</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 →</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={`{{imageUrl}}`}</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
|
||||
@@ -1,12 +0,0 @@
|
||||
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
|
||||
@@ -1,7 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<title>installing service worker</title>
|
||||
<script type="text/javascript">
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/serviceworker.js')
|
||||
}
|
||||
</script>
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"short_name": "My page",
|
||||
"name": "My fantastic page",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/static/images/icons-192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "/static/images/icons-512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"display": "standalone",
|
||||
"scope": "/",
|
||||
"theme_color": "#005af0",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user