1
0
mirror of synced 2026-02-03 18:01:02 -05:00

Compare commits

...

24 Commits

Author SHA1 Message Date
Brandon Bayer
847b41f2be more test fixes 2021-03-16 19:06:09 -04:00
Brandon Bayer
3c68f600c1 fix more tests 2021-03-16 18:51:18 -04:00
Brandon Bayer
6d225f7b10 git subrepo push nextjs
subrepo:
  subdir:   "nextjs"
  merged:   "9808a42f5"
upstream:
  origin:   "git@github.com:blitz-js/next.js.git"
  branch:   "canary"
  commit:   "9808a42f5"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"
2021-03-16 18:16:46 -04:00
Brandon Bayer
83fd77f1f2 fixing nextjs tests 2021-03-16 18:16:09 -04:00
Brandon Bayer
59fe8e0c7d fix ci 2021-03-16 17:32:04 -04:00
Brandon Bayer
8967281015 try ci fixes 2021-03-16 17:31:04 -04:00
Brandon Bayer
00490e17fb nextjs build working again 2021-03-16 16:29:19 -04:00
Brandon Bayer
b9a2133bb3 git subrepo pull (merge) nextjs
subrepo:
  subdir:   "nextjs"
  merged:   "09ffbef7d"
upstream:
  origin:   "git@github.com:blitz-js/next.js.git"
  branch:   "canary"
  commit:   "09ffbef7d"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"
2021-03-16 16:20:46 -04:00
Brandon Bayer
5ae016dc3f git subrepo push nextjs
subrepo:
  subdir:   "nextjs"
  merged:   "1c5e93ddc"
upstream:
  origin:   "git@github.com:blitz-js/next.js.git"
  branch:   "canary"
  commit:   "1c5e93ddc"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"
2021-03-16 16:13:40 -04:00
Brandon Bayer
9dbb6db245 Merge branch 'canary' into forking 2021-03-16 16:13:20 -04:00
Brandon Bayer
c36cbbcbb3 yml fix 2021-03-16 16:03:37 -04:00
Brandon Bayer
7ecb67b4df work on nextjs gh action 2021-03-16 15:49:02 -04:00
Brandon Bayer
04ebd34223 update gh action 2021-03-16 15:37:57 -04:00
Brandon Bayer
cc68f99f48 add nextjs gh workflow 2021-03-16 15:35:42 -04:00
Brandon Bayer
08d74f098c Merge branch 'canary' into forking 2021-03-16 15:33:08 -04:00
Brandon Bayer
1ff8a1dd36 nextjs tests working 2021-03-16 15:31:21 -04:00
Brandon Bayer
fc8d697d81 Merge branch 'canary' into forking 2021-03-16 14:41:10 -04:00
Brandon Bayer
1d2f2acdc8 fix linting & enable linting of nextjs code 2021-03-08 19:44:40 -05:00
Brandon Bayer
fdd93c43cd fix nextjs build 2021-03-08 19:10:54 -05:00
Brandon Bayer
0cf81d05d7 Merge branch 'canary' into forking 2021-03-08 18:39:22 -05:00
Brandon Bayer
68307b7159 upgrade typescript 2021-03-08 18:38:07 -05:00
Brandon Bayer
4b12379a2b get nextjs building 2021-03-06 20:10:17 -05:00
Brandon Bayer
6e247a4e69 downgrade some package version to match existing nextjs versions 2021-03-06 20:05:45 -05:00
Brandon Bayer
d6bf079c87 integrate nextjs into yarn workspaces 2021-03-06 18:52:15 -05:00
390 changed files with 164077 additions and 126011 deletions

View File

@@ -1,4 +1,3 @@
lib
node_modules
reports
*.log
@@ -26,6 +25,27 @@ eslint.config.*
/scripts
/types
/recipes/*/templates
packages/generator/templates
/packages/generator/templates
/packages/cli/lib
/nextjs
// COPIED FROM nextjs/.eslintignore
/nextjs/**/.next/**
/nextjs/**/_next/**
/nextjs/**/dist/**
/nextjs/examples/with-typescript-eslint-jest/**
/nextjs/examples/with-kea/**
/nextjs/packages/next/bundles/webpack/packages/*.runtime.js
/nextjs/packages/next/compiled/**/*
/nextjs/packages/react-refresh-utils/**/*.js
/nextjs/packages/react-dev-overlay/lib/**
/nextjs/**/__tmp__/**
/nextjs/.github/actions/next-stats-action/.work
/nextjs/packages/next-codemod/transforms/__testfixtures__/**/*
/nextjs/packages/next-codemod/transforms/__tests__/**/*
/nextjs/packages/next-codemod/**/*.js
/nextjs/packages/next-codemod/**/*.d.ts
/nextjs/packages/next-env/**/*.d.ts
/nextjs/test/integration/async-modules/**
/nextjs/test-timings.json

View File

@@ -1,4 +1,4 @@
name: CI
name: Blitz
on:
push:
@@ -52,14 +52,13 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node_version: [12, 15]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node_version }}
node-version: "15"
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"

270
.github/workflows/nextjs.yml vendored Normal file
View File

@@ -0,0 +1,270 @@
name: Nextjs
defaults:
run:
working-directory: nextjs
on:
push:
branches: [canary]
pull_request:
types: [opened, synchronize]
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./
env:
NEXT_TELEMETRY_DISABLED: 1
outputs:
docsChange: ${{ steps.docs-change.outputs.DOCS_CHANGE }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 25
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- run: yarn install --frozen-lockfile --check-files
- run: yarn workspace @blitzjs/next prepublish
- run: node run-tests.js --timings --write-timings -g 1/1
working-directory: nextjs
- name: Check docs only change
working-directory: nextjs
run: echo ::set-output name=DOCS_CHANGE::$(node skip-docs-change.js echo 'not-docs-only-change')
id: docs-change
- run: echo ${{steps.docs-change.outputs.DOCS_CHANGE}}
- uses: actions/cache@v2
id: cache-build
with:
path: ./*
key: ${{ github.sha }}
checkPrecompiled:
name: Check Pre-compiled
runs-on: ubuntu-latest
needs: build
env:
NEXT_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ github.sha }}
- run: ./check-pre-compiled.sh
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testUnit:
name: Test Unit
runs-on: ubuntu-latest
needs: build
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ github.sha }}
- run: node run-tests.js --timings --type unit -g 1/1
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testIntegration:
name: Test Integration
runs-on: ubuntu-latest
needs: build
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
strategy:
fail-fast: false
matrix:
group: [1, 2, 3, 4, 5, 6]
steps:
- run: echo ${{needs.build.outputs.docsChange}}
working-directory: ./
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ github.sha }}
# TODO: remove after we fix watchpack watching too much
- 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 }}/6 -c 3
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testElectron:
name: Test Electron
runs-on: ubuntu-latest
needs: build
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
TEST_ELECTRON: 1
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ github.sha }}
# TODO: remove after we fix watchpack watching too much
- 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: yarn add -W --dev spectron@7.0.0 electron@5.0.0
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
working-directory: ./
- run: xvfb-run node run-tests.js test/integration/with-electron/test/index.test.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testsPass:
name: thank you, next
runs-on: ubuntu-latest
needs: [checkPrecompiled, testIntegration, testUnit]
steps:
- run: exit 0
testFutureDependencies:
name: Webpack 5 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./
env:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
NEXT_PRIVATE_TEST_WEBPACK5_MODE: 1
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: yarn install --check-files
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
- 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: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
working-directory: nextjs
testLegacyReact:
name: React 16 + Webpack 4 (Basic, Production, Acceptance)
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./
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' }}
working-directory: nextjs
testFirefox:
name: Test Firefox (production)
runs-on: ubuntu-latest
needs: build
env:
HEADLESS: true
BROWSERNAME: "firefox"
NEXT_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ github.sha }}
- run: node run-tests.js test/integration/production/test/index.test.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testSafari:
name: Test Safari (production)
runs-on: ubuntu-latest
needs: build
env:
BROWSERSTACK: true
BROWSERNAME: "safari"
NEXT_TELEMETRY_DISABLED: 1
SKIP_LOCAL_SELENIUM_SERVER: true
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
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'
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testSafariOld:
name: Test Safari 10.1 (nav)
runs-on: ubuntu-latest
needs: [build, testSafari]
env:
BROWSERSTACK: true
LEGACY_SAFARI: true
BROWSERNAME: "safari"
NEXT_TELEMETRY_DISABLED: 1
SKIP_LOCAL_SELENIUM_SERVER: true
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
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'
if: ${{needs.build.outputs.docsChange != 'docs only change'}}

1
.gitignore vendored
View File

@@ -2,7 +2,6 @@
.DS_Store
.idea
.jest-*
lib
node_modules
reports
*.log

View File

@@ -19,3 +19,4 @@ bin
!packages/blitz/src/bin
packages/generator/templates/**
.github/ISSUE_TEMPLATE/bug_report.md
nextjs/.github/workflows/**

View File

@@ -44,7 +44,7 @@
"devDependencies": {
"@cypress/skip-test": "2.6.0",
"@next/bundle-analyzer": "^10.0.6",
"@testing-library/react": "^11.2.3",
"@testing-library/react": "11.2.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/passport-auth0": "1.0.4",
"@types/passport-github2": "1.2.4",

View File

@@ -43,7 +43,7 @@
},
"devDependencies": {
"@cypress/skip-test": "2.6.0",
"@testing-library/react": "^11.2.3",
"@testing-library/react": "11.2.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/react": "17.0.2",
"@types/secure-password": "3.1.0",

View File

@@ -40,14 +40,10 @@
"zod": "1.11.11"
},
"devDependencies": {
"@testing-library/jest-dom": "5.11.9",
"@testing-library/react": "^11.2.3",
"@testing-library/react": "11.2.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/jest": "^26.0.20",
"@types/react": "17.0.2",
"@types/secure-password": "3.1.0",
"@typescript-eslint/eslint-plugin": "~4.14.0",
"@typescript-eslint/parser": "~4.14.0",
"babel-eslint": "~10.1.0",
"eslint": "7.21.0",
"eslint-config-react-app": "~6.0.0",
@@ -58,13 +54,6 @@
"eslint-plugin-react-hooks": "~4.2.0",
"husky": "5.1.2",
"jest": "^26.6.3",
"jest-environment-jsdom-fourteen": "^1.0.1",
"jest-watch-typeahead": "^0.6.1",
"lint-staged": "10.5.4",
"prettier": "2.2.1",
"pretty-quick": "3.1.0",
"start-server-and-test": "1.11.7",
"ts-jest": "26.5.0",
"typescript": "4.1.5"
},
"private": true

View File

@@ -34,8 +34,6 @@
},
"devDependencies": {
"@types/react": "17.0.2",
"@typescript-eslint/eslint-plugin": "~4.14.0",
"@typescript-eslint/parser": "~4.14.0",
"babel-eslint": "~10.1.0",
"eslint": "7.21.0",
"eslint-config-react-app": "~6.0.0",

View File

@@ -36,8 +36,6 @@
"react-dom": "0.0.0-experimental-3310209d0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "~4.14.0",
"@typescript-eslint/parser": "~4.14.0",
"babel-eslint": "~10.1.0",
"eslint": "7.21.0",
"eslint-config-react-app": "~6.0.0",

View File

@@ -1,6 +1,6 @@
# Learn how to add code owners here:
# https://help.github.com/en/articles/about-code-owners
* @timneutkens @Timer @ijjk @lfades
/docs/ @timneutkens @Timer @ijjk @lfades @chibicode
/examples/ @timneutkens @Timer @ijjk @lfades @chibicode
* @timneutkens @Timer @ijjk @lfades @divmain
/docs/ @timneutkens @Timer @ijjk @lfades @divmain @leerob
/examples/ @timneutkens @Timer @ijjk @lfades @divmain @leerob

View File

@@ -3,65 +3,73 @@ about: Create a bug report for the Next.js core
title: ''
labels: 'template: bug'
issue_body: true
inputs:
- type: description
body:
- type: markdown
attributes:
value: Thanks for taking the time to file a bug report! Please fill out this form as completely as possible.
- type: description
- type: markdown
attributes:
value: If you leave out sections there is a high likelihood it will be moved to the GitHub Discussions "Help" section.
- type: description
- type: markdown
attributes:
value: 'Please first verify if your issue exists in the Next.js canary release line: `npm install next@canary`.'
- type: description
- type: markdown
attributes:
value: 'next@canary is the beta version of Next.js. It includes all features and fixes that are pending to land on the stable release line.'
- type: input
attributes:
label: What version of Next.js are you using?
description: 'For example: 10.0.1'
validations:
required: true
- type: input
attributes:
label: What version of Node.js are you using?
description: 'For example: 12.0.0'
validations:
required: true
- type: input
attributes:
label: What browser are you using?
description: 'For example: Chrome, Safari'
validations:
required: true
- type: input
attributes:
label: What operating system are you using?
description: 'For example: macOS, Windows'
validations:
required: true
- type: input
attributes:
label: How are you deploying your application?
description: 'For example: next start, next export, Vercel, Other platform'
validations:
required: true
- type: textarea
attributes:
label: Describe the Bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: Steps to reproduce the behavior, please provide a clear code snippets that always reproduces the issue or a GitHub repository. Screenshots can be provided in the issue body below.
validations:
required: true
- type: description
- type: markdown
attributes:
value: Before posting the issue go through the steps you've written down to make sure the steps provided are detailed and clear.
- type: description
- type: markdown
attributes:
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
- type: description
- type: markdown
attributes:
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!

View File

@@ -3,64 +3,73 @@ about: Create a bug report for the examples
title: ''
labels: 'type: example,template: bug'
issue_body: true
inputs:
- type: description
body:
- type: markdown
attributes:
value: Thanks for taking the time to file a examples bug report! Please fill out this form as completely as possible.
- type: description
- type: markdown
attributes:
value: If you leave out sections there is a high likelihood it will be moved to the GitHub Discussions "Help" section.
- type: input
attributes:
label: What example does this report relate to?
description: 'For example: with-styled-components'
validations:
required: true
- type: input
attributes:
label: What version of Next.js are you using?
description: 'For example: 10.0.1'
validations:
required: true
- type: input
attributes:
label: What version of Node.js are you using?
description: 'For example: 12.0.0'
validations:
required: true
- type: input
attributes:
label: What browser are you using?
description: 'For example: Chrome, Safari'
validations:
required: true
- type: input
attributes:
label: What operating system are you using?
description: 'For example: macOS, Windows'
validations:
required: true
- type: input
attributes:
label: How are you deploying your application?
description: 'For example: next start, next export, Vercel, Other platform'
validations:
required: true
- type: textarea
attributes:
label: Describe the Bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: Steps to reproduce the behavior, please provide a clear code snippets that always reproduces the issue or a GitHub repository. Screenshots can be provided in the issue body below.
validations:
required: true
- type: description
- type: markdown
attributes:
value: Before posting the issue go through the steps you've written down to make sure the steps provided are detailed and clear.
- type: description
- type: markdown
attributes:
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
- type: description
- type: markdown
attributes:
value: Thanks in advance!

View File

@@ -3,25 +3,28 @@ about: Create a feature request for the Next.js core
title: ''
labels: 'template: story'
issue_body: true
inputs:
- type: description
body:
- type: markdown
attributes:
value: Thanks for taking the time to file a feature request! Please fill out this form as completely as possible.
- type: description
- type: markdown
attributes:
value: 'Feature requests will be converted to the GitHub Discussions "Ideas" section.'
- type: textarea
attributes:
label: Describe the feature you'd like to request
description: A clear and concise description of what you want and what your use case is.
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: true

View File

@@ -181,7 +181,7 @@ jobs:
- run: yarn install --check-files
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}/test/index.test.js test/acceptance/*.test.js
- run: xvfb-run node run-tests.js test/integration/{fallback-modules,link-ref,production,basic,async-modules,font-optimization,ssr-ctx}/test/index.test.js test/acceptance/*.test.js
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
testLegacyReact:

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = git@github.com:blitz-js/next.js.git
branch = canary
commit = 5a4b3061adf94b802f4d65f99ba1cc80d7867cd9
parent = c699d4f021de0cbe7d8e6619e46078c0b31a1ada
commit = 9808a42f5358d5c106bc8f57e04607d78b9da2a2
parent = 83fd77f1f2794d3423839f59f7c57b4da019f196
method = merge
cmdver = 0.4.3

View File

@@ -1,39 +0,0 @@
// Disable automatic instrumentation
process.env.OTEL_NO_PATCH_MODULES = '*'
const { NodeTracerProvider } = require('@opentelemetry/node')
const { SimpleSpanProcessor } = require('@opentelemetry/tracing')
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin')
const tracerProvider = new NodeTracerProvider({
// All automatic instrumentation plugins have to be disabled as it affects worker_thread/child_process bootup performance
plugins: {
mongodb: { enabled: false, path: '@opentelemetry/plugin-mongodb' },
grpc: { enabled: false, path: '@opentelemetry/plugin-grpc' },
'@grpc/grpc-js': { enabled: false, path: '@opentelemetry/plugin-grpc-js' },
http: { enabled: false, path: '@opentelemetry/plugin-http' },
https: { enabled: false, path: '@opentelemetry/plugin-https' },
mysql: { enabled: false, path: '@opentelemetry/plugin-mysql' },
pg: { enabled: false, path: '@opentelemetry/plugin-pg' },
redis: { enabled: false, path: '@opentelemetry/plugin-redis' },
ioredis: { enabled: false, path: '@opentelemetry/plugin-ioredis' },
'pg-pool': { enabled: false, path: '@opentelemetry/plugin-pg-pool' },
express: { enabled: false, path: '@opentelemetry/plugin-express' },
'@hapi/hapi': {
enabled: false,
path: '@opentelemetry/hapi-instrumentation',
},
koa: { enabled: false, path: '@opentelemetry/koa-instrumentation' },
dns: { enabled: false, path: '@opentelemetry/plugin-dns' },
},
})
tracerProvider.addSpanProcessor(
new SimpleSpanProcessor(
new ZipkinExporter({
serviceName: 'next-js',
})
)
)
tracerProvider.register()

View File

@@ -21,11 +21,26 @@ export default function Custom404() {
}
```
> **Note**: You can use [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) inside this page if you need to fetch data at build time.
## 500 Page
By default Next.js provides a 500 error page that matches the default 404 pages style. This page is not statically optimized as it allows server-side errors to be reported. This is why 404 and 500 (other errors) are separated.
Server-rendering an error page for every visit adds complexity to responding to errors. To help users get responses to errors as fast as possible, Next.js provides a static 500 page by default without having to add any additional files.
### Customizing The Error Page
### Customizing The 500 Page
To customize the 500 page you can create a `pages/500.js` file. This file is statically generated at build time.
```jsx
// pages/500.js
export default function Custom500() {
return <h1>500 - Server-side error occurred</h1>
}
```
> **Note**: You can use [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) inside this page if you need to fetch data at build time.
### More Advanced Error Page Customizing
500 errors are handled both client-side and server-side by the `Error` component. If you wish to override it, define the file `pages/_error.js` and add the following code:

View File

@@ -217,9 +217,9 @@ export default function IndexPage(props) {
## Leveraging the NEXT_LOCALE cookie
Next.js supports overriding the accept-language header with a `NEXT_LOCALE=the-locale` cookie. This cookie can be set using a language switcher and then when a user comes back to the site it will leverage the locale specified in the cookie.
Next.js supports overriding the accept-language header with a `NEXT_LOCALE=the-locale` cookie. This cookie can be set using a language switcher and then when a user comes back to the site it will leverage the locale specified in the cookie when redirecting from `/` to the correct locale location.
For example, if a user prefers the locale `fr` but a `NEXT_LOCALE=en` cookie is set the `en` locale will be used instead until the cookie is removed or expired.
For example, if a user prefers the locale `fr` in their accept-language header but a `NEXT_LOCALE=en` cookie is set the `en` locale when visiting `/` the user will be redirected to the `en` locale location until the cookie is removed or expired.
## Search Engine Optimization

View File

@@ -15,6 +15,8 @@ Next.js automatically supports the `tsconfig.json` and `jsconfig.json` `"paths"`
> Note: `jsconfig.json` can be used when you don't use TypeScript
> Note: you need to restart dev server to reflect modifications done in `tsconfig.json` / `jsconfig.json`
These options allow you to configure module aliases, for example a common pattern is aliasing certain directories to use absolute paths.
One useful feature of these options is that they integrate automatically into certain editors, for example vscode.

View File

@@ -4,7 +4,7 @@ description: Enables browser source map generation during the production build.
# Source Maps
Source Maps are enabled by default during development. During production builds they are disabled as generation source maps can significantly increase build times and memory usage while being generated.
Source Maps are enabled by default during development. During production builds, they are disabled as generating source maps can significantly increase build times and memory usage while being generated.
Next.js provides a configuration flag you can use to enable browser source map generation during the production build:
@@ -15,9 +15,9 @@ module.exports = {
}
```
When the `productionBrowserSourceMaps` option is enabled the source maps will be output in the same directory as the JavaScript files, Next.js will automatically serve these files when requested.
When the `productionBrowserSourceMaps` option is enabled, the source maps will be output in the same directory as the JavaScript files. Next.js will automatically serve these files when requested.
## Caveats
- Can increase `next build` time
- Adding source maps can increase `next build` time
- Increases memory usage during `next build`

View File

@@ -227,6 +227,17 @@ module.exports = {
},
],
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
headers: [
{
key: 'x-hello',
value: 'worlld',
},
],
},
]
},
}

View File

@@ -152,9 +152,21 @@ module.exports = {
locale: false,
permanent: false,
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
destination: '/another',
permanent: false,
},
]
},
}
```
In some rare cases, you might need to assign a custom status code for older HTTP Clients to properly redirect. In these cases, you can use the `statusCode` property instead of the `permanent` property, but not both. Note: to ensure IE11 compatibility a `Refresh` header is automatically added for the 308 status code.
## Other Redirects
- Inside [API Routes](/docs/api-routes/response-helpers.md), you can use `res.redirect()`.
- Inside [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) and [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering), you can redirect specific pages at request-time.

View File

@@ -244,6 +244,12 @@ module.exports = {
destination: '/en/another',
locale: false,
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
destination: '/another',
},
]
},
}

View File

@@ -44,7 +44,7 @@ The page above is an AMP-only page, which means:
- The page has no Next.js or React client-side runtime
- The page is automatically optimized with [AMP Optimizer](https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer), an optimizer that applies the same transformations as AMP caches (improves performance by up to 42%)
- The page has an user-accessible (optimized) version of the page and a search-engine indexable (unoptimized) version of the page
- The page has a user-accessible (optimized) version of the page and a search-engine indexable (unoptimized) version of the page
## Hybrid AMP Page

View File

@@ -50,6 +50,7 @@ The following is the definition of the `router` object returned by both [`useRou
- `locales`: `String[]` - All supported locales (if enabled).
- `defaultLocale`: `String` - The current default locale (if enabled).
- `isReady`: `boolean` - Whether the router fields are updated client-side and ready for use. Should only be used inside of `useEffect` methods and not for conditionally rendering on the server.
- `isPreview`: `boolean` - Whether the application is currently in [preview mode](/docs/advanced-features/preview-mode.md).
Additionally, the following methods are also included inside `router`:
@@ -71,7 +72,9 @@ router.push(url, as, options)
- `url` - The URL to navigate to
- `as` - Optional decorator for the URL that will be shown in the browser. Before Next.js 9.5.3 this was used for dynamic routes, check our [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) to see how it worked
- `options` - Optional object with the following configuration options:
- `scroll`: Scroll to the top of the page after a navigation. Defaults to `true`
- [`shallow`](/docs/routing/shallow-routing.md): Update the path of the current page without rerunning [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation), [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) or [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md). Defaults to `false`
- `scroll` - Optional boolean, controls scrolling to the top of the page after navigation. Defaults to `true`
> You don't need to use `router.push` for external URLs. [window.location](https://developer.mozilla.org/en-US/docs/Web/API/Window/location) is better suited for those cases.

View File

@@ -17,10 +17,7 @@ For example, the API route `pages/api/post/[pid].js` has the following code:
```js
export default function handler(req, res) {
const {
query: { pid },
} = req
const { pid } = req.query
res.end(`Post: ${pid}`)
}
```
@@ -69,10 +66,7 @@ An API route for `pages/api/post/[...slug].js` could look like this:
```js
export default function handler(req, res) {
const {
query: { slug },
} = req
const { slug } = req.query
res.end(`Post: ${slug.join(', ')}`)
}
```

View File

@@ -15,7 +15,7 @@ description: Next.js supports API Routes, which allow you to build your API with
</ul>
</details>
API routes provide a straightforward solution to build your **API** with Next.js.
API routes provide a solution to build your **API** with Next.js.
Any file inside the folder `pages/api` is mapped to `/api/*` and will be treated as an API endpoint instead of a `page`. They are server-side only bundles and won't increase your client-side bundle size.
@@ -46,6 +46,13 @@ export default function handler(req, res) {
To fetch API endpoints, take a look into any of the examples at the start of this section.
## Use Cases
For new projects, you can build your entire API with API Routes. If you have an existing API, you do not need to forward calls to the API through an API Route. Some other use cases for API Routes are:
- Masking the URL of an external service (e.g. `/api/secret` instead of `https://company.com/secret-url`)
- Using [Environment Variables](/docs/basic-features/environment-variables.md) on the server to securely access external services.
## Caveats
- API Routes [do not specify CORS headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), meaning they are **same-origin only** by default. You can customize such behavior by wrapping the request handler with the [cors middleware](/docs/api-routes/api-middlewares.md#connectexpress-middleware-support).

View File

@@ -26,3 +26,5 @@ The included helpers are:
- `res.json(json)` - Sends a JSON response. `json` must be a valid JSON object
- `res.send(body)` - Sends the HTTP response. `body` can be a `string`, an `object` or a `Buffer`
- `res.redirect([status,] path)` - Redirects to a specified path or URL. `status` must be a valid [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes). If not specified, `status` defaults to "307" "Temporary redirect".
To view an example using types, check out the [TypeScript documentation](/docs/basic-features/typescript.md#api-routes).

View File

@@ -68,7 +68,6 @@ Let's transform the profile example to use [server-side rendering](/docs/basic-f
// pages/profile.js
import withSession from '../lib/session'
import useUser from '../lib/useUser'
import Layout from '../components/Layout'
export const getServerSideProps = withSession(async function ({ req, res }) {
@@ -114,16 +113,16 @@ Now that we've discussed authentication patterns, let's look at specific provide
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-iron-session">with-iron-session</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-next-auth">with-next-auth</a></li>
<li><a href="https://github.com/nextauthjs/next-auth-example">next-auth-example</a></li>
</ul>
</details>
If you have an existing database with user data, you'll likely want to utilize an open-source solution that's provider agnostic.
- If you need email/password log-in, use [`next-iron-session`](https://github.com/vercel/next.js/tree/canary/examples/with-iron-session).
- If you need to persist session data on the server, use [`next-auth`](https://github.com/vercel/next.js/tree/canary/examples/with-next-auth).
- If you need to support social login (Google, Facebook, etc.), use [`next-auth`](https://github.com/vercel/next.js/tree/canary/examples/with-next-auth).
- If you want to use [JWTs](https://jwt.io/), use [`next-auth`](https://github.com/vercel/next.js/tree/canary/examples/with-next-auth).
- If you need to persist session data on the server, use [`next-auth`](https://github.com/nextauthjs/next-auth-example).
- If you need to support social login (Google, Facebook, etc.), use [`next-auth`](https://github.com/nextauthjs/next-auth-example).
- If you want to use [JWTs](https://jwt.io/), use [`next-auth`](https://github.com/nextauthjs/next-auth-example).
Both of these libraries support either authentication pattern. If you're interested in [Passport](http://www.passportjs.org/), we also have examples for it using secure and encrypted cookies:
@@ -189,6 +188,18 @@ You can either use [FirebaseUI](https://github.com/firebase/firebaseui-web-react
[Userbase](https://userbase.com/) supports the static generation pattern for authentication. It's open source and allows for a high level of security with end-to-end encryption. You can learn more about it in their [official site](https://userbase.com/).
### SuperTokens
<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-supertokens">with-supertokens</a></li>
</ul>
</details>
[SuperTokens](https://supertokens.io) is a highly customizable, open-source solution split into modules (so you only use what you need).
SuperTokens currently supports credentials login, email verification, password reset flows, and third-party logins.
## Related
For more information on what to do next, we recommend the following sections:

View File

@@ -87,7 +87,7 @@ The `context` parameter is an object containing the following keys:
}
return {
props: {}, // will be passed to the page component as props
props: { data }, // will be passed to the page component as props
}
}
```
@@ -111,7 +111,7 @@ The `context` parameter is an object containing the following keys:
}
return {
props: {}, // will be passed to the page component as props
props: { data }, // will be passed to the page component as props
}
}
```
@@ -156,7 +156,7 @@ export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
// By returning { props: posts }, the Blog component
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
@@ -325,7 +325,7 @@ export async function getStaticProps() {
content: fileContents,
}
})
// By returning { props: posts }, the Blog component
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {

View File

@@ -135,3 +135,15 @@ This one is useful when running tests with tools like `jest` or `cypress` where
There is a small difference between `test` environment, and both `development` and `production` that you need to bear in mind: `.env.local` won't be loaded, as you expect tests to produce the same results for everyone. This way every test execution will use same env defaults across different executions by ignoring your `.env.local` (which is intended to override the default set).
> **Note**: similar to Default Environment Variables, `.env.test` file should be included in your repository, but `.env.test.local` shouldn't, as `.env*.local` are intended to be ignored through `.gitignore`.
While running unit tests you can make sure to load your environment variables the same way Next.js does by leveraging the `loadEnvConfig` function from the `@next/env` package.
```js
// The below can be used in a Jest global setup file or similar for your testing set-up
import { loadEnvConfig } from '@next/env'
export default async () => {
const projectDir = process.cwd()
loadEnvConfig(projectDir)
}
```

View File

@@ -160,7 +160,9 @@ export async function getStaticPaths() {
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => `/posts/${post.id}`)
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.

View File

@@ -6,7 +6,7 @@ description: Deploy your Next.js app to production with Vercel and other hosting
## Vercel (Recommended)
The easiest way to deploy Next.js to production is to use the **[Vercel platform](https://vercel.com)** from the creators of Next.js. [Vercel](https://vercel.com) is an all-in-one platform with Global CDN supporting static & Jamstack deployment and Serverless Functions.
The easiest way to deploy Next.js to production is to use the **[Vercel platform](https://vercel.com)** from the creators of Next.js. [Vercel](https://vercel.com) is a cloud platform for static sites, hybrid apps, and Serverless Functions.
### Getting started
@@ -78,6 +78,59 @@ Make sure your `package.json` has the `"build"` and `"start"` scripts:
`next build` builds the production application in the `.next` folder. After building, `next start` starts a Node.js server that supports [hybrid pages](/docs/basic-features/pages.md), serving both statically generated and server-side rendered pages.
### Docker Image
Next.js can be deployed to any hosting provider that supports [Docker](https://www.docker.com/) containers. You can use this approach when deploying to container orchestrators such as [Kubernetes](https://kubernetes.io/) or [HashiCorp Nomad](https://www.nomadproject.io/), or when running inside a single node in any cloud provider.
Here is a multi-stage `Dockerfile` using `node:alpine` that you can use:
```Dockerfile
# Install dependencies only when needed
FROM node:alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn build
# Production image, copy all the files and run next
FROM node:alpine AS runner
WORKDIR /app
ENV NODE_ENV production
# You only need to copy next.config.js if you are NOT using the default configuration
# COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
RUN chown -R nextjs:nodejs /app/.next
USER nextjs
EXPOSE 3000
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
# RUN npx next telemetry disable
CMD ["node_modules/.bin/next", "start"]
```
Make sure to place this Dockerfile in the root folder of your project.
You can build your container with `docker build . -t my-next-js-app` and run it with `docker run -p 3000:3000 my-next-js-app`.
### Static HTML Export
If youd like to do a static HTML export of your Next.js app, follow the directions on [our documentation](/docs/advanced-features/static-html-export.md).

View File

@@ -74,6 +74,8 @@ In the example above we have multiple links, each one maps a path (`href`) to a
- `/about``pages/about.js`
- `/blog/hello-world``pages/blog/[slug].js`
Any `<Link />` in the viewport (initially or through scroll) will be prefetched by default (including the corresponding data) for pages using [Static Generation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation). The corresponding data for [server-rendered](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering) routes is _not_ prefetched.
### Linking to dynamic paths
You can also use interpolation to create the path, which comes in handy for [dynamic route segments](#dynamic-route-segments). For example, to show a list of posts which have been passed to the component as a prop:

View File

@@ -11,8 +11,9 @@ This is because Next.js optimizes images on-demand, as users request them (not a
#### Possible Ways to Fix It
- Use `next start` to run a server, which includes the Image Optimization API.
- Use Vercel to deploy, which supports [Image Optimization](https://vercel.com/docs/next.js/image-optimization).
- Use any provider which supports Image Optimization (like [Vercel](https://vercel.com/docs/next.js/image-optimization)).
- Configure a third-party [loader](https://nextjs.org/docs/basic-features/image-optimization#loader) in `next.config.js`.
- Use the [`loader`](https://nextjs.org/docs/api-reference/next/image#loader) prop for `next/image`.
### Useful Links

View File

@@ -111,3 +111,15 @@ Using Heroku's [custom cache](https://devcenter.heroku.com/articles/nodejs-suppo
```javascript
"cacheDirectories": [".next/cache"]
```
#### Azure Pipelines
Using Azure Pipelines' [Cache task](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/cache), add the following task to your pipeline yaml file somewhere prior to the task that executes `next build`:
```yaml
- task: Cache@2
displayName: 'Cache .next/cache'
inputs:
key: next | $(Agent.OS) | yarn.lock
path: '$(System.DefaultWorkingDirectory)/.next/cache'
```

View File

@@ -4,6 +4,12 @@
In this simple example, we integrate Apollo seamlessly with [Next.js data fetching methods](https://nextjs.org/docs/basic-features/data-fetching) to fetch queries in the server and hydrate them in the browser.
## Deploy your own
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/api-routes-apollo-server-and-client&project-name=api-routes-apollo-server-and-client&repository-name=api-routes-apollo-server-and-client)
## 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:

View File

@@ -0,0 +1,4 @@
PREPRIO_API=https://graphql.prepr.io/graphql
PREPRIO_PRODUCTION_TOKEN=
PREPRIO_PREVIEW_TOKEN=
PREPRIO_PREVIEW_KEY=

View File

@@ -0,0 +1,129 @@
# A statically generated blog example using Next.js and Prepr
This example showcases Next.js's [Static Generation](https://nextjs.org/docs/basic-features/pages) feature using [Prepr](https://prepr.io/) as the data source.
## Demo
- **Live**: [https://next-blog-prepr.now.sh/](https://next-blog-prepr.now.sh/)
- **Preview Mode**: [https://next-blog-prepr.now.sh/api/preview...](https://next-blog-prepr.now.sh/api/preview?secret=237864ihasdhj283768&slug=discover-enjoy-amsterdam)
### [https://next-blog-prepr.now.sh/](https://next-blog-prepr.now.sh/)
### Related examples
- [WordPress](/examples/cms-wordpress)
- [DatoCMS](/examples/cms-datocms)
- [Sanity](/examples/cms-sanity)
- [TakeShape](/examples/cms-takeshape)
- [Prismic](/examples/cms-prismic)
- [Contentful](/examples/cms-contentful)
- [Strapi](/examples/cms-strapi)
- [Agility CMS](/examples/cms-agilitycms)
- [Cosmic](/examples/cms-cosmic)
- [ButterCMS](/examples/cms-buttercms)
- [Storyblok](/examples/cms-storyblok)
- [Kontent](/examples/cms-kontent)
- [Ghost](/examples/cms-ghost)
- [GraphCMS](/examples/cms-graphcms)
- [Blog Starter](/examples/blog-starter)
## Getting Started
Once you have access to [the environment variables you'll need](#step-3-set-up-environment-variables), deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/cms-prepr&project-name=cms-prepr&repository-name=cms-prepr&env=PREPRIO_API,PREPRIO_PRODUCTION_TOKEN,PREPRIO_PREVIEW_TOKEN,PREPRIO_PREVIEW_KEY&envDescription=Required%20to%20connect%20the%20app%20with%20Prepr&envLink=https://vercel.link/cms-prepr-env)
## 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 cms-prepr cms-prepr-app
# or
yarn create next-app --example cms-prepr cms-prepr-app
```
## Configuration
### Step 1. Create an account and a environment in Prepr
First, [create an account in Prepr](https://prepr.io).
### Step 2. Create Author model
From your Prepr dashboard, click **Settings** -> **Models**
Click on the arrow next to **Add model** and select **Import**.
Import the [`models/author.json`](models/author.json) file.
After that
Import the [`models/post.json`](models/post.json) file.
Click on the Author field and select `Author` at the option `Publication model` and click **Save**.
### Step 3. Set up environment variables
Copy the `.env.local.example` file in this directory to `.env.local` (which will be ignored by Git):
```bash
cp .env.local.example .env.local
```
Inside your environment, navigate to **Settings > Development > Access Tokens**.
Click **Add access token**, enter the name `Next.js Preview` and add the scope `graphql_preview` and click **Save**.
Copy the generated access token and set the variable `PREPRIO_PREVIEW_TOKEN` in `.env.local`.
Go back to the Access token overview and click **Add access token**.
Enter the name `Next.js Production` and add the scope `graphql_published` and click **Save**.
Copy the generated access token and set the variable `PREPRIO_PRODUCTION_TOKEN` in `.env.local`.
The `PREPRIO_PREVIEW_KEY` can be any random string (but avoid spaces), like a UUID`, this is used
for [Preview Mode](https://nextjs.org/docs/advanced-features/preview-mode).
### Step 4. Run Next.js in development mode
```bash
npm install
npm run dev
# or
yarn install
yarn dev
```
Your blog should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/vercel/next.js/discussions).
### Step 5. Try preview mode
In Prepr, go to one of the posts in your environment and:
- **Update the title**. For example, you can add `[REVIEW]` in front of the title.
- After you edit the publication save the post with a review state.
To view the preview, transform the url to the following format: `http://localhost:3000/api/preview?secret=<YOUR_SECRET_TOKEN>&slug=<SLUG_TO_PREVIEW>` where `<YOUR_SECRET_TOKEN>` is
the same secret you defined in the `.env.local` file and `<SLUG_TO_PREVIEW>` is the slug of one of the posts you want to preview.
You should now be able to see post that are in Review and Done state. To exit the preview mode, you can click on _"Click here to exit preview mode"_ at the top.
### Step 6. Deploy on Vercel
You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
#### Deploy Your Local Project
To deploy your local project to Vercel, push it to GitHub/GitLab/Bitbucket and [import to Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example).
**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set them to match your `.env.local` file.
#### Deploy from Our Template
Alternatively, you can deploy using our template by clicking on the Deploy button below.
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/cms-prepr&project-name=cms-prepr&repository-name=cms-prepr&env=PREPRIO_API,PREPRIO_PRODUCTION_TOKEN,PREPRIO_PREVIEW_TOKEN,PREPRIO_PREVIEW_KEY&envDescription=Required%20to%20connect%20the%20app%20with%20Prepr&envLink=https://vercel.link/cms-prepr-env)

View File

@@ -0,0 +1,42 @@
import Container from './container'
import cn from 'classnames'
import { EXAMPLE_PATH } from '../lib/constants'
export default function Alert({ preview }) {
return (
<div
className={cn('border-b', {
'bg-accent-7 border-accent-7 text-white': preview,
'bg-accent-1 border-accent-2': !preview,
})}
>
<Container>
<div className="py-2 text-center text-sm">
{preview ? (
<>
This page is a preview.{' '}
<a
href="/api/exit-preview"
className="underline hover:text-cyan duration-200 transition-colors"
>
Click here
</a>{' '}
to exit preview mode.
</>
) : (
<>
The source code for this blog is{' '}
<a
href={`https://github.com/vercel/next.js/tree/canary/examples/${EXAMPLE_PATH}`}
className="underline hover:text-success duration-200 transition-colors"
>
available on GitHub
</a>
.
</>
)}
</div>
</Container>
</div>
)
}

View File

@@ -0,0 +1,17 @@
import Image from 'next/image'
export default function Avatar({ name, picture }) {
return (
<div className="flex items-center">
<div className="w-12 h-12 relative mr-4">
<Image
src={picture}
layout="fill"
className="rounded-full"
alt={name}
/>
</div>
<div className="text-xl font-bold">{name}</div>
</div>
)
}

View File

@@ -0,0 +1,3 @@
export default function Container({ children }) {
return <div className="container mx-auto px-5">{children}</div>
}

View File

@@ -0,0 +1,29 @@
import Image from 'next/image'
import Link from 'next/link'
import cn from 'classnames'
export default function CoverImage({ title, url, slug }) {
const image = (
<Image
width={2000}
height={1000}
alt={`Cover Image for ${title}`}
className={cn('shadow-small', {
'hover:shadow-medium transition-shadow duration-200': slug,
})}
src={url}
/>
)
return (
<div className="sm:mx-0">
{slug ? (
<Link as={`/posts/${slug}`} href="/posts/[slug]">
<a aria-label={title}>{image}</a>
</Link>
) : (
image
)}
</div>
)
}

View File

@@ -0,0 +1,6 @@
import { parseISO, format } from 'date-fns'
export default function Date({ dateString }) {
const date = parseISO(dateString)
return <time dateTime={dateString}>{format(date, 'LLLL d, yyyy')}</time>
}

View File

@@ -0,0 +1,30 @@
import Container from './container'
import { EXAMPLE_PATH } from '../lib/constants'
export default function Footer() {
return (
<footer className="bg-accent-1 border-t border-accent-2">
<Container>
<div className="py-28 flex flex-col lg:flex-row items-center">
<h3 className="text-4xl lg:text-5xl font-bold tracking-tighter leading-tight text-center lg:text-left mb-10 lg:mb-0 lg:pr-4 lg:w-1/2">
Statically Generated with Next.js.
</h3>
<div className="flex flex-col lg:flex-row justify-center items-center lg:pl-4 lg:w-1/2">
<a
href="https://nextjs.org/docs/basic-features/pages"
className="mx-3 bg-black hover:bg-white hover:text-black border border-black text-white font-bold py-3 px-12 lg:px-8 duration-200 transition-colors mb-6 lg:mb-0"
>
Read Documentation
</a>
<a
href={`https://github.com/vercel/next.js/tree/canary/examples/${EXAMPLE_PATH}`}
className="mx-3 font-bold hover:underline"
>
View on GitHub
</a>
</div>
</div>
</Container>
</footer>
)
}

View File

@@ -0,0 +1,12 @@
import Link from 'next/link'
export default function Header() {
return (
<h2 className="text-2xl md:text-4xl font-bold tracking-tight md:tracking-tighter leading-tight mb-20 mt-8">
<Link href="/">
<a className="hover:underline">Blog</a>
</Link>
.
</h2>
)
}

View File

@@ -0,0 +1,40 @@
import Avatar from '../components/avatar'
import Date from '../components/date'
import CoverImage from '../components/cover-image'
import Link from 'next/link'
export default function HeroPost({
title,
coverImage,
date,
excerpt,
author,
slug,
}) {
return (
<section>
<div className="mb-8 md:mb-16">
<CoverImage slug={slug} title={title} url={coverImage} />
</div>
<div className="mb-20 md:grid md:grid-cols-2 md:col-gap-16 lg:col-gap-8 md:mb-28">
<div>
<h3 className="mb-4 text-4xl leading-tight lg:text-6xl">
<Link as={`/posts/${slug}`} href="/posts/[slug]">
<a className="hover:underline">{title}</a>
</Link>
</h3>
<div className="mb-4 text-lg md:mb-0">
<Date dateString={date} />
</div>
</div>
<div>
<p className="mb-4 text-lg leading-relaxed">{excerpt}</p>
<Avatar
name={author.name}
picture={author.cover[0].cdn_files[0].url}
/>
</div>
</div>
</section>
)
}

View File

@@ -0,0 +1,28 @@
import { CMS_NAME, CMS_URL } from '../lib/constants'
export default function Intro() {
return (
<section className="flex-col md:flex-row flex items-center md:justify-between mt-16 mb-16 md:mb-12">
<h1 className="text-6xl md:text-8xl font-bold tracking-tighter leading-tight md:pr-8">
Blog.
</h1>
<h4 className="text-center md:text-left text-lg mt-5 md:pl-8">
A statically generated blog example using{' '}
<a
href="https://nextjs.org/"
className="underline hover:text-success duration-200 transition-colors"
>
Next.js
</a>{' '}
and{' '}
<a
href={CMS_URL}
className="underline hover:text-success duration-200 transition-colors"
>
{CMS_NAME}
</a>
.
</h4>
</section>
)
}

View File

@@ -0,0 +1,16 @@
import Alert from '../components/alert'
import Footer from '../components/footer'
import Meta from '../components/meta'
export default function Layout({ preview, children }) {
return (
<>
<Meta />
<div className="min-h-screen">
<Alert preview={preview} />
<main>{children}</main>
</div>
<Footer />
</>
)
}

View File

@@ -0,0 +1,42 @@
import Head from 'next/head'
import { CMS_NAME, HOME_OG_IMAGE_URL } from '../lib/constants'
export default function Meta() {
return (
<Head>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon/favicon-16x16.png"
/>
<link rel="manifest" href="/favicon/site.webmanifest" />
<link
rel="mask-icon"
href="/favicon/safari-pinned-tab.svg"
color="#000000"
/>
<link rel="shortcut icon" href="/favicon/favicon.ico" />
<meta name="msapplication-TileColor" content="#000000" />
<meta name="msapplication-config" content="/favicon/browserconfig.xml" />
<meta name="theme-color" content="#000" />
<link rel="alternate" type="application/rss+xml" href="/feed.xml" />
<meta
name="description"
content={`A statically generated blog example using Next.js and ${CMS_NAME}.`}
/>
<meta property="og:image" content={HOME_OG_IMAGE_URL} />
</Head>
)
}

View File

@@ -0,0 +1,24 @@
import PostPreview from '../components/post-preview'
export default function MoreStories({ posts }) {
return (
<section>
<h2 className="mb-8 text-6xl md:text-7xl font-bold tracking-tighter leading-tight">
More Stories
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 md:gap-x-16 lg:gap-x-32 gap-y-20 md:gap-y-32 mb-32">
{posts.map((post) => (
<PostPreview
key={post._slug}
title={post.title}
coverImage={post.cover[0].cdn_files[0].url}
date={post.date}
author={post.author[0]}
slug={post._slug}
excerpt={post.summary}
/>
))}
</div>
</section>
)
}

View File

@@ -0,0 +1,10 @@
import postStyles from './post-styles.module.css'
export default function PostBody({ content }) {
return (
<div
className={`max-w-2xl mx-auto post ${postStyles.post}`}
dangerouslySetInnerHTML={{ __html: content }}
/>
)
}

View File

@@ -0,0 +1,29 @@
import Avatar from '../components/avatar'
import Date from '../components/date'
import CoverImage from '../components/cover-image'
import PostTitle from '../components/post-title'
export default function PostHeader({ title, coverImage, date, author }) {
return (
<>
<PostTitle>{title}</PostTitle>
<div className="hidden md:block md:mb-12">
<Avatar name={author.name} picture={author.cover[0].cdn_files[0].url} />
</div>
<div className="mb-8 -mx-5 md:mb-16 sm:mx-0">
<CoverImage title={title} url={coverImage} />
</div>
<div className="max-w-2xl mx-auto">
<div className="block mb-6 md:hidden">
<Avatar
name={author.name}
picture={author.cover[0].cdn_files[0].url}
/>
</div>
<div className="mb-6 text-lg">
<Date dateString={date} />
</div>
</div>
</>
)
}

View File

@@ -0,0 +1,31 @@
import Avatar from '../components/avatar'
import Date from '../components/date'
import CoverImage from './cover-image'
import Link from 'next/link'
export default function PostPreview({
title,
coverImage,
date,
excerpt,
author,
slug,
}) {
return (
<div>
<div className="mb-5">
<CoverImage slug={slug} title={title} url={coverImage} />
</div>
<h3 className="mb-3 text-3xl leading-snug">
<Link as={`/posts/${slug}`} href="/posts/[slug]">
<a className="hover:underline">{title}</a>
</Link>
</h3>
<div className="mb-4 text-lg">
<Date dateString={date} />
</div>
<p className="mb-4 text-lg leading-relaxed">{excerpt}</p>
<Avatar name={author.name} picture={author.cover[0].cdn_files[0].url} />
</div>
)
}

View File

@@ -0,0 +1,22 @@
.post {
@apply text-lg leading-relaxed;
}
.post p,
.post ul,
.post ol,
.post blockquote {
@apply my-6;
}
.post h1 {
@apply mt-12 mb-4 text-4xl leading-snug;
}
.post h2 {
@apply mt-12 mb-4 text-3xl leading-snug;
}
.post h3 {
@apply mt-8 mb-4 text-2xl leading-snug;
}

View File

@@ -0,0 +1,7 @@
export default function PostTitle({ children }) {
return (
<h1 className="text-6xl md:text-7xl lg:text-8xl font-bold tracking-tighter leading-tight md:leading-none mb-12 text-center md:text-left">
{children}
</h1>
)
}

View File

@@ -0,0 +1,3 @@
export default function SectionSeparator() {
return <hr className="border-accent-2 mt-28 mb-24" />
}

View File

@@ -0,0 +1,5 @@
{
"compilerOptions": {
"baseUrl": "."
}
}

View File

@@ -0,0 +1,4 @@
export const EXAMPLE_PATH = 'cms-prepr'
export const CMS_NAME = 'Prepr'
export const CMS_URL = 'https://prepr.io/'
export const HOME_OG_IMAGE_URL = ''

View File

@@ -0,0 +1,156 @@
import { createPreprClient } from '@preprio/nodejs-sdk'
const prepr = createPreprClient({
token: process.env.PREPRIO_PRODUCTION_TOKEN,
timeout: 4000,
baseUrl: process.env.PREPRIO_API,
})
export { prepr }
export async function getAllPostsForHome(preview) {
// Query publications
const data =
(await prepr
.graphqlQuery(
`
query {
Posts {
items {
_id,
_slug,
date: _publish_on
title,
summary,
author {
name
cover {
cdn_files {
url(width: 100, height:100)
}
}
}
cover {
cdn_files {
url(width:2000, height:1000)
}
}
}
}
}`
)
.token(
preview
? process.env.PREPRIO_PREVIEW_TOKEN
: process.env.PREPRIO_PRODUCTION_TOKEN
)
.fetch()) || []
return data.data.Posts.items
}
export async function getAllPostsWithSlug() {
// Query publications
const data =
(await prepr
.graphqlQuery(
`
query {
Posts {
items {
slug : _slug,
}
}
}`
)
.fetch()) || []
return data.data.Posts.items
}
export async function getPostAndMorePosts(slug, preview) {
// Query publications
const data =
(await prepr
.graphqlQuery(
`
query slugPost($slug: String!) {
Post ( slug : $slug) {
_id,
_slug,
date: _publish_on
title,
summary,
content,
author {
name
cover {
cdn_files {
url(width: 100, height:100)
}
}
}
cover {
cdn_files {
url(width:2000, height:1000)
}
}
}
morePosts : Posts(where : { _slug_nany : [$slug] }) {
items {
_id,
_slug,
date: _publish_on
title,
summary,
author {
name
cover {
cdn_files {
url(width: 100, height:100)
}
}
}
cover {
cdn_files {
url(width:2000, height:1000)
}
}
}
}
}`
)
.graphqlVariables({
slug: slug,
})
.token(
preview
? process.env.PREPRIO_PREVIEW_TOKEN
: process.env.PREPRIO_PRODUCTION_TOKEN
)
.fetch()) || []
return data.data
}
export async function getPreviewPostBySlug(slug) {
// Query publications
const data =
(await prepr
.graphqlQuery(
`
query preview($slug: String!) {
Post ( slug : $slug) {
_id,
slug : _slug
}
}`
)
.token(process.env.PREPRIO_PREVIEW_TOKEN)
.graphqlVariables({
slug: slug,
})
.fetch()) || []
return data.data.Post
}

View File

@@ -0,0 +1,67 @@
{
"id": "f7153965-7bc9-4b9b-b964-49129b34c5e8",
"created_on": "2021-03-04T12:03:46+00:00",
"changed_on": "2021-03-04T12:03:46+00:00",
"body": "Author",
"description": null,
"label": "PublicationModel",
"status": "published",
"stories": false,
"timelines": false,
"allow_stories": false,
"channels": false,
"allow_channels": false,
"container_required": false,
"channels_required": false,
"seo_score": false,
"ab_testing": false,
"versioning": false,
"slug": null,
"for": null,
"fields": [
{
"type": "Text",
"required": false,
"preview": true,
"body": "Name",
"view": "single_line",
"localized": true,
"id": "fd7f062f-84e4-4362-9e15-61c1a26a4078",
"api_id": "name",
"created_on": "2021-03-04T12:03:55+00:00",
"changed_on": "2021-03-04T12:03:55+00:00",
"label": "PublicationModelField",
"title": false,
"seo_title": false,
"seo_description": false,
"description": null,
"disable_editing": false,
"appearance": "single_line",
"accept_restrictions": null,
"no_html": false
},
{
"accept": ["photo"],
"max": "1",
"preview": true,
"type": "Asset",
"min": "1",
"required": true,
"body": "Cover Image",
"localized": true,
"id": "fd81a8e2-2f59-44b7-b3b2-873a27958db1",
"api_id": "cover",
"created_on": "2021-03-04T12:04:13+00:00",
"changed_on": "2021-03-04T12:04:13+00:00",
"label": "PublicationModelField",
"title": false,
"seo_title": false,
"seo_description": false,
"description": null,
"disable_editing": false,
"appearance": null,
"accept_restrictions": null,
"presets_change_required": false
}
]
}

View File

@@ -0,0 +1,158 @@
{
"id": "4da8ca3d-86c2-40ba-84c0-5ea949293b9b",
"created_on": "2021-03-04T12:02:44+00:00",
"changed_on": "2021-03-04T12:10:37+00:00",
"body": "Post",
"description": null,
"label": "PublicationModel",
"status": "published",
"stories": false,
"timelines": false,
"allow_stories": false,
"channels": false,
"allow_channels": false,
"container_required": false,
"channels_required": false,
"seo_score": false,
"ab_testing": false,
"versioning": false,
"slug": null,
"for": null,
"fields": [
{
"type": "Text",
"required": false,
"preview": true,
"body": "Title",
"view": "single_line",
"localized": true,
"id": "7aa96451-d3b5-41e9-b012-77f66dd2213b",
"api_id": "title",
"created_on": "2021-03-04T12:02:49+00:00",
"changed_on": "2021-03-04T12:02:49+00:00",
"label": "PublicationModelField",
"title": false,
"seo_title": false,
"seo_description": false,
"description": null,
"disable_editing": false,
"appearance": "single_line",
"accept_restrictions": null,
"no_html": false
},
{
"type": "Text",
"required": false,
"preview": true,
"body": "Summary",
"view": "textarea",
"localized": true,
"id": "ea6a35ca-5a39-4786-9cf7-15e917a0dcf4",
"api_id": "summary",
"created_on": "2021-03-04T12:02:59+00:00",
"changed_on": "2021-03-04T12:02:59+00:00",
"label": "PublicationModelField",
"title": false,
"seo_title": false,
"seo_description": false,
"description": null,
"disable_editing": false,
"appearance": "textarea",
"accept_restrictions": null,
"no_html": false
},
{
"accept": [
"bold",
"italic",
"underline",
"unordered-list",
"ordered-list",
"link",
"table"
],
"preview": true,
"view": "html_editor",
"type": "Text",
"required": false,
"body": "Content",
"localized": true,
"id": "cd31e930-a08c-4740-903e-5c41fcd1c555",
"api_id": "content",
"created_on": "2021-03-04T12:04:36+00:00",
"changed_on": "2021-03-04T12:04:36+00:00",
"label": "PublicationModelField",
"title": false,
"seo_title": false,
"seo_description": false,
"description": null,
"disable_editing": false,
"appearance": "html_editor",
"accept_restrictions": null,
"no_html": false
},
{
"accept": ["photo"],
"max": "1",
"preview": true,
"type": "Asset",
"min": "1",
"required": true,
"body": "Cover Image",
"localized": true,
"id": "cfca83f3-5a73-4567-bde1-4adeb57915d0",
"api_id": "cover",
"created_on": "2021-03-04T12:03:17+00:00",
"changed_on": "2021-03-04T12:03:17+00:00",
"label": "PublicationModelField",
"title": false,
"seo_title": false,
"seo_description": false,
"description": null,
"disable_editing": false,
"appearance": null,
"accept_restrictions": null,
"presets_change_required": false
},
{
"type": "Publication",
"min": "1",
"required": true,
"max": "1",
"preview": false,
"body": "Author",
"localized": true,
"id": "8308380f-af0a-40e7-ae30-33b2f7ce93d9",
"api_id": "author",
"created_on": "2021-03-04T12:04:51+00:00",
"changed_on": "2021-03-04T12:04:51+00:00",
"label": "PublicationModelField",
"title": false,
"seo_title": false,
"seo_description": false,
"description": null,
"disable_editing": false,
"appearance": null,
"accept_restrictions": null
},
{
"type": "Slug",
"description": "The slug is generated automatically. You can change the slug, as long as it is unique.",
"body": "Slug",
"id": "7214e365-1b4c-4de3-8412-e311250fb4da",
"api_id": null,
"created_on": "2021-03-04T12:03:32+00:00",
"changed_on": "2021-03-04T12:03:32+00:00",
"label": "PublicationModelField",
"title": false,
"seo_title": false,
"seo_description": false,
"required": false,
"localized": false,
"preview": false,
"disable_editing": false,
"appearance": null,
"accept_restrictions": null
}
]
}

View File

@@ -0,0 +1,5 @@
module.exports = {
images: {
domains: ['b-cdn.net'],
},
}

View File

@@ -0,0 +1,25 @@
{
"name": "cms-prepr",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@preprio/nodejs-sdk": "^1.1.0",
"autoprefixer": "10.1.0",
"classnames": "2.2.6",
"date-fns": "2.10.0",
"next": "latest",
"postcss": "8.2.2",
"react": "17.0.1",
"react-dom": "17.0.1"
},
"devDependencies": {
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^6.7.0",
"tailwindcss": "2.0.2"
},
"license": "MIT"
}

View File

@@ -0,0 +1,7 @@
import '../styles/index.css'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp

View File

@@ -0,0 +1,15 @@
import Document, { Html, Head, Main, NextScript } from 'next/document'
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}

View File

@@ -0,0 +1,8 @@
export default async function handler(_, res) {
// Exit the current user from "Preview Mode". This function accepts no args.
res.clearPreviewData()
// Redirect the user back to the index page.
res.writeHead(307, { Location: '/' })
res.end()
}

View File

@@ -0,0 +1,25 @@
import { getPreviewPostBySlug } from '../../lib/preprio'
export default async function handler(req, res) {
// Check the secret and next parameters
// This secret should only be known to this API route and the CMS
if (req.query.secret !== process.env.PREPRIO_PREVIEW_KEY || !req.query.slug) {
return res.status(401).json({ message: 'Invalid token' })
}
// Fetch the headless CMS to check if the provided `slug` exists
const post = await getPreviewPostBySlug(req.query.slug)
// If the slug doesn't exist prevent preview mode from being enabled
if (!post) {
return res.status(401).json({ message: 'Invalid slug' })
}
// Enable Preview Mode by setting the cookies
res.setPreviewData({})
// Redirect to the path from the fetched post
// We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
res.writeHead(307, { Location: `/posts/${post.slug}` })
res.end()
}

View File

@@ -0,0 +1,44 @@
import Container from '../components/container'
import MoreStories from '../components/more-stories'
import HeroPost from '../components/hero-post'
import Intro from '../components/intro'
import Layout from '../components/layout'
import { getAllPostsForHome } from '../lib/preprio'
import Head from 'next/head'
import { CMS_NAME } from '../lib/constants'
export default function Index({ posts, preview }) {
const heroPost = posts[0]
const morePosts = posts.slice(1)
return (
<>
<Layout preview={preview}>
<Head>
<title>Next.js Blog Example with {CMS_NAME}</title>
</Head>
<Container>
<Intro />
{heroPost && (
<HeroPost
title={heroPost.title}
coverImage={heroPost.cover[0].cdn_files[0].url}
date={heroPost.date}
author={heroPost.author[0]}
slug={heroPost._slug}
excerpt={heroPost.summary}
/>
)}
{morePosts.length > 0 && <MoreStories posts={morePosts} />}
</Container>
</Layout>
</>
)
}
export async function getStaticProps({ preview = false }) {
const posts = (await getAllPostsForHome(preview)) || []
return {
props: { posts, preview },
}
}

View File

@@ -0,0 +1,75 @@
import { useRouter } from 'next/router'
import ErrorPage from 'next/error'
import Container from 'components/container'
import PostBody from 'components/post-body'
import MoreStories from 'components/more-stories'
import Header from 'components/header'
import PostHeader from 'components/post-header'
import SectionSeparator from 'components/section-separator'
import Layout from 'components/layout'
import { getAllPostsWithSlug, getPostAndMorePosts } from 'lib/preprio'
import PostTitle from 'components/post-title'
import Head from 'next/head'
import { CMS_NAME } from 'lib/constants'
export default function Post({ post, morePosts, preview }) {
const router = useRouter()
if (!router.isFallback && !post?._slug) {
return <ErrorPage statusCode={404} />
}
return (
<Layout preview={preview}>
<Container>
<Header />
{router.isFallback ? (
<PostTitle>Loading</PostTitle>
) : (
<>
<article>
<Head>
<title>
{post.title} | Next.js Blog Example with {CMS_NAME}
</title>
{/* <meta property="og:image" content={post.ogImage.url} /> */}
</Head>
<PostHeader
title={post.title}
coverImage={post.cover[0].cdn_files[0].url}
date={post.date}
author={post.author[0]}
/>
<PostBody content={post.content} />
</article>
<SectionSeparator />
{morePosts.length > 0 && <MoreStories posts={morePosts} />}
</>
)}
</Container>
</Layout>
)
}
export async function getStaticProps({ params, preview = false }) {
const data = await getPostAndMorePosts(params.slug, preview)
return {
props: {
preview,
post: data.Post,
morePosts: data.morePosts.items || [],
},
}
}
export async function getStaticPaths() {
const posts = await getAllPostsWithSlug()
return {
paths: posts.map(({ slug }) => ({
params: { slug },
})),
fallback: true,
}
}

View File

@@ -0,0 +1,18 @@
module.exports = {
plugins: [
'tailwindcss',
'postcss-flexbugs-fixes',
[
'postcss-preset-env',
{
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
features: {
'custom-properties': false,
},
},
],
],
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/favicons/mstile-150x150.png"/>
<TileColor>#000000</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1024.000000pt" height="1024.000000pt" viewBox="0 0 1024.000000 1024.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,1024.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M4785 10234 c-22 -2 -92 -9 -155 -14 -1453 -131 -2814 -915 -3676
-2120 -480 -670 -787 -1430 -903 -2235 -41 -281 -46 -364 -46 -745 0 -381 5
-464 46 -745 278 -1921 1645 -3535 3499 -4133 332 -107 682 -180 1080 -224
155 -17 825 -17 980 0 687 76 1269 246 1843 539 88 45 105 57 93 67 -8 6 -383
509 -833 1117 l-818 1105 -1025 1517 c-564 834 -1028 1516 -1032 1516 -4 1 -8
-673 -10 -1496 -3 -1441 -4 -1499 -22 -1533 -26 -49 -46 -69 -88 -91 -32 -16
-60 -19 -211 -19 l-173 0 -46 29 c-30 19 -52 44 -67 73 l-21 45 2 2005 3 2006
31 39 c16 21 50 48 74 61 41 20 57 22 230 22 204 0 238 -8 291 -66 15 -16 570
-852 1234 -1859 664 -1007 1572 -2382 2018 -3057 l810 -1227 41 27 c363 236
747 572 1051 922 647 743 1064 1649 1204 2615 41 281 46 364 46 745 0 381 -5
464 -46 745 -278 1921 -1645 3535 -3499 4133 -327 106 -675 179 -1065 223 -96
10 -757 21 -840 13z m2094 -3094 c48 -24 87 -70 101 -118 8 -26 10 -582 8
-1835 l-3 -1798 -317 486 -318 486 0 1307 c0 845 4 1320 10 1343 16 56 51 100
99 126 41 21 56 23 213 23 148 0 174 -2 207 -20z"/>
<path d="M7843 789 c-35 -22 -46 -37 -15 -20 22 13 58 40 52 41 -3 0 -20 -10
-37 -21z"/>
<path d="M7774 744 c-18 -14 -18 -15 4 -4 12 6 22 13 22 15 0 8 -5 6 -26 -11z"/>
<path d="M7724 714 c-18 -14 -18 -15 4 -4 12 6 22 13 22 15 0 8 -5 6 -26 -11z"/>
<path d="M7674 684 c-18 -14 -18 -15 4 -4 12 6 22 13 22 15 0 8 -5 6 -26 -11z"/>
<path d="M7598 644 c-38 -20 -36 -28 2 -9 17 9 30 18 30 20 0 7 -1 6 -32 -11z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,19 @@
{
"name": "Next.js",
"short_name": "Next.js",
"icons": [
{
"src": "/favicons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/favicons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#000000",
"background_color": "#000000",
"display": "standalone"
}

View File

@@ -0,0 +1,5 @@
/* purgecss start ignore */
@tailwind base;
@tailwind components;
/* purgecss end ignore */
@tailwind utilities;

View File

@@ -0,0 +1,33 @@
module.exports = {
purge: ['./components/**/*.js', './pages/**/*.js'],
theme: {
extend: {
colors: {
'accent-1': '#FAFAFA',
'accent-2': '#EAEAEA',
'accent-7': '#333',
success: '#0070f3',
cyan: '#79FFE1',
},
spacing: {
28: '7rem',
},
letterSpacing: {
tighter: '-.04em',
},
lineHeight: {
tight: 1.2,
},
fontSize: {
'5xl': '2.5rem',
'6xl': '2.75rem',
'7xl': '4.5rem',
'8xl': '6.25rem',
},
boxShadow: {
small: '0 5px 10px rgba(0, 0, 0, 0.12)',
medium: '0 8px 30px rgba(0, 0, 0, 0.12)',
},
},
},
}

View File

@@ -43,7 +43,7 @@ yarn create next-app --example cms-strapi cms-strapi-app
### Step 1. Set up Strapi locally
[Follow the instructions on this page](https://strapi.io/documentation/v3.x/installation/cli.html) to create a Strapi project locally.
[Follow the instructions on this page](https://strapi.io/documentation/developer-docs/latest/getting-started/quick-start.html#_1-install-strapi-and-create-a-new-project) to create a Strapi project locally.
```bash
npx create-strapi-app my-project --quickstart

View File

@@ -9,7 +9,7 @@ exports['default'] = {
secure: false,
// Passed to https.createServer if secure=true. Should contain SSL certificates
serverOptions: {},
// Should we redirect all traffic to the first host in this array if hte request header doesn't match?
// Should we redirect all traffic to the first host in this array if the request header doesn't match?
// i.e.: [ 'https://www.site.com' ]
allowedRequestHosts: process.env.ALLOWED_HOSTS
? process.env.ALLOWED_HOSTS.split(',')

View File

@@ -8,8 +8,8 @@
},
"dependencies": {
"next": "latest",
"react": "^16.13.1",
"react-dom": "^16.13.1"
"react": "^17.0.1",
"react-dom": "^17.0.1"
},
"license": "MIT"
}

View File

@@ -0,0 +1,27 @@
# Styled-JSX with Content Security Policy
This example showcases how you can use `nonce` for `style-src` directive in `Content Security Policy` with `styled-jsx`.
Checkout the [demo](https://styled-jsx-with-csp.vercel.app/) and notice the following,
- `style-src` directive in `Content-Security-Policy` response header.
- `meta` tag to pass on the `nonce` to styled-jsx for client-side rendering.
- `style` tags with `nonce` attributes.
## Deploy your own
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/styled-jsx-with-csp&project-name=styled-jsx-with-csp&repository-name=styled-jsx-with-csp)
## 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 styled-jsx-with-csp styled-jsx-with-csp-app
# or
yarn create next-app --example styled-jsx-with-csp styled-jsx-with-csp-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1,16 @@
{
"name": "styled-jsx-with-csp",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"nanoid": "3.1.21",
"next": "10.0.8",
"react": "17.0.1",
"react-dom": "17.0.1"
}
}

View File

@@ -0,0 +1,6 @@
const CustomApp = ({ Component, pageProps }) => <Component {...pageProps} />
// Disable static optimization to always server render, making nonce unique on every request
CustomApp.getInitialProps = () => ({})
export default CustomApp

View File

@@ -0,0 +1,49 @@
import Document, { Html, Head, Main, NextScript } from 'next/document'
import flush from 'styled-jsx/server'
import { nanoid } from 'nanoid'
class CustomDocument extends Document {
static async getInitialProps(ctx) {
const nonce = nanoid()
// https://github.com/vercel/next.js/blob/canary/packages/next/pages/_document.tsx#L89
const { html, head } = await ctx.renderPage()
// Adds `nonce` to style tags on Server Side Rendering
const styles = [...flush({ nonce })]
let contentSecurityPolicy = ''
if (process.env.NODE_ENV === 'production') {
contentSecurityPolicy = `default-src 'self'; style-src 'nonce-${nonce}';`
} else {
// react-refresh needs 'unsafe-eval'
// Next.js needs 'unsafe-inline' during development https://github.com/vercel/next.js/blob/canary/packages/next/client/dev/fouc.js
// Specifying 'nonce' makes a modern browsers ignore 'unsafe-inline'
contentSecurityPolicy = `default-src 'self'; style-src 'unsafe-inline'; script-src 'self' 'unsafe-eval';`
}
ctx.res.setHeader('Content-Security-Policy', contentSecurityPolicy)
return { styles, html, head, nonce }
}
render() {
return (
<Html>
<Head>
{/* Styled-JSX will add this `nonce` to style tags on Client Side Rendering */}
{/* https://github.com/vercel/styled-jsx/blob/master/src/lib/stylesheet.js#L31 */}
{/* https://github.com/vercel/styled-jsx/blob/master/src/lib/stylesheet.js#L240 */}
<meta property="csp-nonce" content={this.props.nonce} />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default CustomDocument

View File

@@ -0,0 +1,40 @@
import { useState } from 'react'
const ClientSideComponent = () => (
<>
<style jsx>
{`
.title {
font-size: 24px;
color: green;
}
`}
</style>
<p className="title">This is rendered on client-side</p>
</>
)
const Home = () => {
const [isVisible, setVisibility] = useState(false)
const toggleVisibility = () => {
setVisibility((prevState) => !prevState)
}
return (
<>
<style jsx>
{`
.title {
font-size: 24px;
}
`}
</style>
<p className="title">Styled-JSX with Content Security Policy</p>
<button onClick={toggleVisibility}>Toggle</button>
{isVisible ? <ClientSideComponent /> : null}
</>
)
}
export default Home

View File

@@ -7,12 +7,12 @@
"start": "next start"
},
"dependencies": {
"@chakra-ui/icons": "^1.0.0",
"@chakra-ui/react": "^1.0.0",
"@chakra-ui/theme-tools": "1.0.0",
"@emotion/react": "11.1.1",
"@emotion/styled": "11.0.0",
"framer-motion": "^2.9.4",
"@chakra-ui/icons": "^1.0.5",
"@chakra-ui/react": "^1.3.3",
"@chakra-ui/theme-tools": "1.0.4",
"@emotion/react": "11.1.5",
"@emotion/styled": "11.1.5",
"framer-motion": "^3.5.2",
"next": "latest",
"react": "^17.0.1",
"react-dom": "^17.0.1"

View File

@@ -0,0 +1,4 @@
{
"presets": ["next/babel"],
"plugins": ["@babel/plugin-syntax-jsx"]
}

View File

@@ -0,0 +1,34 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel

View File

@@ -1,21 +1,21 @@
# @zeit/fetch example
# Example app with [Compiled](https://github.com/atlassian-labs/compiled) (CSS-in-JS)
This example shows how to use [`@zeit/fetch`](https://npmjs.com/package/@zeit/fetch) in a Next.js application.
This example features how to use [Compiled](https://github.com/atlassian-labs/compiled) as the build time CSS-in-JS styling solution instead of [styled-jsx](https://github.com/zeit/styled-jsx).
## Deploy your own
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-zeit-fetch&project-name=with-zeit-fetch&repository-name=with-zeit-fetch)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-compiled-css&project-name=with-compiled-css&repository-name=with-compiled-css)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
```bash
npx create-next-app --example with-zeit-fetch with-zeit-fetch-app
npx create-next-app --example with-compiled-css with-compiled-css-app
# or
yarn create next-app --example with-zeit-fetch with-zeit-fetch-app
yarn create next-app --example with-compiled-css with-compiled-css-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

View File

@@ -0,0 +1,19 @@
import { ClassNames } from '@compiled/react'
import { error } from '../style/colors'
export const BoxStyles = ({ children }) => (
<ClassNames>
{({ css }) =>
children({
className: css`
display: flex;
width: 100px;
height: 100px;
border: 1px solid ${error};
padding: 8px;
flex-direction: column;
`,
})
}
</ClassNames>
)

View File

@@ -0,0 +1,11 @@
import { styled } from '@compiled/react'
export const Button = styled.button`
color: ${(props) => props.color};
background-color: transparent;
padding: 6px 8px;
border-radius: 3px;
width: 100%;
font-family: sans-serif;
border: 1px solid ${(props) => props.color};
`

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