├── .editorconfig ├── .eslintignore ├── .eslintrc.cjs ├── .github ├── .kodiak.toml ├── CODEOWNERS ├── pull_request_template.md └── workflows │ ├── deno-test.yml │ ├── e2e-report.yml │ ├── lint.yml │ ├── pre-release.yml │ ├── release-please.yml │ ├── run-tests.yml │ ├── size-check.yml │ └── test-e2e.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.cjs ├── .release-please-manifest.json ├── .vscode └── settings.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── deno.json ├── e2e-report ├── .eslintrc.json ├── .gitignore ├── README.md ├── app │ ├── badge │ │ └── route.js │ ├── globals.css │ ├── layout.js │ └── page.js ├── components │ ├── copy-badge.js │ ├── icons.js │ ├── stats.js │ ├── switcher.js │ └── table.js ├── data │ ├── issues.json │ └── test-results.json ├── jsconfig.json ├── netlify.toml ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.js ├── public │ ├── MulishVar-latin.woff2 │ ├── favicon.ico │ └── logo.svg ├── tailwind.config.js └── utils │ ├── consts.js │ └── data.js ├── edge-runtime ├── README.md ├── lib │ ├── headers.ts │ ├── logging.ts │ ├── middleware.test.ts │ ├── middleware.ts │ ├── next-request.ts │ ├── response.ts │ ├── routing.ts │ ├── util.test.ts │ └── util.ts ├── matchers.json ├── middleware.ts ├── next.config.json ├── shim │ └── index.js └── vendor.ts ├── manifest.yml ├── next-js-runtime.png ├── package-lock.json ├── package.json ├── playwright.config.ts ├── release-please-config.json ├── renovate.json ├── report ├── netlify.toml ├── style.css └── test-results.json ├── run-local-test.sh ├── src ├── build │ ├── advanced-api-routes.ts │ ├── cache.ts │ ├── content │ │ ├── next-shims │ │ │ └── telemetry-storage.cts │ │ ├── prerendered.ts │ │ ├── server.test.ts │ │ ├── server.ts │ │ ├── static.test.ts │ │ └── static.ts │ ├── functions │ │ ├── edge.ts │ │ └── server.ts │ ├── image-cdn.test.ts │ ├── image-cdn.ts │ ├── plugin-context.test.ts │ ├── plugin-context.ts │ ├── templates │ │ ├── handler-monorepo.tmpl.js │ │ └── handler.tmpl.js │ └── verification.ts ├── index.ts ├── run │ ├── config.ts │ ├── constants.ts │ ├── handlers │ │ ├── cache.cts │ │ ├── request-context.cts │ │ ├── server.ts │ │ ├── tags-handler.cts │ │ ├── tracer.cts │ │ ├── use-cache-handler.ts │ │ └── wait-until.cts │ ├── headers.test.ts │ ├── headers.ts │ ├── next.cts │ ├── revalidate.ts │ └── storage │ │ ├── regional-blob-store.cts │ │ ├── request-scoped-in-memory-cache.cts │ │ ├── storage.cts │ │ └── storage.test.ts └── shared │ ├── blob-types.cts │ ├── blob-types.test.ts │ ├── blobkey.test.ts │ ├── blobkey.ts │ └── cache-types.cts ├── tests ├── e2e-skip-retry-legacy.json ├── e2e-skip-retry.json ├── e2e-utils-v2.patch ├── e2e-utils.patch ├── e2e │ ├── after.test.ts │ ├── cli-before-regional-blobs-support.test.ts │ ├── dynamic-cms.test.ts │ ├── edge-middleware.test.ts │ ├── export.test.ts │ ├── nx-integrated.test.ts │ ├── on-demand-app.test.ts │ ├── package-manager.test.ts │ ├── page-router.test.ts │ ├── simple-app.test.ts │ └── turborepo.test.ts ├── fixtures │ ├── advanced-api-routes │ │ ├── next-env.d.ts │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ └── api │ │ │ │ ├── hello-background.ts │ │ │ │ └── hello-scheduled.js │ │ └── tsconfig.json │ ├── after │ │ ├── app │ │ │ ├── after │ │ │ │ ├── check │ │ │ │ │ └── page.js │ │ │ │ └── trigger │ │ │ │ │ └── page.js │ │ │ └── layout.js │ │ ├── next.config.js │ │ └── package.json │ ├── base-path │ │ ├── app │ │ │ ├── layout.js │ │ │ ├── other │ │ │ │ └── page.js │ │ │ └── page.js │ │ ├── next.config.js │ │ ├── package.json │ │ └── public │ │ │ ├── next.svg │ │ │ └── squirrel.jpg │ ├── cli-before-regional-blobs-support │ │ ├── next.config.js │ │ ├── package.json │ │ └── pages │ │ │ └── index.js │ ├── dist-dir │ │ ├── .gitignore │ │ ├── app │ │ │ ├── api │ │ │ │ ├── headers │ │ │ │ │ └── route.js │ │ │ │ └── url │ │ │ │ │ └── route.js │ │ │ ├── image │ │ │ │ └── page.js │ │ │ ├── layout.js │ │ │ ├── other │ │ │ │ └── page.js │ │ │ ├── page.js │ │ │ ├── redirect │ │ │ │ ├── response │ │ │ │ │ └── route.js │ │ │ │ └── route.js │ │ │ └── stale-cache-serving │ │ │ │ └── app-page │ │ │ │ └── page.js │ │ ├── next.config.js │ │ ├── package.json │ │ └── public │ │ │ ├── next.svg │ │ │ └── squirrel.jpg │ ├── dynamic-cms │ │ ├── README.md │ │ ├── netlify │ │ │ └── functions │ │ │ │ └── cms.mts │ │ ├── next.config.js │ │ ├── package.json │ │ └── pages │ │ │ ├── 404.js │ │ │ ├── api │ │ │ └── revalidate.js │ │ │ └── content │ │ │ └── [...slug].js │ ├── middleware-conditions │ │ ├── app │ │ │ ├── layout.js │ │ │ ├── other │ │ │ │ └── page.js │ │ │ ├── page.js │ │ │ └── test │ │ │ │ ├── next │ │ │ │ └── page.js │ │ │ │ ├── redirect │ │ │ │ └── page.js │ │ │ │ └── rewrite │ │ │ │ └── page.js │ │ ├── middleware.ts │ │ ├── next.config.js │ │ └── package.json │ ├── middleware-i18n-excluded-paths │ │ ├── middleware.ts │ │ ├── next-env.d.ts │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ ├── [[...catchall]].tsx │ │ │ └── api │ │ │ │ └── [[...catchall]].ts │ │ └── tsconfig.json │ ├── middleware-i18n-skip-normalize │ │ ├── middleware.js │ │ ├── next.config.js │ │ ├── package.json │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── api │ │ │ └── ok.js │ │ │ ├── dynamic │ │ │ └── [slug].js │ │ │ ├── index.js │ │ │ └── new-home.js │ ├── middleware-i18n │ │ ├── middleware.js │ │ ├── next.config.js │ │ ├── package.json │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── api │ │ │ └── ok.js │ │ │ ├── dynamic │ │ │ └── [slug].js │ │ │ ├── index.js │ │ │ └── new-home.js │ ├── middleware-og │ │ ├── app │ │ │ ├── layout.js │ │ │ ├── og.js │ │ │ ├── opengraph-image.js │ │ │ └── page.js │ │ ├── next.config.js │ │ └── package.json │ ├── middleware-pages │ │ ├── middleware.js │ │ ├── next-env.d.ts │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ ├── [id].js │ │ │ ├── _app.js │ │ │ ├── about │ │ │ │ ├── a.js │ │ │ │ └── b.js │ │ │ ├── api │ │ │ │ ├── edge-headers.js │ │ │ │ └── headers.js │ │ │ ├── blog │ │ │ │ └── [slug].js │ │ │ ├── error-throw.js │ │ │ ├── error.js │ │ │ ├── html-links.js │ │ │ ├── product │ │ │ │ └── [...product-params].tsx │ │ │ ├── shallow.js │ │ │ ├── ssg │ │ │ │ └── [slug].js │ │ │ ├── ssr-page-2.js │ │ │ └── ssr-page.js │ │ └── tsconfig.json │ ├── middleware-src │ │ ├── next.config.js │ │ ├── package.json │ │ └── src │ │ │ ├── app │ │ │ ├── layout.js │ │ │ ├── page.js │ │ │ └── test │ │ │ │ └── next │ │ │ │ └── page.js │ │ │ └── middleware.ts │ ├── middleware-static-asset-matcher │ │ ├── app │ │ │ ├── layout.js │ │ │ └── page.js │ │ ├── middleware.ts │ │ ├── next.config.js │ │ ├── package.json │ │ └── public │ │ │ └── hello │ │ │ └── world.txt │ ├── middleware-subrequest-vuln │ │ ├── app │ │ │ ├── [[...wildcard]] │ │ │ │ └── page.js │ │ │ └── layout.js │ │ ├── middleware.ts │ │ ├── next.config.js │ │ └── package.json │ ├── middleware-trailing-slash │ │ ├── app │ │ │ ├── layout.js │ │ │ ├── other │ │ │ │ └── page.js │ │ │ ├── page.js │ │ │ └── test │ │ │ │ ├── next │ │ │ │ └── page.js │ │ │ │ ├── redirect │ │ │ │ └── page.js │ │ │ │ └── rewrite │ │ │ │ └── page.js │ │ ├── middleware.ts │ │ ├── next.config.js │ │ └── package.json │ ├── middleware │ │ ├── app │ │ │ ├── caching-redirect-target │ │ │ │ └── page.js │ │ │ ├── caching-rewrite-target │ │ │ │ └── page.js │ │ │ ├── layout.js │ │ │ ├── link-to-redirect-to-cached-page │ │ │ │ └── page.js │ │ │ ├── link-to-rewrite-to-cached-page │ │ │ │ └── page.js │ │ │ ├── other │ │ │ │ └── page.js │ │ │ ├── page.js │ │ │ └── test │ │ │ │ ├── next │ │ │ │ └── page.js │ │ │ │ ├── redirect │ │ │ │ └── page.js │ │ │ │ ├── rewrite-target │ │ │ │ └── page.js │ │ │ │ └── rewrite │ │ │ │ └── page.js │ │ ├── middleware.ts │ │ ├── next.config.js │ │ └── package.json │ ├── netlify-forms-workaround │ │ ├── app │ │ │ ├── layout.js │ │ │ └── page.js │ │ ├── next.config.js │ │ ├── package.json │ │ ├── public │ │ │ └── form.html │ │ └── tsconfig.json │ ├── netlify-forms │ │ ├── app │ │ │ ├── layout.js │ │ │ └── page.js │ │ ├── next-env.d.ts │ │ ├── next.config.js │ │ ├── package.json │ │ ├── public │ │ │ └── form.html │ │ └── tsconfig.json │ ├── nx-integrated │ │ ├── .gitignore │ │ ├── .npmrc │ │ ├── apps │ │ │ ├── custom-dist-dir │ │ │ │ ├── .env │ │ │ │ ├── .env.local │ │ │ │ ├── .env.production │ │ │ │ ├── .env.production.local │ │ │ │ ├── app │ │ │ │ │ ├── api │ │ │ │ │ │ ├── env │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── headers │ │ │ │ │ │ │ └── route.js │ │ │ │ │ │ └── url │ │ │ │ │ │ │ └── route.js │ │ │ │ │ ├── image │ │ │ │ │ │ └── page.js │ │ │ │ │ ├── layout.js │ │ │ │ │ ├── other │ │ │ │ │ │ └── page.js │ │ │ │ │ ├── page.js │ │ │ │ │ ├── redirect │ │ │ │ │ │ ├── response │ │ │ │ │ │ │ └── route.js │ │ │ │ │ │ └── route.js │ │ │ │ │ └── stale-cache-serving │ │ │ │ │ │ └── app-page │ │ │ │ │ │ └── page.js │ │ │ │ ├── next-env.d.ts │ │ │ │ ├── next.config.js │ │ │ │ ├── project.json │ │ │ │ ├── public │ │ │ │ │ ├── next.svg │ │ │ │ │ └── squirrel.jpg │ │ │ │ ├── tsconfig.json │ │ │ │ └── tsconfig.spec.json │ │ │ └── next-app │ │ │ │ ├── app │ │ │ │ ├── api │ │ │ │ │ ├── hello │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── static │ │ │ │ │ │ └── route.js │ │ │ │ ├── global.css │ │ │ │ ├── layout.tsx │ │ │ │ ├── page.module.css │ │ │ │ └── page.tsx │ │ │ │ ├── index.d.ts │ │ │ │ ├── netlify.toml │ │ │ │ ├── next-env.d.ts │ │ │ │ ├── next.config.js │ │ │ │ ├── project.json │ │ │ │ ├── public │ │ │ │ ├── .gitkeep │ │ │ │ └── favicon.ico │ │ │ │ ├── static │ │ │ │ └── words.txt │ │ │ │ ├── tsconfig.json │ │ │ │ └── tsconfig.spec.json │ │ ├── nx.json │ │ ├── package.json │ │ └── tsconfig.base.json │ ├── output-export-custom-dist │ │ ├── .gitignore │ │ ├── app │ │ │ ├── layout.js │ │ │ └── page.js │ │ ├── next.config.js │ │ ├── package.json │ │ └── public │ │ │ ├── next.svg │ │ │ └── squirrel.jpg │ ├── output-export │ │ ├── app │ │ │ ├── image │ │ │ │ └── local │ │ │ │ │ └── page.js │ │ │ ├── layout.js │ │ │ └── page.js │ │ ├── next.config.js │ │ ├── package.json │ │ └── public │ │ │ ├── next.svg │ │ │ └── squirrel.jpg │ ├── page-router-404-get-static-props-with-revalidate │ │ ├── next.config.js │ │ ├── package.json │ │ └── pages │ │ │ ├── 404.js │ │ │ └── products │ │ │ └── [slug].js │ ├── page-router-base-path-i18n │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ ├── 404.js │ │ │ ├── api │ │ │ │ ├── purge-cdn.js │ │ │ │ ├── revalidate-no-await.js │ │ │ │ └── revalidate.js │ │ │ ├── fallback-true │ │ │ │ └── [slug].js │ │ │ ├── products │ │ │ │ └── [slug].js │ │ │ └── static │ │ │ │ ├── not-found.js │ │ │ │ └── revalidate-manual.js │ │ └── public │ │ │ └── next.svg │ ├── page-router │ │ ├── .env │ │ ├── .env.local │ │ ├── .env.production │ │ ├── .env.production.local │ │ ├── netlify │ │ │ └── functions │ │ │ │ ├── purge-cdn.ts │ │ │ │ └── read-static-props-blobs.ts │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ ├── 404.js │ │ │ ├── always-the-same-body │ │ │ │ └── [slug].js │ │ │ ├── api │ │ │ │ ├── env.js │ │ │ │ ├── revalidate-no-await.js │ │ │ │ ├── revalidate.js │ │ │ │ ├── sleep-5.js │ │ │ │ └── unstable-cache-node.js │ │ │ ├── fallback-true │ │ │ │ └── [slug].js │ │ │ ├── products │ │ │ │ └── [slug].js │ │ │ ├── revalidate-60 │ │ │ │ └── [slug].js │ │ │ └── static │ │ │ │ ├── fully-static.js │ │ │ │ ├── not-found.js │ │ │ │ ├── revalidate-automatic.js │ │ │ │ ├── revalidate-manual.js │ │ │ │ ├── revalidate-slow-data.js │ │ │ │ └── revalidate-slow.js │ │ └── public │ │ │ └── next.svg │ ├── pnpm │ │ ├── .npmrc │ │ ├── app │ │ │ ├── layout.js │ │ │ ├── other │ │ │ │ └── page.js │ │ │ └── page.js │ │ ├── next.config.js │ │ └── package.json │ ├── ppr │ │ ├── app │ │ │ ├── layout.js │ │ │ └── page.js │ │ ├── next.config.js │ │ ├── package.json │ │ └── public │ │ │ ├── next.svg │ │ │ └── squirrel.jpg │ ├── revalidate-fetch │ │ ├── app │ │ │ ├── dynamic-posts │ │ │ │ └── [id] │ │ │ │ │ └── page.js │ │ │ ├── layout.js │ │ │ ├── page.js │ │ │ ├── posts │ │ │ │ └── [id] │ │ │ │ │ └── page.js │ │ │ └── same-fetch-multiple-times │ │ │ │ └── [id] │ │ │ │ └── page.js │ │ ├── next.config.js │ │ └── package.json │ ├── server-components │ │ ├── app │ │ │ ├── api │ │ │ │ ├── on-demand-revalidate │ │ │ │ │ ├── path │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── tag │ │ │ │ │ │ └── route.ts │ │ │ │ ├── purge-cdn │ │ │ │ │ └── route.ts │ │ │ │ ├── revalidate-handler │ │ │ │ │ └── route.ts │ │ │ │ ├── static │ │ │ │ │ └── [slug] │ │ │ │ │ │ └── route.ts │ │ │ │ └── zero-length-response │ │ │ │ │ └── route.ts │ │ │ ├── dynamic-fetch │ │ │ │ ├── loading.js │ │ │ │ └── page.js │ │ │ ├── layout.js │ │ │ ├── page.js │ │ │ ├── product │ │ │ │ └── [slug] │ │ │ │ │ └── page.js │ │ │ ├── revalidate-fetch │ │ │ │ └── page.js │ │ │ ├── static-fetch-1 │ │ │ │ └── page.js │ │ │ ├── static-fetch-2 │ │ │ │ └── page.js │ │ │ ├── static-fetch-3 │ │ │ │ └── page.js │ │ │ ├── static-fetch-dynamic │ │ │ │ └── page.js │ │ │ └── static-fetch │ │ │ │ └── [id] │ │ │ │ └── page.js │ │ ├── next-env.d.ts │ │ ├── next.config.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── simple │ │ ├── app │ │ │ ├── api │ │ │ │ ├── cached-permanent │ │ │ │ │ └── route.js │ │ │ │ ├── cached-revalidate │ │ │ │ │ └── route.js │ │ │ │ ├── cjs-file-with-js-extension │ │ │ │ │ ├── bundled.cjs │ │ │ │ │ └── route.js │ │ │ │ ├── headers │ │ │ │ │ └── route.js │ │ │ │ ├── slow-not-cacheable-with-html-read │ │ │ │ │ └── route.js │ │ │ │ ├── slow-not-cacheable │ │ │ │ │ └── route.js │ │ │ │ ├── static │ │ │ │ │ └── route.js │ │ │ │ └── url │ │ │ │ │ └── route.js │ │ │ ├── config-redirect │ │ │ │ ├── dest │ │ │ │ │ └── page.js │ │ │ │ └── page.js │ │ │ ├── config-rewrite │ │ │ │ ├── dest │ │ │ │ │ └── page.js │ │ │ │ └── page.js │ │ │ ├── image │ │ │ │ ├── local │ │ │ │ │ └── page.js │ │ │ │ ├── migration-from-v4-runtime │ │ │ │ │ ├── next-image-runtime-v4.js │ │ │ │ │ └── page.js │ │ │ │ ├── remote-domain │ │ │ │ │ └── page.js │ │ │ │ ├── remote-pattern-1 │ │ │ │ │ └── page.js │ │ │ │ └── remote-pattern-2 │ │ │ │ │ └── page.js │ │ │ ├── layout.js │ │ │ ├── not-found.js │ │ │ ├── other │ │ │ │ └── page.js │ │ │ ├── page.js │ │ │ ├── redirect │ │ │ │ ├── response │ │ │ │ │ └── route.js │ │ │ │ └── route.js │ │ │ ├── route-resolves-to-not-found │ │ │ │ └── page.js │ │ │ ├── stale-cache-serving │ │ │ │ └── app-page │ │ │ │ │ └── page.js │ │ │ └── unstable_cache │ │ │ │ └── page.js │ │ ├── cjs-file-with-js-extension.js │ │ ├── netlify.toml │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ └── fully-static.js │ │ ├── public │ │ │ ├── next.svg │ │ │ └── squirrel.jpg │ │ └── static │ │ │ ├── prebuilt.html │ │ │ └── words.txt │ ├── turborepo-npm │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── .npmrc │ │ ├── README.md │ │ ├── apps │ │ │ ├── docs │ │ │ │ ├── .eslintrc.js │ │ │ │ ├── README.md │ │ │ │ ├── app │ │ │ │ │ ├── favicon.ico │ │ │ │ │ ├── globals.css │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── page.module.css │ │ │ │ │ └── page.tsx │ │ │ │ ├── next-env.d.ts │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ ├── circles.svg │ │ │ │ │ ├── next.svg │ │ │ │ │ ├── turborepo.svg │ │ │ │ │ └── vercel.svg │ │ │ │ └── tsconfig.json │ │ │ ├── page-router │ │ │ │ ├── .env │ │ │ │ ├── .env.local │ │ │ │ ├── .env.production │ │ │ │ ├── .env.production.local │ │ │ │ ├── next-env.d.ts │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ ├── pages │ │ │ │ │ ├── api │ │ │ │ │ │ ├── env.js │ │ │ │ │ │ ├── purge-cdn.js │ │ │ │ │ │ └── revalidate.js │ │ │ │ │ └── static │ │ │ │ │ │ ├── revalidate-automatic.js │ │ │ │ │ │ ├── revalidate-manual.js │ │ │ │ │ │ └── revalidate-slow.js │ │ │ │ ├── public │ │ │ │ │ └── next.svg │ │ │ │ ├── test.cjs │ │ │ │ └── tsconfig.json │ │ │ └── web │ │ │ │ ├── .eslintrc.js │ │ │ │ ├── README.md │ │ │ │ ├── app │ │ │ │ ├── favicon.ico │ │ │ │ ├── globals.css │ │ │ │ ├── layout.tsx │ │ │ │ ├── page.module.css │ │ │ │ └── page.tsx │ │ │ │ ├── next-env.d.ts │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ ├── circles.svg │ │ │ │ ├── next.svg │ │ │ │ ├── turborepo.svg │ │ │ │ └── vercel.svg │ │ │ │ └── tsconfig.json │ │ ├── package.json │ │ ├── packages │ │ │ ├── eslint-config │ │ │ │ ├── README.md │ │ │ │ ├── library.js │ │ │ │ ├── next.js │ │ │ │ ├── package.json │ │ │ │ └── react-internal.js │ │ │ ├── typescript-config │ │ │ │ ├── base.json │ │ │ │ ├── nextjs.json │ │ │ │ ├── package.json │ │ │ │ └── react-library.json │ │ │ └── ui │ │ │ │ ├── .eslintrc.js │ │ │ │ ├── package.json │ │ │ │ ├── src │ │ │ │ ├── button.tsx │ │ │ │ ├── card.tsx │ │ │ │ └── code.tsx │ │ │ │ ├── tsconfig.json │ │ │ │ ├── tsconfig.lint.json │ │ │ │ ├── turbo.json │ │ │ │ └── turbo │ │ │ │ └── generators │ │ │ │ ├── config.ts │ │ │ │ └── templates │ │ │ │ └── component.hbs │ │ ├── tsconfig.json │ │ └── turbo.json │ ├── turborepo │ │ ├── .gitignore │ │ ├── .npmrc │ │ ├── .vscode │ │ │ └── settings.json │ │ ├── apps │ │ │ ├── docs │ │ │ │ ├── app │ │ │ │ │ ├── favicon.ico │ │ │ │ │ ├── globals.css │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── page.module.css │ │ │ │ │ └── page.tsx │ │ │ │ ├── next-env.d.ts │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ ├── circles.svg │ │ │ │ │ ├── next.svg │ │ │ │ │ ├── turborepo.svg │ │ │ │ │ └── vercel.svg │ │ │ │ └── tsconfig.json │ │ │ ├── page-router │ │ │ │ ├── next-env.d.ts │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ ├── src │ │ │ │ │ ├── middleware.ts │ │ │ │ │ └── pages │ │ │ │ │ │ ├── api │ │ │ │ │ │ ├── purge-cdn.js │ │ │ │ │ │ └── revalidate.js │ │ │ │ │ │ └── static │ │ │ │ │ │ ├── revalidate-automatic.js │ │ │ │ │ │ ├── revalidate-manual.js │ │ │ │ │ │ └── revalidate-slow.js │ │ │ │ └── tsconfig.json │ │ │ └── web │ │ │ │ ├── app │ │ │ │ ├── favicon.ico │ │ │ │ ├── globals.css │ │ │ │ ├── layout.tsx │ │ │ │ ├── page.module.css │ │ │ │ └── page.tsx │ │ │ │ ├── next-env.d.ts │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ ├── circles.svg │ │ │ │ ├── next.svg │ │ │ │ ├── turborepo.svg │ │ │ │ └── vercel.svg │ │ │ │ └── tsconfig.json │ │ ├── package.json │ │ ├── packages │ │ │ ├── typescript-config │ │ │ │ ├── base.json │ │ │ │ ├── nextjs.json │ │ │ │ ├── package.json │ │ │ │ └── react-library.json │ │ │ └── ui │ │ │ │ ├── package.json │ │ │ │ ├── src │ │ │ │ ├── button.tsx │ │ │ │ ├── card.tsx │ │ │ │ └── code.tsx │ │ │ │ ├── tsconfig.json │ │ │ │ ├── tsconfig.lint.json │ │ │ │ ├── turbo.json │ │ │ │ └── turbo │ │ │ │ └── generators │ │ │ │ ├── config.ts │ │ │ │ └── templates │ │ │ │ └── component.hbs │ │ ├── pnpm-workspace.yaml │ │ ├── tsconfig.json │ │ └── turbo.json │ ├── use-cache │ │ ├── app │ │ │ ├── api │ │ │ │ └── revalidate │ │ │ │ │ └── [...slug] │ │ │ │ │ └── route.ts │ │ │ ├── default │ │ │ │ ├── use-cache-component │ │ │ │ │ ├── dynamic │ │ │ │ │ │ ├── ttl-1year │ │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── ttl-5seconds │ │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── static │ │ │ │ │ │ ├── ttl-10seconds │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── ttl-1year │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ └── page.tsx │ │ │ │ ├── use-cache-data │ │ │ │ │ ├── dynamic │ │ │ │ │ │ ├── ttl-1year │ │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── ttl-5seconds │ │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── static │ │ │ │ │ │ ├── ttl-10seconds │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── ttl-1year │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ └── page.tsx │ │ │ │ └── use-cache-page │ │ │ │ │ ├── dynamic │ │ │ │ │ ├── ttl-1year │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── ttl-5seconds │ │ │ │ │ │ └── [slug] │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── static │ │ │ │ │ ├── ttl-10seconds │ │ │ │ │ └── [slug] │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── ttl-1year │ │ │ │ │ └── [slug] │ │ │ │ │ └── page.tsx │ │ │ ├── helpers.tsx │ │ │ └── layout.js │ │ ├── next-env.d.ts │ │ ├── next.config.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── wasm-src │ │ ├── next.config.js │ │ ├── package.json │ │ └── src │ │ │ ├── add.wasm │ │ │ ├── app │ │ │ ├── og-node │ │ │ │ └── route.js │ │ │ └── og │ │ │ │ └── route.js │ │ │ ├── middleware.js │ │ │ └── pages │ │ │ ├── api │ │ │ ├── og-wrong-runtime.js │ │ │ └── og.js │ │ │ └── index.js │ └── wasm │ │ ├── add.wasm │ │ ├── app │ │ ├── og-node │ │ │ └── route.js │ │ └── og │ │ │ └── route.js │ │ ├── middleware.js │ │ ├── next.config.js │ │ ├── package.json │ │ └── pages │ │ ├── api │ │ ├── og-wrong-runtime.js │ │ └── og.js │ │ └── index.js ├── index.ts ├── integration │ ├── advanced-api-routes.test.ts │ ├── build │ │ └── copy-next-code.test.ts │ ├── cache-handler.test.ts │ ├── edge-handler.test.ts │ ├── fetch-handler.test.ts │ ├── netlify-forms.test.ts │ ├── page-router.test.ts │ ├── pnpm.test.ts │ ├── request-context.test.ts │ ├── revalidate-path.test.ts │ ├── revalidate-tags.test.ts │ ├── simple-app.test.ts │ ├── static.test.ts │ ├── use-cache.test.ts │ └── wasm.test.ts ├── netlify-deploy.ts ├── netlify-e2e-legacy.json ├── netlify-e2e.cjs ├── playwright-slack-conf.json ├── prepare.mjs ├── smoke │ ├── deploy.test.ts │ └── fixtures │ │ ├── .gitignore │ │ ├── next-12.0.3 │ │ ├── next.config.js │ │ ├── package.json │ │ └── pages │ │ │ └── index.js │ │ ├── next-12.1.0 │ │ ├── next.config.js │ │ ├── package.json │ │ └── pages │ │ │ └── index.js │ │ ├── npm-monorepo-empty-base │ │ ├── apps │ │ │ └── site │ │ │ │ ├── netlify.toml │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ └── pages │ │ │ │ └── index.js │ │ ├── package.json │ │ └── packages │ │ │ └── ui │ │ │ ├── package.json │ │ │ └── src │ │ │ └── test.jsx │ │ ├── npm-monorepo-site-created-at-build │ │ ├── mock-download │ │ │ ├── apps │ │ │ │ └── site │ │ │ │ │ ├── next.config.js │ │ │ │ │ ├── package.json │ │ │ │ │ └── pages │ │ │ │ │ └── index.js │ │ │ └── packages │ │ │ │ └── ui │ │ │ │ ├── package.json │ │ │ │ └── src │ │ │ │ └── test.jsx │ │ ├── netlify.toml │ │ ├── package.json │ │ ├── pre-deploy.mjs │ │ └── setup-site.mjs │ │ ├── npm-nested-site-multiple-next-version-site-compatible │ │ ├── apps │ │ │ └── site │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ └── pages │ │ │ │ └── index.js │ │ └── package.json │ │ ├── npm-nested-site-multiple-next-version-site-incompatible │ │ ├── apps │ │ │ └── site │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ └── pages │ │ │ │ └── index.js │ │ └── package.json │ │ ├── yarn-monorepo-multiple-next-versions-site-compatible │ │ ├── apps │ │ │ └── site │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ └── pages │ │ │ │ └── index.js │ │ ├── package.json │ │ └── packages │ │ │ └── ui │ │ │ ├── package.json │ │ │ └── src │ │ │ └── test.jsx │ │ ├── yarn-monorepo-multiple-next-versions-site-incompatible │ │ ├── apps │ │ │ └── site │ │ │ │ ├── next.config.js │ │ │ │ ├── package.json │ │ │ │ └── pages │ │ │ │ └── index.js │ │ ├── package.json │ │ └── packages │ │ │ └── ui │ │ │ ├── package.json │ │ │ └── src │ │ │ └── test.jsx │ │ └── yarn-monorepo-with-pnpm-linker │ │ ├── .yarnrc.yml │ │ ├── apps │ │ └── site │ │ │ ├── next.config.js │ │ │ ├── package.json │ │ │ └── pages │ │ │ └── index.js │ │ ├── package.json │ │ └── packages │ │ └── ui │ │ ├── package.json │ │ └── src │ │ └── test.jsx ├── test-config.json ├── test-setup-e2e.ts ├── test-setup.ts └── utils │ ├── constants.mjs │ ├── contexts.ts │ ├── create-e2e-fixture.ts │ ├── fixture.ts │ ├── helpers.ts │ ├── index.ts │ ├── lambda-helpers.mjs │ ├── local-server.ts │ ├── mock-file-system.ts │ ├── next-version-helpers.mjs │ ├── playwright-helpers.ts │ └── sandbox-child.mjs ├── tools ├── build-helpers.js ├── build.js ├── deno │ ├── eszip.ts │ ├── generate-md.ts │ ├── ghIssues2json.ts │ └── junit2json.ts └── vendor-deno-tools.js ├── tsconfig.json ├── turbofan ├── netlify.toml └── netlify │ └── edge-functions │ └── turbofan.ts ├── vitest.config.ts └── vitest.workspace.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | max_line_length = 100 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | demo/ 3 | tests/ 4 | edge-runtime 5 | tools/deno -------------------------------------------------------------------------------- /.github/.kodiak.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [merge.automerge_dependencies] 4 | versions = ["minor", "patch"] 5 | usernames = ["renovate"] 6 | 7 | [approve] 8 | auto_approve_usernames = ["renovate"] -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @opennextjs/netlify-frameworks-and-build 2 | -------------------------------------------------------------------------------- /.github/workflows/deno-test.yml: -------------------------------------------------------------------------------- 1 | name: Deno test 2 | on: 3 | pull_request: 4 | branches: [main] 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | - name: Setup Deno 12 | uses: denoland/setup-deno@v1 13 | with: 14 | deno-version: v1.x.x 15 | - name: Vendor Deno modules 16 | run: deno vendor edge-runtime/vendor.ts --output=edge-runtime/vendor --force 17 | - name: Test 18 | run: deno test -A edge-runtime/ 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .next 4 | edge-runtime/vendor 5 | # deno.json is ephemeral and generated for the purpose of vendoring remote modules in CI 6 | tools/deno/deno.json 7 | tools/deno/vendor 8 | 9 | # Local Netlify folder 10 | .netlify 11 | 12 | /test-results/ 13 | /playwright-report/ 14 | /blob-report/ 15 | /playwright/.cache/ 16 | 17 | deno.lock 18 | .eslintcache 19 | .DS_Store 20 | tests/**/package-lock.json 21 | tests/**/pnpm-lock.yaml 22 | tests/**/yarn.lock 23 | tests/**/out/ 24 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .next 3 | playwright-report/ 4 | .netlify 5 | CHANGELOG.md 6 | package-lock.json 7 | package.json 8 | edge-runtime/vendor/ 9 | deno.lock 10 | tests/fixtures/dist-dir/cool/output 11 | tests/fixtures/output-export-custom-dist/custom-dist 12 | .nx 13 | custom-dist-dir 14 | pnpm.lock 15 | # to avoid needing extra permissions to format files 16 | .github/workflows -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('@netlify/eslint-config-node/.prettierrc.json'), 3 | printWidth: 100, 4 | } 5 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "5.11.2" 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enablePaths": ["tools/deno", "edge-runtime"], 3 | "deno.unstable": true 4 | } 5 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "lint": { 3 | "files": { 4 | "include": ["edge-runtime/middleware.ts"] 5 | } 6 | }, 7 | "imports": { 8 | "@netlify/edge-functions": "https://edge.netlify.com/v1/index.ts" 9 | }, 10 | "importMap": "./edge-runtime/vendor/import_map.json" 11 | } 12 | -------------------------------------------------------------------------------- /e2e-report/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "root": true 4 | } 5 | -------------------------------------------------------------------------------- /e2e-report/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /e2e-report/README.md: -------------------------------------------------------------------------------- 1 | # Next Runtime v5 Report 2 | -------------------------------------------------------------------------------- /e2e-report/app/layout.js: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | 3 | export const metadata = { 4 | title: 'Netlify - Next.js E2E Tests', 5 | } 6 | 7 | export default function RootLayout({ children }) { 8 | return ( 9 | 10 | {children} 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /e2e-report/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /e2e-report/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "e2e-report/" 3 | command = "next build" 4 | publish = ".next" 5 | 6 | [[plugins]] 7 | package = "@netlify/plugin-nextjs" -------------------------------------------------------------------------------- /e2e-report/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | export default nextConfig 5 | -------------------------------------------------------------------------------- /e2e-report/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /e2e-report/public/MulishVar-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/e2e-report/public/MulishVar-latin.woff2 -------------------------------------------------------------------------------- /e2e-report/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/e2e-report/public/favicon.ico -------------------------------------------------------------------------------- /e2e-report/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./app/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'], 4 | daisyui: { 5 | themes: ['light'], 6 | }, 7 | theme: { 8 | extend: { 9 | fontFamily: { 10 | primary: 'Mulish', 11 | }, 12 | colors: { 13 | primary: '#2036a1', 14 | }, 15 | }, 16 | }, 17 | plugins: [require('daisyui')], 18 | } 19 | -------------------------------------------------------------------------------- /e2e-report/utils/consts.js: -------------------------------------------------------------------------------- 1 | export const badgeSettings = { 2 | // Badge image resolution should be 2x display size for hi-res displays 3 | imageSize: { width: 370, height: 50 }, 4 | displaySize: { width: 185, height: 25 }, 5 | label: 'Next.js runtime v5', 6 | alt: 'Netlify Next.js runtime v5 test status', 7 | } 8 | -------------------------------------------------------------------------------- /edge-runtime/lib/logging.ts: -------------------------------------------------------------------------------- 1 | export { 2 | logger, 3 | LogLevel, 4 | StructuredLogger, 5 | } from '../vendor/v1-7-0--edge-utils.netlify.app/logger/mod.ts' 6 | -------------------------------------------------------------------------------- /edge-runtime/matchers.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /edge-runtime/next.config.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | name: '@netlify/plugin-nextjs' 2 | -------------------------------------------------------------------------------- /next-js-runtime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/next-js-runtime.png -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", 3 | "exclude-paths": [".github", ".vscode", "e2e-report", "report", "tests", "tools", "turbofan"], 4 | "include-component-in-tag": false, 5 | "packages": { 6 | ".": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["local>netlify/renovate-config"] 4 | } 5 | -------------------------------------------------------------------------------- /report/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "." 3 | -------------------------------------------------------------------------------- /report/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: 3 | system-ui, 4 | -apple-system, 5 | BlinkMacSystemFont, 6 | 'Segoe UI', 7 | Roboto, 8 | Oxygen, 9 | Ubuntu, 10 | Cantarell, 11 | 'Open Sans', 12 | 'Helvetica Neue', 13 | sans-serif; 14 | } 15 | 16 | .test-results { 17 | display: flex; 18 | flex-wrap: wrap; 19 | } 20 | 21 | .test-results a { 22 | display: inline-block; 23 | width: 16px; 24 | height: 16px; 25 | margin: 1px; 26 | } 27 | 28 | a[data-status='passed'] { 29 | background-color: #2ecc71; 30 | } 31 | 32 | a[data-status='failed'] { 33 | background-color: #e74c3c; 34 | } 35 | -------------------------------------------------------------------------------- /src/run/constants.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'node:path' 2 | import { fileURLToPath } from 'node:url' 3 | 4 | export const MODULE_DIR = fileURLToPath(new URL('.', import.meta.url)) 5 | export const PLUGIN_DIR = resolve(`${MODULE_DIR}../../..`) 6 | // a file where we store the required-server-files config object in to access during runtime 7 | export const RUN_CONFIG_FILE = 'run-config.json' 8 | -------------------------------------------------------------------------------- /tests/e2e-utils-v2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/test/lib/e2e-utils/index.ts b/test/lib/e2e-utils/index.ts 2 | index 06765e81d9..a7a5a9e4bd 100644 3 | --- a/test/lib/e2e-utils/index.ts 4 | +++ b/test/lib/e2e-utils/index.ts 5 | @@ -5,7 +5,7 @@ import { PHASE_DEVELOPMENT_SERVER } from 'next/constants' 6 | import { NextInstance, NextInstanceOpts } from '../next-modes/base' 7 | import { NextDevInstance } from '../next-modes/next-dev' 8 | import { NextStartInstance } from '../next-modes/next-start' 9 | -import { NextDeployInstance } from '../next-modes/next-deploy' 10 | +import { NextDeployInstance } from '../next-modes/netlify-deploy' 11 | import { shouldRunTurboDevTest } from '../next-test-utils' 12 | 13 | export type { NextInstance } 14 | -------------------------------------------------------------------------------- /tests/e2e-utils.patch: -------------------------------------------------------------------------------- 1 | diff --git a/test/lib/e2e-utils.ts b/test/lib/e2e-utils.ts 2 | index ee43a460d6..9f9aa30d33 100644 3 | --- a/test/lib/e2e-utils.ts 4 | +++ b/test/lib/e2e-utils.ts 5 | @@ -7,3 +7,3 @@ import { NextDevInstance } from './next-modes/next-dev' 6 | import { NextStartInstance } from './next-modes/next-start' 7 | -import { NextDeployInstance } from './next-modes/next-deploy' 8 | +import { NextDeployInstance } from './next-modes/netlify-deploy' 9 | import { shouldRunTurboDevTest } from './next-test-utils' 10 | -------------------------------------------------------------------------------- /tests/fixtures/advanced-api-routes/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/advanced-api-routes/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | generateBuildId: () => 'build-id', 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/advanced-api-routes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "advanced-api-routes", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@netlify/functions": "^2.7.0", 12 | "next": "latest", 13 | "react": "18.2.0", 14 | "react-dom": "18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@types/react": "18.2.75" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/advanced-api-routes/pages/api/hello-background.ts: -------------------------------------------------------------------------------- 1 | export default (req, res) => { 2 | res.setHeader('Content-Type', 'application/json') 3 | res.status(200) 4 | res.json({ message: 'hello world :)' }) 5 | } 6 | 7 | export const config = { 8 | type: 'experimental-background', 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/advanced-api-routes/pages/api/hello-scheduled.js: -------------------------------------------------------------------------------- 1 | export default (req, res) => { 2 | res.setHeader('Content-Type', 'application/json') 3 | res.status(200) 4 | res.json({ message: 'hello world :)' }) 5 | } 6 | 7 | export const config = { 8 | type: 'experimental-scheduled', 9 | schedule: '@hourly', 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/advanced-api-routes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": false, 7 | "noEmit": true, 8 | "incremental": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve" 15 | }, 16 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 17 | "exclude": ["node_modules"] 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/after/app/after/check/page.js: -------------------------------------------------------------------------------- 1 | export const revalidate = 3600 // arbitrarily long, just so that it doesn't happen during a test run 2 | 3 | export default async function Page() { 4 | const data = { 5 | timestamp: Date.now(), 6 | } 7 | console.log('/timestamp/key/[key] rendered', data) 8 | 9 | return
{JSON.stringify(data)}
10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/after/app/after/trigger/page.js: -------------------------------------------------------------------------------- 1 | import { revalidatePath } from 'next/cache' 2 | import { after, connection } from 'next/server' 3 | 4 | export default async function Page() { 5 | await connection() 6 | after(async () => { 7 | // this will run after response was sent 8 | console.log('after() triggered') 9 | console.log('after() sleep 1s') 10 | await new Promise((resolve) => setTimeout(resolve, 1000)) 11 | 12 | console.log('after() revalidatePath /after/check') 13 | revalidatePath('/after/check') 14 | }) 15 | 16 | return
Page with after()
17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/after/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/after/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /tests/fixtures/after/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "after", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "test": { 16 | "dependencies": { 17 | "next": ">=15.1.0" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/base-path/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/base-path/app/other/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Other

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/base-path/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 | a cute squirrel 6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/base-path/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | basePath: '/base/path', 5 | eslint: { 6 | ignoreDuringBuilds: true, 7 | }, 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/base-path/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base-path", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/base-path/public/squirrel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/base-path/public/squirrel.jpg -------------------------------------------------------------------------------- /tests/fixtures/cli-before-regional-blobs-support/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | } 7 | 8 | module.exports = nextConfig 9 | -------------------------------------------------------------------------------- /tests/fixtures/cli-before-regional-blobs-support/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "old-cli", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "netlify-cli": "17.21.1", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/fixtures/cli-before-regional-blobs-support/pages/index.js: -------------------------------------------------------------------------------- 1 | export default function Home({ ssr }) { 2 | return ( 3 |
4 |
SSR: {ssr ? 'yes' : 'no'}
5 |
6 | ) 7 | } 8 | 9 | export const getServerSideProps = async () => { 10 | return { 11 | props: { 12 | ssr: true, 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/.gitignore: -------------------------------------------------------------------------------- 1 | cool -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/api/headers/route.js: -------------------------------------------------------------------------------- 1 | import { cookies } from 'next/headers' 2 | 3 | export const GET = async () => { 4 | cookies().set('foo', 'foo1') 5 | cookies().set('bar', 'bar1') 6 | 7 | // Key, value, options 8 | cookies().set('test1', 'value1', { secure: true }) 9 | 10 | // One object 11 | cookies().set({ 12 | name: 'test2', 13 | value: 'value2', 14 | httpOnly: true, 15 | path: '/handler', 16 | }) 17 | 18 | // Cookies here will be merged with the ones above 19 | return new Response('Hello, world!', { 20 | headers: [ 21 | ['Content-Type', 'text/custom'], 22 | ['Set-Cookie', 'bar=bar2'], 23 | ['Set-Cookie', 'baz=baz2'], 24 | ], 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/api/url/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | 3 | export async function GET(request) { 4 | return NextResponse.json({ url: request.url }) 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/image/page.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function NextImageUsingNetlifyImageCDN() { 4 | return ( 5 |
6 |

Next/Image + Netlify Image CDN

7 | a cute squirrel (next/image) 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/other/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Other

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 | a cute squirrel 6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/redirect/response/route.js: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | 3 | export async function GET() { 4 | return NextResponse.redirect('https://www.netlify.com/') 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/redirect/route.js: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | 3 | export async function GET() { 4 | return redirect('https://www.netlify.com/') 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/app/stale-cache-serving/app-page/page.js: -------------------------------------------------------------------------------- 1 | export const dynamic = 'force-dynamic' 2 | 3 | const delay = 3000 4 | 5 | export default async function Page(props) { 6 | const start = Date.now() 7 | const data = await fetch(`https://next-data-api-endpoint.vercel.app/api/delay?delay=${delay}`, { 8 | next: { revalidate: 3 }, 9 | }).then((res) => res.json()) 10 | const fetchDuration = Date.now() - start 11 | 12 | return ( 13 | <> 14 |

{JSON.stringify({ fetchDuration, data, now: Date.now() })}

15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | distDir: 'cool/output', 5 | eslint: { 6 | ignoreDuringBuilds: true, 7 | }, 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dist-dir", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/dist-dir/public/squirrel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/dist-dir/public/squirrel.jpg -------------------------------------------------------------------------------- /tests/fixtures/dynamic-cms/README.md: -------------------------------------------------------------------------------- 1 | This fixture is meant to emulate dynamic content responses of a CMS-backed next site 2 | -------------------------------------------------------------------------------- /tests/fixtures/dynamic-cms/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | i18n: { 8 | locales: ['en', 'fr'], 9 | defaultLocale: 'en', 10 | }, 11 | generateBuildId: () => 'build-id', 12 | } 13 | 14 | module.exports = nextConfig 15 | -------------------------------------------------------------------------------- /tests/fixtures/dynamic-cms/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dynamic-cms", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@netlify/blobs": "^8.1.0", 12 | "@netlify/functions": "^2.7.0", 13 | "netlify-cli": "^19.0.3", 14 | "next": "latest", 15 | "react": "18.2.0", 16 | "react-dom": "18.2.0" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "22.13.13", 20 | "@types/react": "19.0.12", 21 | "typescript": "5.8.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/dynamic-cms/pages/404.js: -------------------------------------------------------------------------------- 1 | export default function NotFound() { 2 | return

Custom 404 page

3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/dynamic-cms/pages/api/revalidate.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | try { 3 | const pathToPurge = req.query.path ?? '/static/revalidate-manual' 4 | await res.revalidate(pathToPurge) 5 | return res.json({ code: 200, message: 'success' }) 6 | } catch (err) { 7 | return res.status(500).send({ code: 500, message: err.message }) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/app/other/page.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 |

Other

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/app/test/next/page.js: -------------------------------------------------------------------------------- 1 | import { headers } from 'next/headers' 2 | 3 | export default function Page() { 4 | const headersList = headers() 5 | const message = headersList.get('x-hello-from-middleware-req') 6 | 7 | return ( 8 |
9 |

Message from middleware: {message}

10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/app/test/redirect/page.js: -------------------------------------------------------------------------------- 1 | export default function Redirect() { 2 | return ( 3 |
4 |

If middleware works, we shoudn't get here

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/app/test/rewrite/page.js: -------------------------------------------------------------------------------- 1 | export default function Rewrite() { 2 | return ( 3 |
4 |

If middleware works, we shoudn't get here

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/middleware.ts: -------------------------------------------------------------------------------- 1 | import type { NextRequest } from 'next/server' 2 | import { NextResponse } from 'next/server' 3 | 4 | export function middleware(request: NextRequest) { 5 | const response: NextResponse = NextResponse.next() 6 | 7 | response.headers.set('x-hello-from-middleware-res', 'hello') 8 | 9 | return response 10 | } 11 | 12 | export const config = { 13 | matcher: [ 14 | { 15 | source: '/foo', 16 | missing: [{ type: 'header', key: 'x-custom-header', value: 'custom-value' }], 17 | }, 18 | { 19 | source: '/hello', 20 | }, 21 | { 22 | source: '/nl/about', 23 | locale: false, 24 | }, 25 | ], 26 | } 27 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | i18n: { 5 | locales: ['en', 'fr', 'nl', 'es'], 6 | defaultLocale: 'en', 7 | }, 8 | eslint: { 9 | ignoreDuringBuilds: true, 10 | }, 11 | } 12 | 13 | module.exports = nextConfig 14 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-conditions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-conditions", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-excluded-paths/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-excluded-paths/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | output: 'standalone', 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | i18n: { 7 | locales: ['en', 'fr'], 8 | defaultLocale: 'en', 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-excluded-paths/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-i18n-excluded-paths", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^17.0.12", 17 | "@types/react": "18.2.47", 18 | "typescript": "^5.2.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-excluded-paths/pages/[[...catchall]].tsx: -------------------------------------------------------------------------------- 1 | import type { GetStaticPaths, GetStaticProps } from 'next' 2 | 3 | export default function CatchAll({ params, locale }) { 4 | return
{JSON.stringify({ params, locale }, null, 2)}
5 | } 6 | 7 | export const getStaticPaths: GetStaticPaths = () => { 8 | return { 9 | paths: [], 10 | fallback: 'blocking', 11 | } 12 | } 13 | 14 | export const getStaticProps: GetStaticProps = ({ params, locale }) => { 15 | return { 16 | props: { 17 | params, 18 | locale, 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-excluded-paths/pages/api/[[...catchall]].ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next' 2 | 3 | type ResponseData = { 4 | params: { 5 | catchall?: string[] 6 | } 7 | } 8 | 9 | export default function handler(req: NextApiRequest, res: NextApiResponse) { 10 | res.status(200).json({ params: req.query }) 11 | } 12 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-excluded-paths/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": false, 8 | "noEmit": true, 9 | "incremental": true, 10 | "module": "esnext", 11 | "esModuleInterop": true, 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve" 16 | }, 17 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 18 | "exclude": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-skip-normalize/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | output: 'standalone', 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | i18n: { 7 | locales: ['en', 'fr', 'nl', 'es'], 8 | defaultLocale: 'en', 9 | }, 10 | skipMiddlewareUrlNormalize: true, 11 | experimental: { 12 | clientRouterFilter: true, 13 | clientRouterFilterRedirects: true, 14 | }, 15 | redirects() { 16 | return [ 17 | { 18 | source: '/to-new', 19 | destination: '/dynamic/new', 20 | permanent: false, 21 | }, 22 | ] 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-skip-normalize/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-pages", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "18.2.47" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-skip-normalize/pages/_app.js: -------------------------------------------------------------------------------- 1 | export default function App({ Component, pageProps }) { 2 | if (!pageProps || typeof pageProps !== 'object') { 3 | throw new Error(`Invariant: received invalid pageProps in _app, received ${pageProps}`) 4 | } 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-skip-normalize/pages/api/ok.js: -------------------------------------------------------------------------------- 1 | export default function handler(req, res) { 2 | res.send('ok') 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-skip-normalize/pages/dynamic/[slug].js: -------------------------------------------------------------------------------- 1 | export default function Account({ slug }) { 2 | return ( 3 |

4 | Welcome to a /dynamic/[slug]: {slug} 5 |

6 | ) 7 | } 8 | 9 | export function getServerSideProps({ params }) { 10 | return { 11 | props: { 12 | slug: params.slug, 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n-skip-normalize/pages/new-home.js: -------------------------------------------------------------------------------- 1 | export default function Account() { 2 | return ( 3 |

4 | Welcome to a new page 5 |

6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | output: 'standalone', 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | i18n: { 7 | locales: ['en', 'fr', 'nl', 'es'], 8 | defaultLocale: 'en', 9 | }, 10 | experimental: { 11 | clientRouterFilter: true, 12 | clientRouterFilterRedirects: true, 13 | }, 14 | redirects() { 15 | return [ 16 | { 17 | source: '/to-new', 18 | destination: '/dynamic/new', 19 | permanent: false, 20 | }, 21 | ] 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-pages", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "18.2.47" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n/pages/_app.js: -------------------------------------------------------------------------------- 1 | export default function App({ Component, pageProps }) { 2 | if (!pageProps || typeof pageProps !== 'object') { 3 | throw new Error(`Invariant: received invalid pageProps in _app, received ${pageProps}`) 4 | } 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n/pages/api/ok.js: -------------------------------------------------------------------------------- 1 | export default function handler(req, res) { 2 | res.send('ok') 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n/pages/dynamic/[slug].js: -------------------------------------------------------------------------------- 1 | export default function Account({ slug }) { 2 | return ( 3 |

4 | Welcome to a /dynamic/[slug]: {slug} 5 |

6 | ) 7 | } 8 | 9 | export function getServerSideProps({ params }) { 10 | return { 11 | props: { 12 | slug: params.slug, 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-i18n/pages/new-home.js: -------------------------------------------------------------------------------- 1 | export default function Account() { 2 | return ( 3 |

4 | Welcome to a new page 5 |

6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-og/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-og/app/og.js: -------------------------------------------------------------------------------- 1 | import { ImageResponse } from 'next/og' 2 | 3 | export default function og() { 4 | return new ImageResponse( 5 | ( 6 |
17 | Open Graph 18 |
19 | ), 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-og/app/opengraph-image.js: -------------------------------------------------------------------------------- 1 | export const alt = 'Open Graph' 2 | 3 | export { default } from './og' 4 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-og/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-og/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-og/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-og", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "test": { 16 | "dependencies": { 17 | "next": ">=14.0.0" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-pages", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^20.10.6", 17 | "@types/react": "18.2.47", 18 | "typescript": "^5.3.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/[id].js: -------------------------------------------------------------------------------- 1 | export default function Index() { 2 | return

Dynamic route

3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/_app.js: -------------------------------------------------------------------------------- 1 | export default function App({ Component, pageProps }) { 2 | if (!pageProps || typeof pageProps !== 'object') { 3 | throw new Error(`Invariant: received invalid pageProps in _app, received ${pageProps}`) 4 | } 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/about/a.js: -------------------------------------------------------------------------------- 1 | export default function AboutA() { 2 | return ( 3 |
4 |

AboutA

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/about/b.js: -------------------------------------------------------------------------------- 1 | export default function AboutB() { 2 | return ( 3 |
4 |

AboutB

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/api/edge-headers.js: -------------------------------------------------------------------------------- 1 | export const runtime = 'edge' 2 | 3 | export default (req) => { 4 | return Response.json(Object.fromEntries(req.headers.entries()), { 5 | headers: { 6 | 'headers-from-edge-function': '1', 7 | }, 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/api/headers.js: -------------------------------------------------------------------------------- 1 | export default function handler(req, res) { 2 | res.headers = { 'headers-from-function': '1' } 3 | res.json({ url: req.url, headers: req.headers }) 4 | } 5 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/blog/[slug].js: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router' 2 | 3 | export default function Page(props) { 4 | const router = useRouter() 5 | return ( 6 | <> 7 |

/blog/[slug]

8 |

{JSON.stringify(router.query)}

9 |

{router.pathname}

10 |

{router.asPath}

11 |

{JSON.stringify(props)}

12 | 13 | ) 14 | } 15 | 16 | export function getServerSideProps({ params }) { 17 | return { 18 | props: { 19 | now: Date.now(), 20 | params, 21 | }, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/error-throw.js: -------------------------------------------------------------------------------- 1 | export default function ThrowOnData({ message }) { 2 | return ( 3 |
4 |

Throw on data request

5 |

{message}

6 |
7 | ) 8 | } 9 | 10 | export const getServerSideProps = ({ query }) => ({ 11 | props: { message: query.message || '' }, 12 | }) 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/error.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | 3 | export default function Errors() { 4 | return ( 5 |
6 | 7 | Throw on data 8 | 9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/html-links.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | 3 | export default function Page() { 4 | return ( 5 |
    6 |
  • 7 | 8 | Does not work 9 | 10 |
  • 11 |
  • 12 | 13 | Works 14 | 15 |
  • 16 |
17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/ssr-page-2.js: -------------------------------------------------------------------------------- 1 | export default function SSRPage(props) { 2 | return

{props.message}

3 | } 4 | 5 | export const getServerSideProps = (req) => { 6 | return { 7 | props: { 8 | message: 'Bye Cruel World', 9 | }, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/pages/ssr-page.js: -------------------------------------------------------------------------------- 1 | export default function SSRPage(props) { 2 | return

{props.message}

3 | } 4 | 5 | export const getServerSideProps = (req) => { 6 | return { 7 | props: { 8 | message: 'Hello World', 9 | }, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": false, 7 | "noEmit": true, 8 | "incremental": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "target": "ES2017" 16 | }, 17 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 18 | "exclude": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-src/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-src/src/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-src/src/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-src/src/app/test/next/page.js: -------------------------------------------------------------------------------- 1 | import { headers } from 'next/headers' 2 | 3 | export default function Page() { 4 | const headersList = headers() 5 | const message = headersList.get('x-hello-from-middleware-req') 6 | 7 | return ( 8 |
9 |

Message from middleware: {message}

10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-static-asset-matcher/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-static-asset-matcher/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-static-asset-matcher/middleware.ts: -------------------------------------------------------------------------------- 1 | export default function middleware() { 2 | return new Response('hello from middleware') 3 | } 4 | 5 | export const config = { 6 | matcher: '/hello/world.txt', 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-static-asset-matcher/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-static-asset-matcher/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-static-asset-matcher/public/hello/world.txt: -------------------------------------------------------------------------------- 1 | hello from a static asset 2 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-subrequest-vuln/app/[[...wildcard]]/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Hi

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-subrequest-vuln/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-subrequest-vuln/middleware.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | import { NextRequest } from 'next/server' 3 | 4 | import packageJson from 'next/package.json' 5 | 6 | export async function middleware(request: NextRequest) { 7 | const response = NextResponse.next() 8 | 9 | response.headers.set('x-test-used-middleware', 'true') 10 | response.headers.set('x-test-used-next-version', packageJson.version) 11 | 12 | return response 13 | } 14 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-subrequest-vuln/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-subrequest-vuln/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-subrequest-vuln", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "15.2.2", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "test": { 16 | "dependencies": { 17 | "next": "15.2.2" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-trailing-slash/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-trailing-slash/app/other/page.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 |

Other

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-trailing-slash/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-trailing-slash/app/test/next/page.js: -------------------------------------------------------------------------------- 1 | import { headers } from 'next/headers' 2 | 3 | export default function Page() { 4 | const headersList = headers() 5 | const message = headersList.get('x-hello-from-middleware-req') 6 | 7 | return ( 8 |
9 |

Message from middleware: {message}

10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-trailing-slash/app/test/redirect/page.js: -------------------------------------------------------------------------------- 1 | export default function Redirect() { 2 | return ( 3 |
4 |

If middleware works, we shoudn't get here

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-trailing-slash/app/test/rewrite/page.js: -------------------------------------------------------------------------------- 1 | export default function Rewrite() { 2 | return ( 3 |
4 |

If middleware works, we shoudn't get here

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-trailing-slash/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | trailingSlash: true, 4 | output: 'standalone', 5 | eslint: { 6 | ignoreDuringBuilds: true, 7 | }, 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/middleware-trailing-slash/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-trailing-slash", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/caching-redirect-target/page.js: -------------------------------------------------------------------------------- 1 | export default function CachingRedirect() { 2 | return ( 3 |
4 |

Hello redirect target

5 |
6 | ) 7 | } 8 | 9 | export const dynamic = 'force-static' 10 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/caching-rewrite-target/page.js: -------------------------------------------------------------------------------- 1 | export default function CachingRewrite() { 2 | return ( 3 |
4 |

Hello rewrite target

5 |
6 | ) 7 | } 8 | 9 | export const dynamic = 'force-static' 10 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/link-to-redirect-to-cached-page/page.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | 3 | export default function LinksToRedirectedCachedPage() { 4 | return ( 5 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/link-to-rewrite-to-cached-page/page.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | 3 | export default function LinksToRewrittenCachedPage() { 4 | return ( 5 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/other/page.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 |

Other

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/test/next/page.js: -------------------------------------------------------------------------------- 1 | import { headers } from 'next/headers' 2 | 3 | export default function Page() { 4 | const headersList = headers() 5 | const message = headersList.get('x-hello-from-middleware-req') 6 | 7 | return ( 8 |
9 |

Message from middleware: {message}

10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/test/redirect/page.js: -------------------------------------------------------------------------------- 1 | export default function Redirect() { 2 | return ( 3 |
4 |

If middleware works, we shoudn't get here

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/test/rewrite-target/page.js: -------------------------------------------------------------------------------- 1 | export default function Rewrite() { 2 | return ( 3 |
4 |

Hello rewrite

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/app/test/rewrite/page.js: -------------------------------------------------------------------------------- 1 | export default function Rewrite() { 2 | return ( 3 |
4 |

If middleware works, we shoudn't get here

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | webpack: (config) => { 8 | // this is a trigger to generate multiple `.next/server/middleware-[hash].js` files instead of 9 | // single `.next/server/middleware.js` file 10 | config.optimization.splitChunks.maxSize = 100_000 11 | 12 | return config 13 | }, 14 | } 15 | 16 | module.exports = nextConfig 17 | -------------------------------------------------------------------------------- /tests/fixtures/middleware/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@aws-amplify/adapter-nextjs": "^1.0.18", 12 | "aws-amplify": "^6.0.18", 13 | "next": "latest", 14 | "react": "18.2.0", 15 | "react-dom": "18.2.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms-workaround/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Netlify Forms', 3 | description: 'Test for verifying Netlify Forms', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms-workaround/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 | 5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms-workaround/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | generateBuildId: () => 'build-id', 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms-workaround/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netlify-forms", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@netlify/functions": "^2.7.0", 12 | "next": "latest", 13 | "react": "18.2.0", 14 | "react-dom": "18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@types/react": "18.2.75" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms-workaround/public/form.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms-workaround/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": false, 7 | "noEmit": true, 8 | "incremental": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ] 20 | }, 21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 22 | "exclude": ["node_modules"] 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Netlify Forms', 3 | description: 'Test for verifying Netlify Forms', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 | 5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | generateBuildId: () => 'build-id', 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netlify-forms", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@netlify/functions": "^2.7.0", 12 | "next": "latest", 13 | "react": "18.2.0", 14 | "react-dom": "18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@types/react": "18.2.75" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms/public/form.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /tests/fixtures/netlify-forms/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": false, 7 | "noEmit": true, 8 | "incremental": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ] 20 | }, 21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 22 | "exclude": ["node_modules"] 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/.npmrc: -------------------------------------------------------------------------------- 1 | strict-peer-dependencies=false 2 | auto-install-peers=true 3 | public-hoist-pattern[]=* 4 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/.env: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV="defined in .env" 2 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/.env.local: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_LOCAL="defined in .env.local" 2 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/.env.production: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_PRODUCTION="defined in .env.production" 2 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/.env.production.local: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_PRODUCTION_DOT_LOCAL="defined in .env.production.local" 2 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/api/env/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | 3 | export async function GET() { 4 | return NextResponse.json({ 5 | '.env': process.env.FROM_DOT_ENV ?? 'undefined', 6 | '.env.local': process.env.FROM_DOT_ENV_DOT_LOCAL ?? 'undefined', 7 | '.env.production': process.env.FROM_DOT_ENV_DOT_PRODUCTION ?? 'undefined', 8 | '.env.production.local': process.env.FROM_DOT_ENV_DOT_PRODUCTION_DOT_LOCAL ?? 'undefined', 9 | }) 10 | } 11 | 12 | export const dynamic = 'force-dynamic' 13 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/api/headers/route.js: -------------------------------------------------------------------------------- 1 | import { cookies } from 'next/headers' 2 | 3 | export const GET = async () => { 4 | cookies().set('foo', 'foo1') 5 | cookies().set('bar', 'bar1') 6 | 7 | // Key, value, options 8 | cookies().set('test1', 'value1', { secure: true }) 9 | 10 | // One object 11 | cookies().set({ 12 | name: 'test2', 13 | value: 'value2', 14 | httpOnly: true, 15 | path: '/handler', 16 | }) 17 | 18 | // Cookies here will be merged with the ones above 19 | return new Response('Hello, world!', { 20 | headers: [ 21 | ['Content-Type', 'text/custom'], 22 | ['Set-Cookie', 'bar=bar2'], 23 | ['Set-Cookie', 'baz=baz2'], 24 | ], 25 | }) 26 | } -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/api/url/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | 3 | export async function GET(request) { 4 | return NextResponse.json({ url: request.url }) 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/image/page.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function NextImageUsingNetlifyImageCDN() { 4 | return ( 5 |
6 |

Next/Image + Netlify Image CDN

7 | a cute squirrel (next/image) 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/other/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Other

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 | a cute squirrel 6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/redirect/response/route.js: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | 3 | export async function GET() { 4 | return NextResponse.redirect('https://www.netlify.com/') 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/redirect/route.js: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | 3 | export async function GET() { 4 | return redirect('https://www.netlify.com/') 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/app/stale-cache-serving/app-page/page.js: -------------------------------------------------------------------------------- 1 | export const dynamic = 'force-dynamic' 2 | 3 | const delay = 3000 4 | 5 | export default async function Page(props) { 6 | const start = Date.now() 7 | const data = await fetch( 8 | `https://next-data-api-endpoint.vercel.app/api/delay?delay=${delay}`, 9 | { next: { revalidate: 3 } } 10 | ).then((res) => res.json()) 11 | const fetchDuration = Date.now() - start 12 | 13 | return ( 14 | <> 15 |

16 | {JSON.stringify({ fetchDuration, data, now: Date.now() })} 17 |

18 | 19 | ) 20 | } -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/next.config.js: -------------------------------------------------------------------------------- 1 | const { composePlugins, withNx } = require('@nx/next') 2 | 3 | /** 4 | * @type {import('@nx/next/plugins/with-nx').WithNxOptions} 5 | **/ 6 | const nextConfig = { 7 | distDir: 'dist', 8 | nx: { 9 | // Set this to true if you would like to use SVGR 10 | // See: https://github.com/gregberge/svgr 11 | svgr: false, 12 | }, 13 | } 14 | 15 | const plugins = [ 16 | // Add more Next.js plugins to this list if needed. 17 | withNx, 18 | ] 19 | 20 | module.exports = composePlugins(...plugins)(nextConfig) 21 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/public/squirrel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/nx-integrated/apps/custom-dist-dir/public/squirrel.jpg -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/custom-dist-dir/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "jsx": "react" 8 | }, 9 | "include": [ 10 | "jest.config.ts", 11 | "src/**/*.test.ts", 12 | "src/**/*.spec.ts", 13 | "src/**/*.test.tsx", 14 | "src/**/*.spec.tsx", 15 | "src/**/*.test.js", 16 | "src/**/*.spec.js", 17 | "src/**/*.test.jsx", 18 | "src/**/*.spec.jsx", 19 | "src/**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/app/api/hello/route.ts: -------------------------------------------------------------------------------- 1 | export async function GET(request: Request) { 2 | return new Response('Hello, from API!') 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/app/api/static/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | import { readFile } from 'node:fs/promises' 3 | 4 | export async function GET(request) { 5 | const words = await readFile('static/words.txt', 'utf-8') 6 | return NextResponse.json({ words }) 7 | } 8 | 9 | export const dynamic = 'force-dynamic' 10 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './global.css' 2 | 3 | export const metadata = { 4 | title: 'Welcome to next-app', 5 | description: 'Generated by create-nx-workspace', 6 | } 7 | 8 | export default function RootLayout({ children }: { children: React.ReactNode }) { 9 | return ( 10 | 11 | {children} 12 | 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/app/page.module.css: -------------------------------------------------------------------------------- 1 | .page { 2 | } 3 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | declare module '*.svg' { 3 | const content: any 4 | export const ReactComponent: any 5 | export default content 6 | } 7 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/netlify.toml: -------------------------------------------------------------------------------- 1 | [functions] 2 | directory = "netlify/functions" 3 | included_files = ["apps/next-app/static/**"] 4 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/next.config.js: -------------------------------------------------------------------------------- 1 | const { composePlugins, withNx } = require('@nx/next') 2 | 3 | /** 4 | * @type {import('@nx/next/plugins/with-nx').WithNxOptions} 5 | **/ 6 | const nextConfig = { 7 | nx: { 8 | // Set this to true if you would like to use SVGR 9 | // See: https://github.com/gregberge/svgr 10 | svgr: false, 11 | }, 12 | } 13 | 14 | const plugins = [ 15 | // Add more Next.js plugins to this list if needed. 16 | withNx, 17 | ] 18 | 19 | module.exports = composePlugins(...plugins)(nextConfig) 20 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/nx-integrated/apps/next-app/public/.gitkeep -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/nx-integrated/apps/next-app/public/favicon.ico -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/static/words.txt: -------------------------------------------------------------------------------- 1 | hello world -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/apps/next-app/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "jsx": "react" 8 | }, 9 | "include": [ 10 | "jest.config.ts", 11 | "src/**/*.test.ts", 12 | "src/**/*.spec.ts", 13 | "src/**/*.test.tsx", 14 | "src/**/*.spec.tsx", 15 | "src/**/*.test.js", 16 | "src/**/*.spec.js", 17 | "src/**/*.test.jsx", 18 | "src/**/*.spec.jsx", 19 | "src/**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/nx-integrated/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "lib": ["es2020", "dom"], 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "baseUrl": ".", 17 | "paths": {} 18 | }, 19 | "exclude": ["node_modules", "tmp"] 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/output-export-custom-dist/.gitignore: -------------------------------------------------------------------------------- 1 | custom-dist -------------------------------------------------------------------------------- /tests/fixtures/output-export-custom-dist/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/output-export-custom-dist/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 | a cute squirrel 6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/output-export-custom-dist/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'export', 4 | distDir: 'custom-dist', 5 | eslint: { 6 | ignoreDuringBuilds: true, 7 | }, 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/output-export-custom-dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "output-export", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/output-export-custom-dist/public/squirrel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/output-export-custom-dist/public/squirrel.jpg -------------------------------------------------------------------------------- /tests/fixtures/output-export/app/image/local/page.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function NextImageUsingNetlifyImageCDN() { 4 | return ( 5 |
6 |

Next/Image + Netlify Image CDN

7 | a cute squirrel (next/image) 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/output-export/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/output-export/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 | a cute squirrel 6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/output-export/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'export', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /tests/fixtures/output-export/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "output-export", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/output-export/public/squirrel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/output-export/public/squirrel.jpg -------------------------------------------------------------------------------- /tests/fixtures/page-router-404-get-static-props-with-revalidate/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | generateBuildId: () => 'build-id', 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-404-get-static-props-with-revalidate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "page-router-404-get-static-props-with-revalidate", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-404-get-static-props-with-revalidate/pages/404.js: -------------------------------------------------------------------------------- 1 | export default function NotFound({ timestamp }) { 2 | return ( 3 |

4 | Custom 404 page with revalidate:

{timestamp}
5 |

6 | ) 7 | } 8 | 9 | /** @type {import('next').GetStaticProps} */ 10 | export const getStaticProps = ({ locale }) => { 11 | return { 12 | props: { 13 | timestamp: Date.now(), 14 | }, 15 | revalidate: 300, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-base-path-i18n/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | generateBuildId: () => 'build-id', 8 | basePath: '/base/path', 9 | i18n: { 10 | locales: ['en', 'fr', 'de'], 11 | defaultLocale: 'en', 12 | }, 13 | } 14 | 15 | module.exports = nextConfig 16 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-base-path-i18n/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "page-router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@netlify/functions": "^2.7.0", 12 | "next": "latest", 13 | "react": "18.2.0", 14 | "react-dom": "18.2.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-base-path-i18n/pages/404.js: -------------------------------------------------------------------------------- 1 | export default function NotFound({ locale }) { 2 | return ( 3 |

4 | Custom 404 page for locale:

{locale}
5 |

6 | ) 7 | } 8 | 9 | /** @type {import('next').GetStaticProps} */ 10 | export const getStaticProps = ({ locale }) => { 11 | return { 12 | props: { 13 | locale, 14 | }, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-base-path-i18n/pages/api/revalidate-no-await.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | try { 3 | const pathToPurge = req.query.path ?? '/static/revalidate-manual' 4 | // res.revalidate returns a promise that can be awaited to wait for the revalidation to complete 5 | // if user doesn't await it, we still want to ensure the revalidation is completed, so we internally track 6 | // this as "background work" to ensure it completes before function suspends execution 7 | res.revalidate(pathToPurge) 8 | return res.json({ code: 200, message: 'success' }) 9 | } catch (err) { 10 | return res.status(500).send({ code: 500, message: err.message }) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-base-path-i18n/pages/api/revalidate.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | try { 3 | const pathToRevalidate = req.query.path 4 | if (!pathToRevalidate) { 5 | return res.status(400).send({ 6 | status: 'error', 7 | error: 'missing "path" query parameter', 8 | }) 9 | } 10 | await res.revalidate(pathToRevalidate) 11 | return res.status(200).json({ message: 'ok' }) 12 | } catch (err) { 13 | return res.status(500).send({ 14 | status: 'error', 15 | error: error.toString(), 16 | }) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-base-path-i18n/pages/static/not-found.js: -------------------------------------------------------------------------------- 1 | const Show = () =>
Won't be used
2 | 3 | export async function getStaticProps() { 4 | return { 5 | notFound: true, 6 | } 7 | } 8 | 9 | export default Show 10 | -------------------------------------------------------------------------------- /tests/fixtures/page-router-base-path-i18n/pages/static/revalidate-manual.js: -------------------------------------------------------------------------------- 1 | const Show = ({ show, time }) => ( 2 |
3 |

4 | This page uses getStaticProps() to pre-fetch a TV show at 5 | {time} 6 |

7 |
8 |

Show #{show.id}

9 |

{show.name}

10 |
11 | ) 12 | 13 | export async function getStaticProps() { 14 | const res = await fetch(`https://tvproxy.netlify.app/shows/71`) 15 | const data = await res.json() 16 | 17 | return { 18 | props: { 19 | show: data, 20 | time: new Date().toISOString(), 21 | }, 22 | } 23 | } 24 | 25 | export default Show 26 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/.env: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV="defined in .env" 2 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/.env.local: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_LOCAL="defined in .env.local" 2 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/.env.production: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_PRODUCTION="defined in .env.production" 2 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/.env.production.local: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_PRODUCTION_DOT_LOCAL="defined in .env.production.local" 2 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | generateBuildId: () => 'build-id', 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "page-router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@netlify/blobs": "^8.1.0", 12 | "@netlify/functions": "^2.7.0", 13 | "next": "latest", 14 | "react": "18.2.0", 15 | "react-dom": "18.2.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/404.js: -------------------------------------------------------------------------------- 1 | export default function NotFound() { 2 | return

Custom 404 page

3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/api/env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {import('next').NextApiRequest} _req 3 | * @param {import('next').NextApiResponse} res 4 | */ 5 | export default async function handler(_req, res) { 6 | res.status(200).json({ 7 | '.env': process.env.FROM_DOT_ENV ?? 'undefined', 8 | '.env.local': process.env.FROM_DOT_ENV_DOT_LOCAL ?? 'undefined', 9 | '.env.production': process.env.FROM_DOT_ENV_DOT_PRODUCTION ?? 'undefined', 10 | '.env.production.local': process.env.FROM_DOT_ENV_DOT_PRODUCTION_DOT_LOCAL ?? 'undefined', 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/api/revalidate-no-await.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | try { 3 | const pathToPurge = req.query.path ?? '/static/revalidate-manual' 4 | // res.revalidate returns a promise that can be awaited to wait for the revalidation to complete 5 | // if user doesn't await it, we still want to ensure the revalidation is completed, so we internally track 6 | // this as "background work" to ensure it completes before function suspends execution 7 | res.revalidate(pathToPurge) 8 | return res.json({ code: 200, message: 'success' }) 9 | } catch (err) { 10 | return res.status(500).send({ code: 500, message: err.message }) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/api/revalidate.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | try { 3 | const pathToPurge = req.query.path ?? '/static/revalidate-manual' 4 | await res.revalidate(pathToPurge) 5 | return res.json({ code: 200, message: 'success' }) 6 | } catch (err) { 7 | return res.status(500).send({ code: 500, message: err.message }) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/api/sleep-5.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | await new Promise((resolve) => setTimeout(resolve, 5000)) 3 | 4 | res.json({ message: 'ok' }) 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/api/unstable-cache-node.js: -------------------------------------------------------------------------------- 1 | import { unstable_cache } from 'next/cache' 2 | 3 | export default async function handler(req, res) { 4 | const data = await unstable_cache(async () => { 5 | return { 6 | random: Math.random(), 7 | } 8 | })() 9 | 10 | res.json({ 11 | now: Date.now(), 12 | data, 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/static/fully-static.js: -------------------------------------------------------------------------------- 1 | const FullyStatic = () => ( 2 |
3 |

This page is not using getStaticProps()

4 |
5 | ) 6 | 7 | export default FullyStatic 8 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/static/not-found.js: -------------------------------------------------------------------------------- 1 | const Show = () =>
Won't be used
2 | 3 | export async function getStaticProps() { 4 | return { 5 | notFound: true, 6 | } 7 | } 8 | 9 | export default Show 10 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/static/revalidate-manual.js: -------------------------------------------------------------------------------- 1 | const Show = ({ show, time }) => ( 2 |
3 |

4 | This page uses getStaticProps() to pre-fetch a TV show at 5 | {time} 6 |

7 |
8 |

Show #{show.id}

9 |

{show.name}

10 |
11 | ) 12 | 13 | export async function getStaticProps(context) { 14 | const res = await fetch(`https://tvproxy.netlify.app/shows/71`) 15 | const data = await res.json() 16 | 17 | return { 18 | props: { 19 | show: data, 20 | time: new Date().toISOString(), 21 | }, 22 | } 23 | } 24 | 25 | export default Show 26 | -------------------------------------------------------------------------------- /tests/fixtures/page-router/pages/static/revalidate-slow.js: -------------------------------------------------------------------------------- 1 | const Show = ({ show, time }) => ( 2 |
3 |

4 | This page uses getStaticProps() to pre-fetch a TV show at 5 | {time} 6 |

7 |
8 |

Show #{show.id}

9 |

{show.name}

10 |
11 | ) 12 | 13 | export async function getStaticProps(context) { 14 | const res = await fetch(`https://tvproxy.netlify.app/shows/71`) 15 | const data = await res.json() 16 | 17 | return { 18 | props: { 19 | show: data, 20 | time: new Date().toISOString(), 21 | }, 22 | revalidate: +process.env.REVALIDATE_SECONDS || 10, // In seconds 23 | } 24 | } 25 | 26 | export default Show 27 | -------------------------------------------------------------------------------- /tests/fixtures/pnpm/.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | -------------------------------------------------------------------------------- /tests/fixtures/pnpm/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/pnpm/app/other/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Other

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/pnpm/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/pnpm/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | swcMinify: true, 4 | output: 'standalone', 5 | eslint: { 6 | ignoreDuringBuilds: true, 7 | }, 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/pnpm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pnpm", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "packageManager": "pnpm@8.9.0" 16 | } 17 | -------------------------------------------------------------------------------- /tests/fixtures/ppr/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/ppr/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 | a cute squirrel 6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/ppr/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | experimental: { 8 | ppr: true, 9 | }, 10 | } 11 | 12 | module.exports = nextConfig 13 | -------------------------------------------------------------------------------- /tests/fixtures/ppr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ppr", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "canary", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "test": { 16 | "dependencies": { 17 | "next": "canary" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/ppr/public/squirrel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/ppr/public/squirrel.jpg -------------------------------------------------------------------------------- /tests/fixtures/revalidate-fetch/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Revalidate fetch', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/revalidate-fetch/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/revalidate-fetch/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /tests/fixtures/revalidate-fetch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "incremental-static-regeneration", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/api/on-demand-revalidate/path/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | import { revalidatePath } from 'next/cache' 3 | 4 | export async function GET(request: NextRequest) { 5 | const url = new URL(request.url) 6 | const pathToRevalidate = url.searchParams.get('path') ?? '/static-fetch/[id]/page' 7 | 8 | revalidatePath(pathToRevalidate) 9 | return NextResponse.json({ revalidated: true, now: new Date().toISOString() }) 10 | } 11 | 12 | export const dynamic = 'force-dynamic' 13 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/api/on-demand-revalidate/tag/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | import { revalidateTag } from 'next/cache' 3 | 4 | export async function GET(request: NextRequest) { 5 | const url = new URL(request.url) 6 | const tagToRevalidate = url.searchParams.get('tag') ?? 'collection' 7 | 8 | revalidateTag(tagToRevalidate) 9 | return NextResponse.json({ revalidated: true, now: new Date().toISOString() }) 10 | } 11 | 12 | export const dynamic = 'force-dynamic' 13 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/api/revalidate-handler/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | 3 | export async function GET() { 4 | const res = await fetch(`https://api.tvmaze.com/shows/1`, { 5 | next: { revalidate: 7 }, 6 | }) 7 | const data = await res.json() 8 | 9 | return NextResponse.json({ data, time: new Date().toISOString() }) 10 | } 11 | 12 | export const dynamic = 'force-static' 13 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/api/static/[slug]/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | 3 | export function generateStaticParams() { 4 | return [{ slug: 'first' }, { slug: 'second' }] 5 | } 6 | 7 | export const GET = (_req: NextRequest, { params }) => { 8 | return NextResponse.json({ params }) 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/api/zero-length-response/route.ts: -------------------------------------------------------------------------------- 1 | export async function GET() { 2 | return new Response('') 3 | } 4 | 5 | export const dynamic = 'force-static' 6 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/dynamic-fetch/loading.js: -------------------------------------------------------------------------------- 1 | export default function Loading() { 2 | return

Loading Data...

3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/dynamic-fetch/page.js: -------------------------------------------------------------------------------- 1 | async function getData() { 2 | const res = await fetch(`https://strangerthings-quotes.vercel.app/api/quotes`, { 3 | cache: 'no-store', 4 | }) 5 | return res.json() 6 | } 7 | 8 | export default async function Page() { 9 | const data = await getData() 10 | 11 | return ( 12 | <> 13 |

Hello, Dynamically Rendered Server Component

14 |

Fetch cache disabled

15 |
16 |
Quote
17 |
{data[0].quote}
18 |
Time
19 |
{Date.now()}
20 |
21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Revalidate fetch', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/page.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | 3 | export default function Page() { 4 | return ( 5 |
6 |

Hello, Statically Rendered Server Component

7 |
    8 |
  • 9 | static-fetch-1 10 |
  • 11 |
  • 12 | static-fetch-1 13 |
  • 14 |
  • 15 | static-fetch-dynamic 16 |
  • 17 |
18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/product/[slug]/page.js: -------------------------------------------------------------------------------- 1 | const Product = ({ params }) => ( 2 |
3 |

Product {decodeURIComponent(params.slug)}

4 |

5 | This page uses generateStaticParams() to prerender a Product 6 | {new Date().toISOString()} 7 |

8 |
9 | ) 10 | 11 | export async function generateStaticParams() { 12 | return [ 13 | { 14 | // Japanese prerendered (non-ascii) and comma 15 | slug: '事前レンダリング,test', 16 | }, 17 | ] 18 | } 19 | 20 | export default Product 21 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/revalidate-fetch/page.js: -------------------------------------------------------------------------------- 1 | const revalidateSeconds = 3 2 | 3 | async function getData() { 4 | const res = await fetch(`https://strangerthings-quotes.vercel.app/api/quotes`, { 5 | next: { revalidate: revalidateSeconds }, 6 | }) 7 | return res.json() 8 | } 9 | 10 | export default async function Page() { 11 | const data = await getData() 12 | 13 | return ( 14 | <> 15 |

Hello, Statically Rendered Server Component

16 |

Revalidating every {revalidateSeconds} seconds

17 |
18 |
Quote
19 |
{data[0].quote}
20 |
Time
21 |
{Date.now()}
22 |
23 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/static-fetch-1/page.js: -------------------------------------------------------------------------------- 1 | async function getData() { 2 | const res = await fetch(`https://strangerthings-quotes.vercel.app/api/quotes`, { 3 | next: { tags: ['collection'] }, 4 | }) 5 | return res.json() 6 | } 7 | 8 | export default async function Page() { 9 | const data = await getData() 10 | 11 | return ( 12 | <> 13 |

Hello, Static Fetch 1

14 |
15 |
Quote
16 |
{data[0].quote}
17 |
Time
18 |
{new Date().toISOString()}
19 |
20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/static-fetch-2/page.js: -------------------------------------------------------------------------------- 1 | async function getData() { 2 | const res = await fetch(`https://strangerthings-quotes.vercel.app/api/quotes`, { 3 | next: { tags: ['collection'] }, 4 | }) 5 | return res.json() 6 | } 7 | 8 | export default async function Page() { 9 | const data = await getData() 10 | 11 | return ( 12 | <> 13 |

Hello, Static Fetch 2

14 |
15 |
Quote
16 |
{data[0].quote}
17 |
Time
18 |
{new Date().toISOString()}
19 |
20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/static-fetch-3/page.js: -------------------------------------------------------------------------------- 1 | async function getData() { 2 | const res = await fetch(`https://strangerthings-quotes.vercel.app/api/quotes`, { 3 | next: { tags: ['collection'] }, 4 | }) 5 | return res.json() 6 | } 7 | 8 | export default async function Page() { 9 | const data = await getData() 10 | 11 | return ( 12 | <> 13 |

Hello, Static Fetch 3

14 |
15 |
Quote
16 |
{data[0].quote}
17 |
Time
18 |
{new Date().toISOString()}
19 |
20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/app/static-fetch-dynamic/page.js: -------------------------------------------------------------------------------- 1 | async function getData() { 2 | const res = await fetch(`https://strangerthings-quotes.vercel.app/api/quotes`) 3 | return res.json() 4 | } 5 | 6 | export default async function Page() { 7 | const data = await getData() 8 | 9 | return ( 10 | <> 11 |

Hello, Force Dynamically Rendered Server Component

12 |
13 |
Quote
14 |
{data[0].quote}
15 |
Time
16 |
{Date.now()}
17 |
18 | 19 | ) 20 | } 21 | 22 | export const dynamic = 'force-dynamic' 23 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-components", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@netlify/functions": "^2.7.0", 12 | "next": "latest", 13 | "react": "18.2.0", 14 | "react-dom": "18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^20.11.5", 18 | "@types/react": "18.2.34", 19 | "typescript": "^5.3.3" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/server-components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": false, 7 | "noEmit": true, 8 | "incremental": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ] 20 | }, 21 | "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], 22 | "exclude": ["node_modules"] 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/api/cached-permanent/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | 3 | export async function GET() { 4 | return NextResponse.json({ 5 | message: 6 | 'Route handler not using request and using force-static dynamic strategy with permanent caching', 7 | }) 8 | } 9 | export const revalidate = false 10 | 11 | export const dynamic = 'force-static' 12 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/api/cached-revalidate/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | 3 | export async function GET() { 4 | return NextResponse.json({ 5 | message: 6 | 'Route handler not using request and using force-static dynamic strategy with 15 seconds revalidate', 7 | }) 8 | } 9 | export const revalidate = 15 10 | 11 | export const dynamic = 'force-static' 12 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/api/cjs-file-with-js-extension/bundled.cjs: -------------------------------------------------------------------------------- 1 | const { parse: pathParse } = require('node:path') 2 | 3 | const fileBase = pathParse(__filename).base 4 | 5 | module.exports = { 6 | fileBase, 7 | // if fileBase is not the same as this module name, it was bundled 8 | isBundled: fileBase !== 'bundled.cjs', 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/api/cjs-file-with-js-extension/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | import { resolve } from 'node:path' 3 | 4 | export async function GET() { 5 | return NextResponse.json({ 6 | notBundledCJSModule: __non_webpack_require__(resolve('./cjs-file-with-js-extension.js')), 7 | bundledCJSModule: require('./bundled.cjs'), 8 | }) 9 | } 10 | 11 | export const dynamic = 'force-dynamic' 12 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/api/headers/route.js: -------------------------------------------------------------------------------- 1 | import { cookies } from 'next/headers' 2 | 3 | export const GET = async () => { 4 | cookies().set('foo', 'foo1') 5 | cookies().set('bar', 'bar1') 6 | 7 | // Key, value, options 8 | cookies().set('test1', 'value1', { secure: true }) 9 | 10 | // One object 11 | cookies().set({ 12 | name: 'test2', 13 | value: 'value2', 14 | httpOnly: true, 15 | path: '/handler', 16 | }) 17 | 18 | // Cookies here will be merged with the ones above 19 | return new Response('Hello, world!', { 20 | headers: [ 21 | ['Content-Type', 'text/custom'], 22 | ['Set-Cookie', 'bar=bar2'], 23 | ['Set-Cookie', 'baz=baz2'], 24 | ], 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/api/static/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | import { readFile } from 'node:fs/promises' 3 | 4 | export async function GET(request) { 5 | const words = await readFile('static/words.txt', 'utf-8') 6 | return NextResponse.json({ words }) 7 | } 8 | 9 | export const dynamic = 'force-dynamic' 10 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/api/url/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | 3 | export async function GET(request) { 4 | return NextResponse.json({ url: request.url }) 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/config-redirect/dest/page.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 |

Hello redirect target

5 |
6 | ) 7 | } 8 | 9 | export const dynamic = 'force-static' 10 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/config-redirect/page.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | 3 | export default function Home() { 4 | return ( 5 |
6 | NextConfig.redirect 7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/config-rewrite/dest/page.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 |

Hello rewrite target

5 |
6 | ) 7 | } 8 | 9 | export const dynamic = 'force-static' 10 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/config-rewrite/page.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | 3 | export default function Home() { 4 | return ( 5 |
6 | NextConfig.rewrite 7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/image/local/page.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function NextImageUsingNetlifyImageCDN() { 4 | return ( 5 |
6 |

Next/Image + Netlify Image CDN

7 | a cute squirrel (next/image) 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/image/migration-from-v4-runtime/page.js: -------------------------------------------------------------------------------- 1 | import { NextImageWithLoaderSimulatingRuntimeV4 } from './next-image-runtime-v4' 2 | 3 | export default function NextImageUsingNetlifyImageCDN() { 4 | return ( 5 |
6 |

Next/Image + Netlify Image CDN

7 | 13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/image/remote-domain/page.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function Domains() { 4 | return ( 5 |
6 |

Remote Images with Netlify CDN

7 | dog up close 13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/image/remote-pattern-1/page.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function NextImageUsingNetlifyImageCDN() { 4 | return ( 5 |
6 |

Remote Images with Netlify CDN

7 | a cute Giraffe 13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/image/remote-pattern-2/page.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function NextImageUsingNetlifyImageCDN() { 4 | return ( 5 |
6 |

Remote Images with Netlify CDN

7 | a cute Cat 13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Simple Next App', 3 | description: 'Description for Simple Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/not-found.js: -------------------------------------------------------------------------------- 1 | export default function NotFound() { 2 | return ( 3 |
4 |

404 Not Found

5 |

Custom Not Found Page

6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/other/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Other

5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/page.js: -------------------------------------------------------------------------------- 1 | export default function Home() { 2 | return ( 3 |
4 |

Home

5 | a cute squirrel 6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/redirect/response/route.js: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | 3 | export async function GET() { 4 | return NextResponse.redirect('https://www.netlify.com/') 5 | } 6 | 7 | export const dynamic = 'force-dynamic' 8 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/redirect/route.js: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | 3 | export async function GET() { 4 | return redirect('https://www.netlify.com/') 5 | } 6 | 7 | export const dynamic = 'force-dynamic' 8 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/route-resolves-to-not-found/page.js: -------------------------------------------------------------------------------- 1 | import { notFound } from 'next/navigation' 2 | 3 | export default async function Page() { 4 | notFound() 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/stale-cache-serving/app-page/page.js: -------------------------------------------------------------------------------- 1 | export const dynamic = 'force-dynamic' 2 | 3 | const delay = 3000 4 | 5 | export default async function Page(props) { 6 | const start = Date.now() 7 | const data = await fetch(`https://next-data-api-endpoint.vercel.app/api/delay?delay=${delay}`, { 8 | next: { revalidate: 3 }, 9 | }).then((res) => res.json()) 10 | const fetchDuration = Date.now() - start 11 | 12 | return ( 13 | <> 14 |

{JSON.stringify({ fetchDuration, data, now: Date.now() })}

15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/simple/app/unstable_cache/page.js: -------------------------------------------------------------------------------- 1 | import { unstable_cache } from 'next/cache' 2 | 3 | export const dynamic = 'force-dynamic' 4 | 5 | const getData = unstable_cache( 6 | async () => { 7 | return { 8 | timestamp: Date.now(), 9 | } 10 | }, 11 | [], 12 | { 13 | revalidate: 1, 14 | }, 15 | ) 16 | 17 | export default async function Page() { 18 | const data = await getData() 19 | 20 | return
{JSON.stringify(data, null, 2)}
21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/simple/cjs-file-with-js-extension.js: -------------------------------------------------------------------------------- 1 | const { parse: pathParse } = require('node:path') 2 | 3 | const fileBase = pathParse(__filename).base 4 | 5 | module.exports = { 6 | fileBase, 7 | // if fileBase is not the same as this module name, it was bundled 8 | isBundled: fileBase !== 'cjs-file-with-js-extension.js', 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-next-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/fixtures/simple/pages/fully-static.js: -------------------------------------------------------------------------------- 1 | // This is forcing this fixture to produce static html pages router 2 | // to not rely just on Next.js currently always handling default pages router 404.html page 3 | const FullyStatic = () => ( 4 |
5 |

This page is not using getStaticProps()

6 |
7 | ) 8 | 9 | export default FullyStatic 10 | -------------------------------------------------------------------------------- /tests/fixtures/simple/public/squirrel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/simple/public/squirrel.jpg -------------------------------------------------------------------------------- /tests/fixtures/simple/static/prebuilt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | hello static html NOT produced by Next.js 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/fixtures/simple/static/words.txt: -------------------------------------------------------------------------------- 1 | hello world -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // This configuration only applies to the package manager root. 2 | /** @type {import("eslint").Linter.Config} */ 3 | module.exports = { 4 | ignorePatterns: ['apps/**', 'packages/**'], 5 | extends: ['@repo/eslint-config/library.js'], 6 | parser: '@typescript-eslint/parser', 7 | parserOptions: { 8 | project: true, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Testing 9 | coverage 10 | 11 | # Turbo 12 | .turbo 13 | 14 | # Vercel 15 | .vercel 16 | 17 | # Build Outputs 18 | .next/ 19 | out/ 20 | build 21 | dist 22 | 23 | 24 | # Debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # Misc 30 | .DS_Store 31 | *.pem 32 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/.npmrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/turborepo-npm/.npmrc -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/docs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['@repo/eslint-config/next.js'], 5 | parser: '@typescript-eslint/parser', 6 | parserOptions: { 7 | project: true, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/docs/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/turborepo-npm/apps/docs/app/favicon.ico -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/docs/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import type { Metadata } from 'next' 3 | import { Inter } from 'next/font/google' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Turborepo', 9 | description: 'Generated by create turbo', 10 | } 11 | 12 | export default function RootLayout({ children }: { children: React.ReactNode }): JSX.Element { 13 | return ( 14 | 15 | {children} 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/docs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/docs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | transpilePackages: ['@repo/ui'], 4 | } 5 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/docs/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ] 9 | }, 10 | "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/.env: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV="defined in .env" 2 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/.env.local: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_LOCAL="defined in .env.local" 2 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/.env.production: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_PRODUCTION="defined in .env.production" 2 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/.env.production.local: -------------------------------------------------------------------------------- 1 | FROM_DOT_ENV_DOT_PRODUCTION_DOT_LOCAL="defined in .env.production.local" 2 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "page-router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build" 8 | }, 9 | "dependencies": { 10 | "@netlify/functions": "^2.7.0", 11 | "@repo/ui": "*", 12 | "next": "latest", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@repo/typescript-config": "*", 18 | "@types/node": "^17.0.12", 19 | "@types/react": "^18.0.22", 20 | "@types/react-dom": "^18.0.7", 21 | "typescript": "^5.2.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/pages/api/env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {import('next').NextApiRequest} _req 3 | * @param {import('next').NextApiResponse} res 4 | */ 5 | export default async function handler(_req, res) { 6 | res.status(200).json({ 7 | '.env': process.env.FROM_DOT_ENV ?? 'undefined', 8 | '.env.local': process.env.FROM_DOT_ENV_DOT_LOCAL ?? 'undefined', 9 | '.env.production': process.env.FROM_DOT_ENV_DOT_PRODUCTION ?? 'undefined', 10 | '.env.production.local': process.env.FROM_DOT_ENV_DOT_PRODUCTION_DOT_LOCAL ?? 'undefined', 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/pages/api/revalidate.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | try { 3 | await res.revalidate('/static/revalidate-manual') 4 | return res.json({ code: 200, message: 'success' }) 5 | } catch (err) { 6 | return res.status(500).send({ code: 500, message: err.message }) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/pages/static/revalidate-manual.js: -------------------------------------------------------------------------------- 1 | const Show = ({ show, time }) => ( 2 |
3 |

4 | This page uses getStaticProps() to pre-fetch a TV show at 5 | {time} 6 |

7 |
8 |

Show #{show.id}

9 |

{show.name}

10 |
11 | ) 12 | 13 | export async function getStaticProps(context) { 14 | const res = await fetch(`https://tvproxy.netlify.app/shows/71`) 15 | const data = await res.json() 16 | 17 | return { 18 | props: { 19 | show: data, 20 | time: new Date().toISOString(), 21 | }, 22 | } 23 | } 24 | 25 | export default Show 26 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/test.cjs: -------------------------------------------------------------------------------- 1 | console.log(require.resolve('styled-jsx')) 2 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/page-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ] 9 | }, 10 | "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/web/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['@repo/eslint-config/next.js'], 5 | parser: '@typescript-eslint/parser', 6 | parserOptions: { 7 | project: true, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/web/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/turborepo-npm/apps/web/app/favicon.ico -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/web/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import type { Metadata } from 'next' 3 | import { Inter } from 'next/font/google' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Turborepo', 9 | description: 'Generated by create turbo', 10 | } 11 | 12 | export default function RootLayout({ children }: { children: React.ReactNode }): JSX.Element { 13 | return ( 14 | 15 | {children} 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/web/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | transpilePackages: ['@repo/ui'], 4 | } 5 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/web/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ] 9 | }, 10 | "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "turborepo-npm", 3 | "private": true, 4 | "scripts": { 5 | "postinstall": "turbo build", 6 | "build": "turbo build", 7 | "dev": "turbo dev", 8 | "lint": "turbo lint", 9 | "format": "prettier --write \"**/*.{ts,tsx,md}\"" 10 | }, 11 | "devDependencies": { 12 | "@repo/eslint-config": "*", 13 | "@repo/typescript-config": "*", 14 | "prettier": "^3.1.1", 15 | "turbo": "latest" 16 | }, 17 | "engines": { 18 | "node": ">=18" 19 | }, 20 | "packageManager": "npm@10.2.3", 21 | "workspaces": [ 22 | "apps/*", 23 | "packages/*" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/eslint-config/README.md: -------------------------------------------------------------------------------- 1 | # `@turbo/eslint-config` 2 | 3 | Collection of internal eslint configurations. 4 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/eslint-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "files": [ 6 | "library.js", 7 | "next.js", 8 | "react-internal.js" 9 | ], 10 | "devDependencies": { 11 | "@vercel/style-guide": "^5.1.0", 12 | "eslint-config-turbo": "^1.11.3", 13 | "eslint-config-prettier": "^9.1.0", 14 | "eslint-plugin-only-warn": "^1.1.0", 15 | "@typescript-eslint/parser": "^6.17.0", 16 | "@typescript-eslint/eslint-plugin": "^6.17.0", 17 | "typescript": "^5.3.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "incremental": false, 9 | "isolatedModules": true, 10 | "lib": ["es2022", "DOM", "DOM.Iterable"], 11 | "module": "NodeNext", 12 | "moduleDetection": "force", 13 | "moduleResolution": "NodeNext", 14 | "noUncheckedIndexedAccess": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "ES2022" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/typescript-config/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "plugins": [{ "name": "next" }], 7 | "module": "ESNext", 8 | "moduleResolution": "Bundler", 9 | "allowJs": true, 10 | "jsx": "preserve", 11 | "noEmit": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/typescript-config/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/ui/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['@repo/eslint-config/react-internal.js'], 5 | parser: '@typescript-eslint/parser', 6 | parserOptions: { 7 | project: './tsconfig.lint.json', 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/ui/src/button.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { ReactNode } from 'react' 4 | 5 | interface ButtonProps { 6 | children: ReactNode 7 | className?: string 8 | appName: string 9 | } 10 | 11 | export const Button = ({ children, className, appName }: ButtonProps) => { 12 | return ( 13 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/ui/src/card.tsx: -------------------------------------------------------------------------------- 1 | export function Card({ 2 | className, 3 | title, 4 | children, 5 | href, 6 | }: { 7 | className?: string 8 | title: string 9 | children: React.ReactNode 10 | href: string 11 | }): JSX.Element { 12 | return ( 13 | 19 |

20 | {title} -> 21 |

22 |

{children}

23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/ui/src/code.tsx: -------------------------------------------------------------------------------- 1 | export function Code({ 2 | children, 3 | className, 4 | }: { 5 | children: React.ReactNode 6 | className?: string 7 | }): JSX.Element { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/ui/tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src", "turbo"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/ui/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "extends": ["//"], 4 | "tasks": { 5 | "build": { 6 | "outputs": ["dist/**"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/packages/ui/turbo/generators/templates/component.hbs: -------------------------------------------------------------------------------- 1 | export const 2 | {{pascalCase name}} 3 | = ({ children }: { children: React.ReactNode }) => { return ( 4 |
5 |

{{pascalCase name}} Component

6 | {children} 7 |
8 | ); }; -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/base.json" 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo-npm/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalDependencies": ["**/.env.*local"], 4 | "tasks": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "outputs": [".next/**", "!.next/cache/**"] 8 | }, 9 | "lint": { 10 | "dependsOn": ["^lint"] 11 | }, 12 | "dev": { 13 | "cache": false, 14 | "persistent": true 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | 30 | 31 | # Debug 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # Misc 37 | .DS_Store 38 | *.pem 39 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/.npmrc: -------------------------------------------------------------------------------- 1 | public-hoist-pattern[]=* 2 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.workingDirectories": [ 3 | { 4 | "mode": "auto" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/docs/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/turborepo/apps/docs/app/favicon.ico -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/docs/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import type { Metadata } from 'next' 3 | import { Inter } from 'next/font/google' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Turborepo', 9 | description: 'Generated by create turbo', 10 | } 11 | 12 | export default function RootLayout({ children }: { children: React.ReactNode }): JSX.Element { 13 | return ( 14 | 15 | {children} 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/docs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/docs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | transpilePackages: ['@repo/ui'], 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --port 3001", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "@repo/ui": "workspace:*", 12 | "next": "latest", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@repo/typescript-config": "workspace:*", 18 | "@types/node": "^17.0.12", 19 | "@types/react": "^18.0.22", 20 | "@types/react-dom": "^18.0.7", 21 | "typescript": "^5.2.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/docs/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ] 9 | }, 10 | "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/page-router/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/page-router/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/page-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "page-router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build" 8 | }, 9 | "dependencies": { 10 | "@netlify/functions": "^2.7.0", 11 | "@repo/ui": "workspace:*", 12 | "next": "latest", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@repo/typescript-config": "workspace:*", 18 | "@types/node": "^17.0.12", 19 | "@types/react": "^18.0.22", 20 | "@types/react-dom": "^18.0.7", 21 | "typescript": "^5.2.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/page-router/src/pages/api/revalidate.js: -------------------------------------------------------------------------------- 1 | export default async function handler(req, res) { 2 | try { 3 | await res.revalidate('/static/revalidate-manual') 4 | return res.json({ code: 200, message: 'success' }) 5 | } catch (err) { 6 | return res.status(500).send({ code: 500, message: err.message }) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/page-router/src/pages/static/revalidate-manual.js: -------------------------------------------------------------------------------- 1 | const Show = ({ show, time }) => ( 2 |
3 |

4 | This page uses getStaticProps() to pre-fetch a TV show at 5 | {time} 6 |

7 |
8 |

Show #{show.id}

9 |

{show.name}

10 |
11 | ) 12 | 13 | export async function getStaticProps(context) { 14 | const res = await fetch(`https://tvproxy.netlify.app/shows/71`) 15 | const data = await res.json() 16 | 17 | return { 18 | props: { 19 | show: data, 20 | time: new Date().toISOString(), 21 | }, 22 | } 23 | } 24 | 25 | export default Show 26 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/page-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ] 9 | }, 10 | "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/web/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/turborepo/apps/web/app/favicon.ico -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/web/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import type { Metadata } from 'next' 3 | import { Inter } from 'next/font/google' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Turborepo', 9 | description: 'Generated by create turbo', 10 | } 11 | 12 | export default function RootLayout({ children }: { children: React.ReactNode }): JSX.Element { 13 | return ( 14 | 15 | {children} 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/web/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "@repo/ui": "workspace:*", 12 | "next": "latest", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@repo/typescript-config": "workspace:*", 18 | "@types/node": "^17.0.12", 19 | "@types/react": "^18.0.22", 20 | "@types/react-dom": "^18.0.7", 21 | "typescript": "^5.2.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/web/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ] 9 | }, 10 | "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "turborepo", 3 | "private": true, 4 | "scripts": { 5 | "postinstall": "turbo build", 6 | "build": "turbo build", 7 | "dev": "turbo dev" 8 | }, 9 | "devDependencies": { 10 | "@repo/typescript-config": "workspace:*", 11 | "turbo": "latest" 12 | }, 13 | "packageManager": "pnpm@8.9.0", 14 | "engines": { 15 | "node": ">=18" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "incremental": false, 9 | "isolatedModules": true, 10 | "lib": ["es2022", "DOM", "DOM.Iterable"], 11 | "module": "NodeNext", 12 | "moduleDetection": "force", 13 | "moduleResolution": "NodeNext", 14 | "noUncheckedIndexedAccess": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "ES2022" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/typescript-config/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "plugins": [{ "name": "next" }], 7 | "module": "ESNext", 8 | "moduleResolution": "Bundler", 9 | "allowJs": true, 10 | "jsx": "preserve", 11 | "noEmit": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/typescript-config/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "exports": { 6 | "./button": "./src/button.tsx", 7 | "./card": "./src/card.tsx", 8 | "./code": "./src/code.tsx" 9 | }, 10 | "scripts": { 11 | "generate:component": "turbo gen react-component" 12 | }, 13 | "devDependencies": { 14 | "@repo/typescript-config": "workspace:*", 15 | "@turbo/gen": "^1.10.12", 16 | "@types/node": "^20.5.2", 17 | "@types/react": "^18.2.0", 18 | "@types/react-dom": "^18.2.0", 19 | "react": "^18.2.0", 20 | "typescript": "^5.2.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/ui/src/button.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { ReactNode } from 'react' 4 | 5 | interface ButtonProps { 6 | children: ReactNode 7 | className?: string 8 | appName: string 9 | } 10 | 11 | export const Button = ({ children, className, appName }: ButtonProps) => { 12 | return ( 13 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/ui/src/card.tsx: -------------------------------------------------------------------------------- 1 | export function Card({ 2 | className, 3 | title, 4 | children, 5 | href, 6 | }: { 7 | className?: string 8 | title: string 9 | children: React.ReactNode 10 | href: string 11 | }): JSX.Element { 12 | return ( 13 | 19 |

20 | {title} -> 21 |

22 |

{children}

23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/ui/src/code.tsx: -------------------------------------------------------------------------------- 1 | export function Code({ 2 | children, 3 | className, 4 | }: { 5 | children: React.ReactNode 6 | className?: string 7 | }): JSX.Element { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/ui/tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src", "turbo"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/ui/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "extends": ["//"], 4 | "tasks": { 5 | "build": { 6 | "outputs": ["dist/**"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/packages/ui/turbo/generators/templates/component.hbs: -------------------------------------------------------------------------------- 1 | import * as React from "react"; interface Props { children?: React.ReactNode; } export const 2 | {{pascalCase name}} 3 | = ({ children }: Props) => { return ( 4 |
5 |

{{name}}

6 | {children} 7 |
8 | ); }; -------------------------------------------------------------------------------- /tests/fixtures/turborepo/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'apps/*' 3 | - 'packages/*' 4 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/base.json" 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/turborepo/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalDependencies": ["**/.env.*local"], 4 | "tasks": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "outputs": [".next/**", "!.next/cache/**"] 8 | }, 9 | "dev": { 10 | "cache": false, 11 | "persistent": true 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/fixtures/use-cache/app/api/revalidate/[...slug]/route.ts: -------------------------------------------------------------------------------- 1 | import { revalidateTag } from 'next/cache' 2 | import { NextRequest } from 'next/server' 3 | 4 | export async function GET(request: NextRequest, { params }) { 5 | const { slug } = await params 6 | 7 | const tagToInvalidate = slug.join('/') 8 | 9 | revalidateTag(tagToInvalidate) 10 | 11 | return Response.json({ tagToInvalidate }) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/use-cache/app/layout.js: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Use cache App', 3 | description: 'Description for Use cache Next App', 4 | } 5 | 6 | export default function RootLayout({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/use-cache/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /tests/fixtures/use-cache/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-cache", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "next": "latest", 12 | "react": "18.2.0", 13 | "react-dom": "18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "19.1.2" 17 | }, 18 | "test": { 19 | "dependencies": { 20 | "next": ">=15.3.0-canary.13" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/fixtures/use-cache/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": false, 8 | "noEmit": true, 9 | "incremental": true, 10 | "module": "esnext", 11 | "esModuleInterop": true, 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ] 21 | }, 22 | "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/wasm-src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "og-api", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@vercel/og": "latest", 12 | "next": "latest", 13 | "react": "18.2.0", 14 | "react-dom": "18.2.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/fixtures/wasm-src/src/add.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/wasm-src/src/add.wasm -------------------------------------------------------------------------------- /tests/fixtures/wasm-src/src/app/og-node/route.js: -------------------------------------------------------------------------------- 1 | import { ImageResponse } from '@vercel/og' 2 | 3 | export async function GET() { 4 | return new ImageResponse(
hi
, { 5 | width: 1200, 6 | height: 630, 7 | }) 8 | } 9 | 10 | export const dynamic = 'force-dynamic' 11 | -------------------------------------------------------------------------------- /tests/fixtures/wasm-src/src/app/og/route.js: -------------------------------------------------------------------------------- 1 | import { ImageResponse } from '@vercel/og' 2 | 3 | export async function GET() { 4 | return new ImageResponse(
hi
, { 5 | width: 1200, 6 | height: 630, 7 | }) 8 | } 9 | 10 | export const runtime = 'edge' 11 | 12 | export const dynamic = 'force-dynamic' 13 | -------------------------------------------------------------------------------- /tests/fixtures/wasm-src/src/middleware.js: -------------------------------------------------------------------------------- 1 | import wasm from './add.wasm?module' 2 | const instance$ = WebAssembly.instantiate(wasm) 3 | 4 | async function increment(a) { 5 | const { instance } = await instance$ 6 | return instance.exports.add_one(a) 7 | } 8 | export default async function middleware(request) { 9 | const input = Number(request.nextUrl.searchParams.get('input')) || 1 10 | const value = await increment(input) 11 | return new Response(null, { headers: { data: JSON.stringify({ input, value }) } }) 12 | } 13 | 14 | export const config = { 15 | matcher: '/wasm', 16 | } 17 | -------------------------------------------------------------------------------- /tests/fixtures/wasm-src/src/pages/api/og-wrong-runtime.js: -------------------------------------------------------------------------------- 1 | // /pages/api/og.jsx 2 | import { ImageResponse } from '@vercel/og' 3 | 4 | export default function () { 5 | return new ImageResponse( 6 | ( 7 |
18 | Hello! 19 |
20 | ), 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /tests/fixtures/wasm-src/src/pages/api/og.js: -------------------------------------------------------------------------------- 1 | // /pages/api/og.jsx 2 | import { ImageResponse } from '@vercel/og' 3 | 4 | export const config = { 5 | runtime: 'edge', 6 | } 7 | 8 | export default function () { 9 | return new ImageResponse( 10 | ( 11 |
22 | Hello! 23 |
24 | ), 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /tests/fixtures/wasm-src/src/pages/index.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return

hello world

3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/wasm/add.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/tests/fixtures/wasm/add.wasm -------------------------------------------------------------------------------- /tests/fixtures/wasm/app/og-node/route.js: -------------------------------------------------------------------------------- 1 | import { ImageResponse } from '@vercel/og' 2 | 3 | export async function GET() { 4 | return new ImageResponse(
hi
, { 5 | width: 1200, 6 | height: 630, 7 | }) 8 | } 9 | 10 | export const dynamic = 'force-dynamic' 11 | -------------------------------------------------------------------------------- /tests/fixtures/wasm/app/og/route.js: -------------------------------------------------------------------------------- 1 | import { ImageResponse } from '@vercel/og' 2 | 3 | export async function GET() { 4 | return new ImageResponse(
hi
, { 5 | width: 1200, 6 | height: 630, 7 | }) 8 | } 9 | 10 | export const runtime = 'edge' 11 | 12 | export const dynamic = 'force-dynamic' 13 | -------------------------------------------------------------------------------- /tests/fixtures/wasm/middleware.js: -------------------------------------------------------------------------------- 1 | import wasm from './add.wasm?module' 2 | const instance$ = WebAssembly.instantiate(wasm) 3 | 4 | async function increment(a) { 5 | const { instance } = await instance$ 6 | return instance.exports.add_one(a) 7 | } 8 | export default async function middleware(request) { 9 | const input = Number(request.nextUrl.searchParams.get('input')) || 1 10 | const value = await increment(input) 11 | return new Response(null, { headers: { data: JSON.stringify({ input, value }) } }) 12 | } 13 | 14 | export const config = { 15 | matcher: '/wasm', 16 | } 17 | -------------------------------------------------------------------------------- /tests/fixtures/wasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "og-api", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "next build", 7 | "dev": "next dev", 8 | "build": "next build" 9 | }, 10 | "dependencies": { 11 | "@vercel/og": "latest", 12 | "next": "latest", 13 | "react": "18.2.0", 14 | "react-dom": "18.2.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/fixtures/wasm/pages/api/og-wrong-runtime.js: -------------------------------------------------------------------------------- 1 | // /pages/api/og.jsx 2 | import { ImageResponse } from '@vercel/og' 3 | 4 | export default function () { 5 | return new ImageResponse( 6 | ( 7 |
18 | Hello! 19 |
20 | ), 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /tests/fixtures/wasm/pages/api/og.js: -------------------------------------------------------------------------------- 1 | // /pages/api/og.jsx 2 | import { ImageResponse } from '@vercel/og' 3 | 4 | export const config = { 5 | runtime: 'edge', 6 | } 7 | 8 | export default function () { 9 | return new ImageResponse( 10 | ( 11 |
22 | Hello! 23 |
24 | ), 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /tests/fixtures/wasm/pages/index.js: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return

hello world

3 | } 4 | -------------------------------------------------------------------------------- /tests/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils/index.js' 2 | -------------------------------------------------------------------------------- /tests/netlify-e2e-legacy.json: -------------------------------------------------------------------------------- 1 | null 2 | -------------------------------------------------------------------------------- /tests/netlify-e2e.cjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const config = { 3 | version: 2, 4 | suites: {}, 5 | rules: { 6 | include: ['test/e2e/**/*.test.{t,j}s{,x}'], 7 | /** @type {string[]} */ 8 | exclude: [], 9 | }, 10 | } 11 | 12 | const rules = require('./test-config.json') 13 | 14 | // Skip non-deploy tests 15 | config.rules.exclude.push(...rules.ignored) 16 | 17 | for (const rule of rules.skipped) { 18 | // Individually-skipped tests 19 | if (rule.tests?.length) { 20 | config.suites[rule.file] = { 21 | failed: rule.tests, 22 | } 23 | } else { 24 | // Entire suite skipped 25 | config.rules.exclude.push(rule.file) 26 | } 27 | } 28 | 29 | module.exports = config 30 | -------------------------------------------------------------------------------- /tests/playwright-slack-conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "sendResults": "on-failure", 3 | "slackLogLevel": "debug", 4 | "sendUsingBot": { 5 | "channels": ["C020GQEKC13"] 6 | }, 7 | "meta": [ 8 | { "key": "version", "value": "__ENV_RESULTS_VERSION" }, 9 | { 10 | "key": "results", 11 | "value": "__ENV_RESULTS_URL" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | .yarn 8 | 9 | # Local env files 10 | .env 11 | .env.local 12 | .env.development.local 13 | .env.test.local 14 | .env.production.local 15 | 16 | # Testing 17 | coverage 18 | 19 | # Turbo 20 | .turbo 21 | 22 | # Vercel 23 | .vercel 24 | 25 | # Build Outputs 26 | .next/ 27 | out/ 28 | build 29 | dist 30 | 31 | 32 | # Debug 33 | npm-debug.log* 34 | yarn-debug.log* 35 | yarn-error.log* 36 | 37 | # Misc 38 | .DS_Store 39 | *.pem 40 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/next-12.0.3/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | } 7 | 8 | module.exports = nextConfig 9 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/next-12.0.3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-12.0.3", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "next": "12.0.3", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0" 12 | }, 13 | "test": { 14 | "dependencies": { 15 | "next": "12.0.3" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/next-12.0.3/pages/index.js: -------------------------------------------------------------------------------- 1 | export default function Home({ ssr }) { 2 | return ( 3 |
4 |
SSR: {ssr ? 'yes' : 'no'}
5 |
6 | ) 7 | } 8 | 9 | export const getServerSideProps = async () => { 10 | return { 11 | props: { 12 | ssr: true, 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/next-12.1.0/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | } 7 | 8 | module.exports = nextConfig 9 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/next-12.1.0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-12.1.0", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "next": "12.1.0", 10 | "react": "^17.0.2", 11 | "react-dom": "^17.0.2" 12 | }, 13 | "test": { 14 | "dependencies": { 15 | "next": "12.1.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/next-12.1.0/pages/index.js: -------------------------------------------------------------------------------- 1 | export default function Home({ ssr }) { 2 | return ( 3 |
4 |
SSR: {ssr ? 'yes' : 'no'}
5 |
6 | ) 7 | } 8 | 9 | export const getServerSideProps = async () => { 10 | return { 11 | props: { 12 | ssr: true, 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-empty-base/apps/site/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "" 3 | command = "npm run build" 4 | publish = "apps/site/.next" 5 | 6 | [[plugins]] 7 | package = "@netlify/plugin-nextjs" 8 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-empty-base/apps/site/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-empty-base/apps/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apps/site", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "@packages/ui": "*", 10 | "next": "latest", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-empty-base/apps/site/pages/index.js: -------------------------------------------------------------------------------- 1 | import { TestElement } from '@packages/ui/test.jsx' 2 | 3 | export default function Home({ ssr }) { 4 | return ( 5 |
6 | SSR: {ssr ? 'yes' : 'no'} 7 |
8 | ) 9 | } 10 | 11 | export const getServerSideProps = async () => { 12 | return { 13 | props: { 14 | ssr: true, 15 | }, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-empty-base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-monorepo-empty-base", 3 | "private": true, 4 | "scripts": { 5 | "build": "cd apps/site && npm run build" 6 | }, 7 | "engines": { 8 | "node": ">=18" 9 | }, 10 | "packageManager": "npm@10.2.3", 11 | "workspaces": [ 12 | "apps/*", 13 | "packages/*" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-empty-base/packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@packages/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "exports": { 6 | "./test.jsx": "./src/test.jsx" 7 | }, 8 | "devDependencies": { 9 | "react": "^18.2.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-empty-base/packages/ui/src/test.jsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export const TestElement = ({ children, testid }) => { 4 | return
{children}
5 | } 6 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/mock-download/apps/site/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/mock-download/apps/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apps/site", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "@packages/ui": "*", 10 | "next": "latest", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/mock-download/apps/site/pages/index.js: -------------------------------------------------------------------------------- 1 | import { TestElement } from '@packages/ui/test.jsx' 2 | 3 | export default function Home({ ssr }) { 4 | return ( 5 |
6 | SSR: {ssr ? 'yes' : 'no'} 7 |
8 | ) 9 | } 10 | 11 | export const getServerSideProps = async () => { 12 | return { 13 | props: { 14 | ssr: true, 15 | }, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/mock-download/packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@packages/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "exports": { 6 | "./test.jsx": "./src/test.jsx" 7 | }, 8 | "devDependencies": { 9 | "react": "^18.2.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/mock-download/packages/ui/src/test.jsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export const TestElement = ({ children, testid }) => { 4 | return
{children}
5 | } 6 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "node setup-site.mjs && npm install && npm run build -w apps/site" 3 | publish = "./apps/site/.next" 4 | 5 | [[plugins]] 6 | package = "@netlify/plugin-nextjs" 7 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-monorepo-site-created-at-build", 3 | "private": true, 4 | "engines": { 5 | "node": ">=18" 6 | }, 7 | "packageManager": "npm@10.2.3", 8 | "workspaces": [ 9 | "apps/*", 10 | "packages/*" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/pre-deploy.mjs: -------------------------------------------------------------------------------- 1 | import { rm } from 'node:fs/promises' 2 | 3 | console.log('running pre-test.mjs') 4 | // ensure we don't have monorepo setup before starting deploy 5 | await rm('apps', { force: true, recursive: true }) 6 | await rm('packages', { force: true, recursive: true }) 7 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-monorepo-site-created-at-build/setup-site.mjs: -------------------------------------------------------------------------------- 1 | import { existsSync } from 'node:fs' 2 | import { cp, mkdir } from 'node:fs/promises' 3 | 4 | if (existsSync('apps/site')) { 5 | throw new Error('apps/site already exists. Run "node pre-test.mjs" to reset the test environment') 6 | } 7 | 8 | if (existsSync('packages/ui')) { 9 | throw new Error( 10 | 'packages/ui already exists. Run "node pre-test.mjs" to reset the test environment', 11 | ) 12 | } 13 | 14 | await mkdir('apps', { recursive: true }) 15 | await mkdir('packages', { recursive: true }) 16 | await cp('mock-download/apps/', 'apps', { recursive: true }) 17 | await cp('mock-download/packages/', 'packages', { recursive: true }) 18 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-nested-site-multiple-next-version-site-compatible/apps/site/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-nested-site-multiple-next-version-site-compatible/apps/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-nested-site-multiple-next-version-site-compatible", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "next": "latest", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-nested-site-multiple-next-version-site-compatible/apps/site/pages/index.js: -------------------------------------------------------------------------------- 1 | export default function Home({ ssr }) { 2 | return ( 3 |
4 |
SSR: {ssr ? 'yes' : 'no'}
5 |
6 | ) 7 | } 8 | 9 | export const getServerSideProps = async () => { 10 | return { 11 | props: { 12 | ssr: true, 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-nested-site-multiple-next-version-site-compatible/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "no-package-path-set", 3 | "private": true, 4 | "scripts": { 5 | "build": "cd apps/site && npm run build" 6 | }, 7 | "engines": { 8 | "node": ">=18" 9 | }, 10 | "packageManager": "npm@10.2.3", 11 | "dependencies": { 12 | "next": "13.4.1" 13 | }, 14 | "test": { 15 | "dependencies": { 16 | "next": "13.4.1" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-nested-site-multiple-next-version-site-incompatible/apps/site/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-nested-site-multiple-next-version-site-incompatible/apps/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apps/site", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "next": "13.4.1", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0" 12 | }, 13 | "test": { 14 | "dependencies": { 15 | "next": "13.4.1" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-nested-site-multiple-next-version-site-incompatible/apps/site/pages/index.js: -------------------------------------------------------------------------------- 1 | export default function Home({ ssr }) { 2 | return ( 3 |
4 |
SSR: {ssr ? 'yes' : 'no'}
5 |
6 | ) 7 | } 8 | 9 | export const getServerSideProps = async () => { 10 | return { 11 | props: { 12 | ssr: true, 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/npm-nested-site-multiple-next-version-site-incompatible/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-nested-site-multiple-next-version-site-incompatible", 3 | "private": true, 4 | "scripts": { 5 | "build": "cd apps/site && npm run build" 6 | }, 7 | "engines": { 8 | "node": ">=18" 9 | }, 10 | "packageManager": "npm@10.2.3", 11 | "dependencies": { 12 | "next": "latest" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-compatible/apps/site/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-compatible/apps/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apps/site", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "@packages/ui": "*", 10 | "next": "latest", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-compatible/apps/site/pages/index.js: -------------------------------------------------------------------------------- 1 | import { TestElement } from '@packages/ui/test.jsx' 2 | 3 | export default function Home({ ssr }) { 4 | return ( 5 |
6 | SSR: {ssr ? 'yes' : 'no'} 7 |
8 | ) 9 | } 10 | 11 | export const getServerSideProps = async () => { 12 | return { 13 | props: { 14 | ssr: true, 15 | }, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-compatible/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yarn-monorepo-multiple-next-versions-site-compatible", 3 | "private": true, 4 | "scripts": { 5 | "build": "cd apps/site && npm run build" 6 | }, 7 | "engines": { 8 | "node": ">=18" 9 | }, 10 | "packageManager": "yarn@1.22.21", 11 | "workspaces": [ 12 | "apps/*", 13 | "packages/*" 14 | ], 15 | "dependencies": { 16 | "next": "13.4.1" 17 | }, 18 | "test": { 19 | "dependencies": { 20 | "next": "13.4.1" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-compatible/packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@packages/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "exports": { 6 | "./test.jsx": "./src/test.jsx" 7 | }, 8 | "devDependencies": { 9 | "react": "^18.2.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-compatible/packages/ui/src/test.jsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export const TestElement = ({ children, testid }) => { 4 | return
{children}
5 | } 6 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-incompatible/apps/site/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-incompatible/apps/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apps/site", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "@packages/ui": "*", 10 | "next": "13.4.1", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0" 13 | }, 14 | "test": { 15 | "dependencies": { 16 | "next": "13.4.1" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-incompatible/apps/site/pages/index.js: -------------------------------------------------------------------------------- 1 | import { TestElement } from '@packages/ui/test.jsx' 2 | 3 | export default function Home({ ssr }) { 4 | return ( 5 |
6 | SSR: {ssr ? 'yes' : 'no'} 7 |
8 | ) 9 | } 10 | 11 | export const getServerSideProps = async () => { 12 | return { 13 | props: { 14 | ssr: true, 15 | }, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-incompatible/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yarn-monorepo-multiple-next-versions-site-incompatible", 3 | "private": true, 4 | "scripts": { 5 | "build": "cd apps/site && npm run build" 6 | }, 7 | "engines": { 8 | "node": ">=18" 9 | }, 10 | "packageManager": "yarn@1.22.21", 11 | "workspaces": [ 12 | "apps/*", 13 | "packages/*" 14 | ], 15 | "dependencies": { 16 | "next": "latest" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-incompatible/packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@packages/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "exports": { 6 | "./test.jsx": "./src/test.jsx" 7 | }, 8 | "devDependencies": { 9 | "react": "^18.2.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-multiple-next-versions-site-incompatible/packages/ui/src/test.jsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export const TestElement = ({ children, testid }) => { 4 | return
{children}
5 | } 6 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-with-pnpm-linker/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: pnpm 2 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-with-pnpm-linker/apps/site/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | eslint: { 5 | ignoreDuringBuilds: true, 6 | }, 7 | transpilePackages: ['@repo/ui'], 8 | } 9 | 10 | module.exports = nextConfig 11 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-with-pnpm-linker/apps/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apps/site", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build" 7 | }, 8 | "dependencies": { 9 | "@packages/ui": "*", 10 | "next": "latest", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-with-pnpm-linker/apps/site/pages/index.js: -------------------------------------------------------------------------------- 1 | import { TestElement } from '@packages/ui/test.jsx' 2 | 3 | export default function Home({ ssr }) { 4 | return ( 5 |
6 | SSR: {ssr ? 'yes' : 'no'} 7 |
8 | ) 9 | } 10 | 11 | export const getServerSideProps = async () => { 12 | return { 13 | props: { 14 | ssr: true, 15 | }, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-with-pnpm-linker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yarn-monorepo-with-pnpm-linker", 3 | "private": true, 4 | "scripts": { 5 | "build": "yarn workspace @apps/site build" 6 | }, 7 | "engines": { 8 | "node": ">=18" 9 | }, 10 | "packageManager": "yarn@3.2.4", 11 | "workspaces": [ 12 | "apps/*", 13 | "packages/*" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-with-pnpm-linker/packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@packages/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "exports": { 6 | "./test.jsx": "./src/test.jsx" 7 | }, 8 | "devDependencies": { 9 | "react": "^18.2.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/smoke/fixtures/yarn-monorepo-with-pnpm-linker/packages/ui/src/test.jsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export const TestElement = ({ children, testid }) => { 4 | return
{children}
5 | } 6 | -------------------------------------------------------------------------------- /tests/test-setup-e2e.ts: -------------------------------------------------------------------------------- 1 | import { execaCommand } from 'execa' 2 | 3 | // build the runtime before running tests 4 | export default async () => { 5 | console.log(`🔨 Building runtime...`, process.cwd()) 6 | await execaCommand('npm run build') 7 | } 8 | -------------------------------------------------------------------------------- /tests/test-setup.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import { afterEach } from 'vitest' 3 | import { type FixtureTestContext } from './utils/contexts' 4 | 5 | export async function afterTestCleanup({ cleanup }: FixtureTestContext) { 6 | if ('reset' in fs) { 7 | ;(fs as any).reset() 8 | } 9 | 10 | const jobs = (cleanup ?? []).map((job) => job()) 11 | 12 | await Promise.all(jobs) 13 | } 14 | 15 | // cleanup after each test as a fallback if someone forgot to call it 16 | afterEach(async (ctx) => { 17 | await afterTestCleanup(ctx) 18 | }) 19 | -------------------------------------------------------------------------------- /tests/utils/constants.mjs: -------------------------------------------------------------------------------- 1 | export const BLOB_TOKEN = 'secret-token' 2 | -------------------------------------------------------------------------------- /tests/utils/contexts.ts: -------------------------------------------------------------------------------- 1 | import { type getStore } from '@netlify/blobs' 2 | import { BlobsServer } from '@netlify/blobs/server' 3 | import { type WriteStream } from 'node:fs' 4 | import { MockInstance, TestContext } from 'vitest' 5 | 6 | export interface FixtureTestContext extends TestContext { 7 | cwd: string 8 | siteID: string 9 | deployID: string 10 | blobStoreHost: string 11 | blobStorePort: number 12 | blobServer: BlobsServer 13 | blobServerGetSpy: MockInstance, ReturnType> 14 | blobStore: ReturnType 15 | functionDist: string 16 | edgeFunctionPort: number 17 | edgeFunctionOutput: WriteStream 18 | cleanup?: (() => Promise)[] 19 | } 20 | -------------------------------------------------------------------------------- /tests/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './helpers.js' 2 | export * from './mock-file-system.js' 3 | -------------------------------------------------------------------------------- /tools/vendor-deno-tools.js: -------------------------------------------------------------------------------- 1 | import { dirname, join } from 'node:path' 2 | import { fileURLToPath } from 'node:url' 3 | 4 | import { vendorDeno } from './build-helpers.js' 5 | 6 | const denoToolsDirectory = join(dirname(fileURLToPath(import.meta.url)), 'deno') 7 | 8 | await vendorDeno({ 9 | vendorSource: join(denoToolsDirectory, 'eszip.ts'), 10 | cwd: denoToolsDirectory, 11 | wasmFilesToDownload: ['https://deno.land/x/eszip@v0.55.4/eszip_wasm_bg.wasm'], 12 | initEmptyDenoJson: true, 13 | }) 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "resolveJsonModule": true, 7 | "outDir": "./dist", 8 | "rootDir": "src", 9 | "strict": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["tests/**/*", "src/**/*.test.ts", "edge-runtime/**", "tests/netlify-deploy.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /turbofan/netlify.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennextjs/opennextjs-netlify/1f8ae92ac7110949ddbb49e943ffc56ac98d35bf/turbofan/netlify.toml -------------------------------------------------------------------------------- /turbofan/netlify/edge-functions/turbofan.ts: -------------------------------------------------------------------------------- 1 | export { handleRequest as default } from 'https://deno.land/x/turbofan/mod.ts' 2 | 3 | export const config = { 4 | method: ['GET', 'PUT'], 5 | path: '/v8/artifacts/:hash', 6 | cache: 'manual', 7 | } 8 | -------------------------------------------------------------------------------- /vitest.workspace.ts: -------------------------------------------------------------------------------- 1 | import { defineWorkspace } from 'vitest/config' 2 | 3 | export default defineWorkspace([ 4 | { 5 | extends: './vitest.config.ts', 6 | test: { 7 | name: 'unit', 8 | include: ['src/**/*.test.ts'], 9 | }, 10 | }, 11 | { 12 | extends: './vitest.config.ts', 13 | test: { 14 | name: 'integration', 15 | include: ['tests/integration/**/*.test.ts'], 16 | }, 17 | }, 18 | { 19 | extends: './vitest.config.ts', 20 | test: { 21 | name: 'smoke', 22 | include: ['tests/smoke/**/*.test.ts'], 23 | }, 24 | }, 25 | ]) 26 | --------------------------------------------------------------------------------