Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): introduce --tailwind flag #46927

Merged
merged 30 commits into from Mar 16, 2023
Merged

Conversation

balazsorban44
Copy link
Member

@balazsorban44 balazsorban44 commented Mar 8, 2023

What?

This PR introduces a new --tailwind flag to the create-next-app CLI, to make it easier to bootstrap a Next.js app with Tailwind CSS pre-configured.

The question is always going to be asked, remembering your previous answer (eg. if you said "No"). When you choose "No" create-next-app will use CSS imports and CSS modules, same as current stable.

Why?

Tailwind CSS is one of the most popular styling solutions right now, and we would like to make it easier to get started.

Currently, the closest you can come to this is by running pnpm create next-app -e with-tailwindcss which will clone the https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss example. But that example is not configured for the App Router. This PR will let you add Tailwind CSS to both app/, pages/, and start out with TypeScript or JavaScript via the CLI prompts.

(Some community feedback https://twitter.com/dev_jonaskaas/status/1632367991827443713, https://twitter.com/samselikoff/status/1634662473331617794)

How?

We are adding 4 new templates to the CLI bundle.

Note: The styling is not pixel-perfect compared to the current templates (using CSS modules) to require fewer overrides, but I tried to match it as close as possible. Here are a few screenshots:

Current, light
Tailwind (new), light
Current, dark, responsive
Tailwind (new), dark, responsive

For reviewers

This introduces 4 new templates, with a very similar code base to the original ones. To keep the PR focused, I decided to copy over duplicate code, but we could potentially create a shared folder for files that are the same across templates to somewhat reduce the CLI size. Not sure if it's worth it, let me know. Probably fine for now, but something to consider if we are adding more permutations in the future.


Work remaining:

  • app+ts
    • layout
    • dark mode
    • media queries
    • animations
  • app+js
  • pages+ts
  • pages+js
  • prompt/config
  • deprecate Tailwind CSS example in favor of CLI
  • update docs
  • add test
  • add Prettier plugin

Closes NEXT-772
Related #45814, #44286

@ijjk
Copy link
Member

ijjk commented Mar 8, 2023

Stats from current PR

Default Build (Decrease detected ✓)
General Overall increase ⚠️
vercel/next.js canary vercel/next.js feat/tailwind-option-cli Change
buildDuration 38.2s 38.4s ⚠️ +240ms
buildDurationCached 15.4s 10.4s -4.9s
nodeModulesSize 112 MB 112 MB ⚠️ +121 kB
nextStartRea..uration (ms) 293ms 289ms -4ms
Client Bundles (main, webpack) Overall decrease ✓
vercel/next.js canary vercel/next.js feat/tailwind-option-cli Change
669.HASH.js gzip 184 B 181 B -3 B
752-HASH.js gzip 67.1 kB 67.1 kB ⚠️ +7 B
main-app-HASH.js gzip 205 B 205 B
main-HASH.js gzip 82.1 kB 82.1 kB -3 B
webpack-HASH.js gzip 1.7 kB 1.7 kB -4 B
Overall change 151 kB 151 kB -3 B
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js feat/tailwind-option-cli Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages Overall decrease ✓
vercel/next.js canary vercel/next.js feat/tailwind-option-cli Change
_app-HASH.js gzip 192 B 192 B
_error-HASH.js gzip 179 B 179 B
amp-HASH.js gzip 484 B 484 B
css-HASH.js gzip 801 B 805 B ⚠️ +4 B
dynamic-HASH.js gzip 2.27 kB 2.27 kB -1 B
edge-ssr-HASH.js gzip 259 B 259 B
head-HASH.js gzip 829 B 827 B -2 B
hooks-HASH.js gzip 848 B 848 B
image-HASH.js gzip 4.34 kB 4.33 kB -4 B
index-HASH.js gzip 253 B 254 B ⚠️ +1 B
link-HASH.js gzip 2.76 kB 2.76 kB
routerDirect..HASH.js gzip 782 B 783 B ⚠️ +1 B
script-HASH.js gzip 858 B 857 B -1 B
withRouter-HASH.js gzip 781 B 781 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 15.7 kB 15.7 kB -2 B
Client Build Manifests Overall decrease ✓
vercel/next.js canary vercel/next.js feat/tailwind-option-cli Change
_buildManifest.js gzip 483 B 481 B -2 B
Overall change 483 B 481 B -2 B
Rendered Page Sizes Overall decrease ✓
vercel/next.js canary vercel/next.js feat/tailwind-option-cli Change
index.html gzip 549 B 547 B -2 B
link.html gzip 559 B 559 B
withRouter.html gzip 545 B 543 B -2 B
Overall change 1.65 kB 1.65 kB -4 B
Edge SSR bundle Size Overall decrease ✓
vercel/next.js canary vercel/next.js feat/tailwind-option-cli Change
edge-ssr.js gzip 129 kB 129 kB ⚠️ +1 B
page.js gzip 113 kB 113 kB -6 B
Overall change 242 kB 242 kB -5 B
Middleware size Overall decrease ✓
vercel/next.js canary vercel/next.js feat/tailwind-option-cli Change
middleware-b..fest.js gzip 587 B 584 B -3 B
middleware-r..fest.js gzip 145 B 145 B
middleware.js gzip 26.6 kB 26.5 kB -4 B
edge-runtime..pack.js gzip 1.83 kB 1.83 kB
Overall change 29.1 kB 29.1 kB -7 B

Diffs

Diff for page.js

Diff too large to display

Diff for middleware-b..-manifest.js
@@ -7,81 +7,81 @@ self.__BUILD_MANIFEST = {
     "static/BUILD_ID/_ssgManifest.js"
   ],
   rootMainFiles: [
-    "static/chunks/webpack-5b61ddb17d1b1e45.js",
-    "static/chunks/752-e0124f97c29b9b26.js",
-    "static/chunks/main-app-b92193f27d8b291e.js"
+    "static/chunks/webpack-ccdd2722b400e949.js",
+    "static/chunks/253-85b2da8e6895eac4.js",
+    "static/chunks/main-app-32b8cc48f97bc083.js"
   ],
   pages: {
     "/": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/index-6a6bc131ab297216.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/index-c656cc0117c9e7c0.js"
     ],
     "/_app": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/_app-636890403c88b2dd.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/_app-f2ed7a096358f4b4.js"
     ],
     "/_error": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/_error-86fc966c9a292a3a.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/_error-ffc6a2c72515e923.js"
     ],
     "/amp": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/amp-1df3ae6a088904c6.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/amp-3e9ec9130f2c5cf7.js"
     ],
     "/css": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
       "static/css/94fdbc56eafa2039.css",
-      "static/chunks/pages/css-92b2928e1e0211bb.js"
+      "static/chunks/pages/css-317c979ec108751a.js"
     ],
     "/dynamic": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/dynamic-16653600b2640b11.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/dynamic-1130fa60c10e7ac0.js"
     ],
     "/edge-ssr": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/edge-ssr-68c3847a5c552eb9.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/edge-ssr-0796c3ad78d714ae.js"
     ],
     "/head": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/head-99a747ea3724f0c1.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/head-110482826ba1aee9.js"
     ],
     "/hooks": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/hooks-20be8048af77e479.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/hooks-62df938c02847a87.js"
     ],
     "/image": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/image-2111ee042115bcac.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/image-9292cd8356e4678e.js"
     ],
     "/link": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/link-15815e525fc2f5c9.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/link-ecaf3b4e46561321.js"
     ],
     "/routerDirect": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/routerDirect-7a2774eeac425191.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/routerDirect-500bf61b63e3a8fb.js"
     ],
     "/script": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/script-7e9d4b7fbb18ef27.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/script-5543ee91518aa361.js"
     ],
     "/withRouter": [
-      "static/chunks/webpack-5b61ddb17d1b1e45.js",
-      "static/chunks/main-139def0955733c65.js",
-      "static/chunks/pages/withRouter-fd070883a10f183d.js"
+      "static/chunks/webpack-ccdd2722b400e949.js",
+      "static/chunks/main-6c5cc8e0ac600c99.js",
+      "static/chunks/pages/withRouter-b8cffc459de058cd.js"
     ]
   },
   ampFirstPages: []
Diff for middleware-r..-manifest.js
@@ -1,6 +1,6 @@
 self.__REACT_LOADABLE_MANIFEST = {
   "dynamic.js -> ../components/hello": {
-    id: 4669,
-    files: ["static/chunks/669.b4ba997a5768ba52.js"]
+    id: 4674,
+    files: ["static/chunks/674.aa831fb505ba3d01.js"]
   }
 };
Diff for middleware.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [826],
   {
-    /***/ 2955: /***/ (
+    /***/ 82: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -14,7 +14,7 @@
       __webpack_require__.d(__webpack_exports__, {
         default: () =>
           /* binding */ next_middleware_loaderabsolutePagePath_private_next_root_dir_2Fmiddleware_js_page_2Fmiddleware_rootDir_2Ftmp_2Fnext_stats21MCvL_2Fstats_app_matchers_
-      }); // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/error.js
+      }); // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/error.js
 
       class PageSignatureError extends Error {
         constructor({ page }) {
@@ -41,7 +41,7 @@
   Read more: https://nextjs.org/docs/messages/middleware-parse-user-agent
   `);
         }
-      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/utils.js
+      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/utils.js
 
       //# sourceMappingURL=error.js.map
       function fromNodeHeaders(object) {
@@ -157,7 +157,7 @@
             }
           );
         }
-      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/spec-extension/fetch-event.js
+      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/spec-extension/fetch-event.js
 
       //# sourceMappingURL=utils.js.map
       const responseSymbol = Symbol("response");
@@ -203,7 +203,7 @@
             page: this.sourcePage
           });
         }
-      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/i18n/detect-domain-locale.js
+      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/i18n/detect-domain-locale.js
 
       //# sourceMappingURL=fetch-event.js.map
       function detectDomainLocale(domainItems, hostname, detectedLocale) {
@@ -232,7 +232,7 @@
           }
         }
         return domainItem;
-      } //# sourceMappingURL=detect-domain-locale.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/remove-trailing-slash.js
+      } //# sourceMappingURL=detect-domain-locale.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/remove-trailing-slash.js
 
       /**
        * Removes the trailing slash for a given route or page path. Preserves the
@@ -242,7 +242,7 @@
        *   - `/` -> `/`
        */ function removeTrailingSlash(route) {
         return route.replace(/\/$/, "") || "/";
-      } //# sourceMappingURL=remove-trailing-slash.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/parse-path.js
+      } //# sourceMappingURL=remove-trailing-slash.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/parse-path.js
 
       /**
        * Given a path this function will find the pathname, query and hash and return
@@ -270,7 +270,7 @@
           query: "",
           hash: ""
         };
-      } //# sourceMappingURL=parse-path.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/add-path-prefix.js
+      } //# sourceMappingURL=parse-path.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/add-path-prefix.js
 
       /**
        * Adds the provided prefix to the given path. It first ensures that the path
@@ -281,7 +281,7 @@
         }
         const { pathname, query, hash } = parsePath(path);
         return `${prefix}${pathname}${query}${hash}`;
-      } //# sourceMappingURL=add-path-prefix.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/add-path-suffix.js
+      } //# sourceMappingURL=add-path-prefix.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/add-path-suffix.js
 
       /**
        * Similarly to `addPathPrefix`, this function adds a suffix at the end on the
@@ -293,7 +293,7 @@
         }
         const { pathname, query, hash } = parsePath(path);
         return `${pathname}${suffix}${query}${hash}`;
-      } //# sourceMappingURL=add-path-suffix.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/path-has-prefix.js
+      } //# sourceMappingURL=add-path-suffix.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/path-has-prefix.js
 
       /**
        * Checks if a given path starts with a given prefix. It ensures it matches
@@ -307,7 +307,7 @@
         }
         const { pathname } = parsePath(path);
         return pathname === prefix || pathname.startsWith(prefix + "/");
-      } //# sourceMappingURL=path-has-prefix.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/add-locale.js
+      } //# sourceMappingURL=path-has-prefix.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/add-locale.js
 
       /**
        * For a given path and a locale, if the locale is given, it will prefix the
@@ -324,7 +324,7 @@
           return addPathPrefix(path, `/${locale}`);
         }
         return path;
-      } //# sourceMappingURL=add-locale.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/format-next-pathname-info.js
+      } //# sourceMappingURL=add-locale.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/format-next-pathname-info.js
 
       function formatNextPathnameInfo(info) {
         let pathname = addLocale(
@@ -348,7 +348,7 @@
             ? addPathSuffix(pathname, "/")
             : pathname
           : removeTrailingSlash(pathname);
-      } //# sourceMappingURL=format-next-pathname-info.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/get-hostname.js
+      } //# sourceMappingURL=format-next-pathname-info.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/get-hostname.js
 
       /**
        * Takes an object with a hostname property (like a parsed URL) and some
@@ -363,7 +363,7 @@
           parsed.hostname) == null
           ? void 0
           : ref.split(":")[0].toLowerCase();
-      } //# sourceMappingURL=get-hostname.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/i18n/normalize-locale-path.js
+      } //# sourceMappingURL=get-hostname.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/i18n/normalize-locale-path.js
 
       /**
        * For a pathname that may include a locale from a list of locales, it
@@ -393,7 +393,7 @@
           pathname,
           detectedLocale
         };
-      } //# sourceMappingURL=normalize-locale-path.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/remove-path-prefix.js
+      } //# sourceMappingURL=normalize-locale-path.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/remove-path-prefix.js
 
       /**
        * Given a path and a prefix it will remove the prefix when it exists in the
@@ -409,7 +409,7 @@
             : `/${withoutPrefix}`;
         }
         return path;
-      } //# sourceMappingURL=remove-path-prefix.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/get-next-pathname-info.js
+      } //# sourceMappingURL=remove-path-prefix.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/get-next-pathname-info.js
 
       function getNextPathnameInfo(pathname, options) {
         var _nextConfig;
@@ -446,7 +446,7 @@
             info.pathname;
         }
         return info;
-      } //# sourceMappingURL=get-next-pathname-info.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/next-url.js
+      } //# sourceMappingURL=get-next-pathname-info.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/next-url.js
 
       const REGEX_LOCALHOST_HOSTNAME = /(?!^https?:\/\/)(127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}|::1|localhost)/;
       function parseURL(url, base) {
@@ -658,8 +658,8 @@
       }
 
       //# sourceMappingURL=next-url.js.map
-      // EXTERNAL MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/@edge-runtime/cookies/index.js
-      var cookies = __webpack_require__(29); // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/spec-extension/cookies.js // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/spec-extension/request.js
+      // EXTERNAL MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/@edge-runtime/cookies/index.js
+      var cookies = __webpack_require__(8432); // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/spec-extension/cookies.js // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/spec-extension/request.js
       //# sourceMappingURL=cookies.js.map
       const INTERNALS = Symbol("internal request");
       class NextRequest extends Request {
@@ -732,7 +732,7 @@
         get url() {
           return this[INTERNALS].url.toString();
         }
-      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/spec-extension/response.js
+      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/spec-extension/response.js
 
       //# sourceMappingURL=request.js.map
       const response_INTERNALS = Symbol("internal response");
@@ -832,7 +832,7 @@
             headers
           });
         }
-      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/relativize-url.js
+      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/relativize-url.js
 
       //# sourceMappingURL=response.js.map
       /**
@@ -846,7 +846,7 @@
         return `${relative.protocol}//${relative.host}` === origin
           ? relative.toString().replace(origin, "")
           : relative.toString();
-      } //# sourceMappingURL=relativize-url.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/internal-utils.js
+      } //# sourceMappingURL=relativize-url.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/internal-utils.js
 
       const INTERNAL_QUERY_NAMES = [
         "__nextFallback",
@@ -870,7 +870,7 @@
           }
         }
         return searchParams;
-      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/app-paths.js
+      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/shared/lib/router/utils/app-paths.js
 
       //# sourceMappingURL=internal-utils.js.map
       /**
@@ -922,7 +922,7 @@
        * Since this function is used on full urls it checks `?` for searchParams handling.
        */ function normalizeRscPath(pathname, enabled) {
         return enabled ? pathname.replace(/\.rsc($|\?)/, "$1") : pathname;
-      } //# sourceMappingURL=app-paths.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/client/components/app-router-headers.js
+      } //# sourceMappingURL=app-paths.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/client/components/app-router-headers.js
 
       const RSC = "RSC";
       const ACTION = "Next-Action";
@@ -935,7 +935,7 @@
         [RSC],
         [NEXT_ROUTER_STATE_TREE],
         [NEXT_ROUTER_PREFETCH]
-      ]; //# sourceMappingURL=app-router-headers.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/adapter.js
+      ]; //# sourceMappingURL=app-router-headers.js.map // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/esm/server/web/adapter.js
 
       class NextRequestHint extends NextRequest {
         constructor(params) {
@@ -1178,12 +1178,12 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
             throw err;
           }
         }
-      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+main-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/build/webpack/loaders/next-middleware-loader.js?absolutePagePath=private-next-root-dir%2Fmiddleware.js&page=%2Fmiddleware&rootDir=%2Ftmp%2Fnext-stats21MCvL%2Fstats-app&matchers=!
+      } // CONCATENATED MODULE: ./node_modules/.pnpm/file+..+diff-repo+packages+next+next-packed.tgz_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/build/webpack/loaders/next-middleware-loader.js?absolutePagePath=private-next-root-dir%2Fmiddleware.js&page=%2Fmiddleware&rootDir=%2Ftmp%2Fnext-stats21MCvL%2Fstats-app&matchers=!
 
       //# sourceMappingURL=adapter.js.map
       enhanceGlobals();
 
-      var mod = __webpack_require__(7917);
+      var mod = __webpack_require__(619);
       var handler = mod.middleware || mod.default;
 
       if (typeof handler !== "function") {
@@ -1205,7 +1205,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 7917: /***/ (
+    /***/ 619: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -1217,7 +1217,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         /* harmony export */
       });
       /* harmony import */ var next_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
-        8352
+        9541
       );
       /* harmony import */ var next_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/ __webpack_require__.n(
         next_server__WEBPACK_IMPORTED_MODULE_0__
@@ -1230,7 +1230,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 1710: /***/ (__unused_webpack_module, exports) => {
+    /***/ 3426: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -1250,7 +1250,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 8771: /***/ (__unused_webpack_module, exports) => {
+    /***/ 5253: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -1288,7 +1288,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 6567: /***/ (__unused_webpack_module, exports) => {
+    /***/ 1425: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -1320,7 +1320,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 7139: /***/ (
+    /***/ 5259: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -1331,8 +1331,8 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         value: true
       });
       exports.addLocale = addLocale;
-      var _addPathPrefix = __webpack_require__(1330);
-      var _pathHasPrefix = __webpack_require__(4434);
+      var _addPathPrefix = __webpack_require__(4208);
+      var _pathHasPrefix = __webpack_require__(9301);
       function addLocale(path, locale, defaultLocale, ignorePrefix) {
         if (
           locale &&
@@ -1352,7 +1352,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 1330: /***/ (
+    /***/ 4208: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -1363,7 +1363,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         value: true
       });
       exports.addPathPrefix = addPathPrefix;
-      var _parsePath = __webpack_require__(211);
+      var _parsePath = __webpack_require__(2929);
       function addPathPrefix(path, prefix) {
         if (!path.startsWith("/") || !prefix) {
           return path;
@@ -1375,7 +1375,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 8756: /***/ (
+    /***/ 9670: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -1386,7 +1386,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         value: true
       });
       exports.addPathSuffix = addPathSuffix;
-      var _parsePath = __webpack_require__(211);
+      var _parsePath = __webpack_require__(2929);
       function addPathSuffix(path, suffix) {
         if (!path.startsWith("/") || !suffix) {
           return path;
@@ -1398,7 +1398,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 1442: /***/ (
+    /***/ 8265: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -1409,10 +1409,10 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         value: true
       });
       exports.formatNextPathnameInfo = formatNextPathnameInfo;
-      var _removeTrailingSlash = __webpack_require__(4877);
-      var _addPathPrefix = __webpack_require__(1330);
-      var _addPathSuffix = __webpack_require__(8756);
-      var _addLocale = __webpack_require__(7139);
+      var _removeTrailingSlash = __webpack_require__(7876);
+      var _addPathPrefix = __webpack_require__(4208);
+      var _addPathSuffix = __webpack_require__(9670);
+      var _addLocale = __webpack_require__(5259);
       function formatNextPathnameInfo(info) {
         let pathname = (0, _addLocale).addLocale(
           info.pathname,
@@ -1443,7 +1443,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 4132: /***/ (
+    /***/ 4751: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -1454,9 +1454,9 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         value: true
       });
       exports.getNextPathnameInfo = getNextPathnameInfo;
-      var _normalizeLocalePath = __webpack_require__(6567);
-      var _removePathPrefix = __webpack_require__(6881);
-      var _pathHasPrefix = __webpack_require__(4434);
+      var _normalizeLocalePath = __webpack_require__(1425);
+      var _removePathPrefix = __webpack_require__(2576);
+      var _pathHasPrefix = __webpack_require__(9301);
       function getNextPathnameInfo(pathname, options) {
         var _nextConfig;
         const { basePath, i18n, trailingSlash } =
@@ -1506,7 +1506,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 211: /***/ (__unused_webpack_module, exports) => {
+    /***/ 2929: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -1540,7 +1540,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 4434: /***/ (
+    /***/ 9301: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -1551,7 +1551,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         value: true
       });
       exports.pathHasPrefix = pathHasPrefix;
-      var _parsePath = __webpack_require__(211);
+      var _parsePath = __webpack_require__(2929);
       function pathHasPrefix(path, prefix) {
         if (typeof path !== "string") {
           return false;
@@ -1563,7 +1563,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 6881: /***/ (
+    /***/ 2576: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -1574,7 +1574,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         value: true
       });
       exports.removePathPrefix = removePathPrefix;
-      var _pathHasPrefix = __webpack_require__(4434);
+      var _pathHasPrefix = __webpack_require__(9301);
       function removePathPrefix(path, prefix) {
         if ((0, _pathHasPrefix).pathHasPrefix(path, prefix)) {
           const withoutPrefix = path.slice(prefix.length);
@@ -1588,7 +1588,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 4877: /***/ (__unused_webpack_module, exports) => {
+    /***/ 7876: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -1602,7 +1602,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 29: /***/ module => {
+    /***/ 8432: /***/ module => {
       "use strict";
 
       var __defProp = Object.defineProperty;
@@ -1931,7 +1931,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 6166: /***/ (module, exports, __webpack_require__) => {
+    /***/ 6204: /***/ (module, exports, __webpack_require__) => {
       var __dirname = "/";
       var __WEBPACK_AMD_DEFINE_RESULT__;
       (() => {
@@ -2773,7 +2773,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 4524: /***/ (__unused_webpack_module, exports) => {
+    /***/ 8666: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -2814,7 +2814,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 3062: /***/ (
+    /***/ 4901: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -2824,10 +2824,10 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       Object.defineProperty(exports, "__esModule", {
         value: true
       });
-      var _detectDomainLocale = __webpack_require__(8771);
-      var _formatNextPathnameInfo = __webpack_require__(1442);
-      var _getHostname = __webpack_require__(1710);
-      var _getNextPathnameInfo = __webpack_require__(4132);
+      var _detectDomainLocale = __webpack_require__(5253);
+      var _formatNextPathnameInfo = __webpack_require__(8265);
+      var _getHostname = __webpack_require__(3426);
+      var _getNextPathnameInfo = __webpack_require__(4751);
       const REGEX_LOCALHOST_HOSTNAME = /(?!^https?:\/\/)(127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}|::1|localhost)/;
       function parseURL(url, base) {
         return new URL(
@@ -3047,7 +3047,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 3868: /***/ (
+    /***/ 4570: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -3057,7 +3057,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       Object.defineProperty(exports, "__esModule", {
         value: true
       });
-      var _cookies = _interopRequireWildcard(__webpack_require__(29));
+      var _cookies = _interopRequireWildcard(__webpack_require__(8432));
       Object.keys(_cookies).forEach(function(key) {
         if (key === "default" || key === "__esModule") return;
         if (key in exports && exports[key] === _cookies[key]) return;
@@ -3119,7 +3119,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 5829: /***/ (
+    /***/ 5985: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -3131,10 +3131,10 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
         value: true
       };
       __webpack_unused_export__ = void 0;
-      var _nextUrl = __webpack_require__(3062);
-      var _utils = __webpack_require__(88);
-      var _error = __webpack_require__(4524);
-      var _cookies = __webpack_require__(3868);
+      var _nextUrl = __webpack_require__(4901);
+      var _utils = __webpack_require__(30);
+      var _error = __webpack_require__(8666);
+      var _cookies = __webpack_require__(4570);
       const INTERNALS = Symbol("internal request");
       __webpack_unused_export__ = INTERNALS;
       class NextRequest extends Request {
@@ -3215,7 +3215,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 5277: /***/ (
+    /***/ 5165: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -3226,9 +3226,9 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       __webpack_unused_export__ = {
         value: true
       };
-      var _nextUrl = __webpack_require__(3062);
-      var _utils = __webpack_require__(88);
-      var _cookies = __webpack_require__(3868);
+      var _nextUrl = __webpack_require__(4901);
+      var _utils = __webpack_require__(30);
+      var _cookies = __webpack_require__(4570);
       const INTERNALS = Symbol("internal response");
       const REDIRECTS = new Set([301, 302, 303, 307, 308]);
       function handleMiddlewareField(init, headers) {
@@ -3337,7 +3337,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 7873: /***/ (
+    /***/ 9132: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -3351,7 +3351,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       __webpack_unused_export__ = isBot;
       exports.Nf = userAgentFromString;
       exports.WE = userAgent;
-      var _uaParserJs = _interopRequireDefault(__webpack_require__(6166));
+      var _uaParserJs = _interopRequireDefault(__webpack_require__(6204));
       function _interopRequireDefault(obj) {
         return obj && obj.__esModule
           ? obj
@@ -3379,7 +3379,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 88: /***/ (__unused_webpack_module, exports) => {
+    /***/ 30: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -3496,14 +3496,14 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
       /***/
     },
 
-    /***/ 8352: /***/ (module, exports, __webpack_require__) => {
+    /***/ 9541: /***/ (module, exports, __webpack_require__) => {
       const serverExports = {
-        NextRequest: __webpack_require__(5829) /* .NextRequest */.Im,
-        NextResponse: __webpack_require__(5277) /* .NextResponse */.x,
+        NextRequest: __webpack_require__(5985) /* .NextRequest */.Im,
+        NextResponse: __webpack_require__(5165) /* .NextResponse */.x,
         userAgentFromString: __webpack_require__(
-          7873
+          9132
         ) /* .userAgentFromString */.Nf,
-        userAgent: __webpack_require__(7873) /* .userAgent */.WE
+        userAgent: __webpack_require__(9132) /* .userAgent */.WE
       };
 
       if (typeof URLPattern !== "undefined") {
@@ -3529,7 +3529,7 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`;
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = moduleId =>
       __webpack_require__((__webpack_require__.s = moduleId));
-    /******/ var __webpack_exports__ = __webpack_exec__(2955);
+    /******/ var __webpack_exports__ = __webpack_exec__(82);
     /******/ (_ENTRIES =
       typeof _ENTRIES === "undefined"
         ? {}
Diff for edge-ssr.js

Diff too large to display

Diff for _buildManifest.js
@@ -1,28 +1,28 @@
 self.__BUILD_MANIFEST = {
   __rewrites: { beforeFiles: [], afterFiles: [], fallback: [] },
-  "/": ["static\u002Fchunks\u002Fpages\u002Findex-6a6bc131ab297216.js"],
-  "/_error": ["static\u002Fchunks\u002Fpages\u002F_error-86fc966c9a292a3a.js"],
-  "/amp": ["static\u002Fchunks\u002Fpages\u002Famp-1df3ae6a088904c6.js"],
+  "/": ["static\u002Fchunks\u002Fpages\u002Findex-c656cc0117c9e7c0.js"],
+  "/_error": ["static\u002Fchunks\u002Fpages\u002F_error-ffc6a2c72515e923.js"],
+  "/amp": ["static\u002Fchunks\u002Fpages\u002Famp-3e9ec9130f2c5cf7.js"],
   "/css": [
     "static\u002Fcss\u002F94fdbc56eafa2039.css",
-    "static\u002Fchunks\u002Fpages\u002Fcss-92b2928e1e0211bb.js"
+    "static\u002Fchunks\u002Fpages\u002Fcss-317c979ec108751a.js"
   ],
   "/dynamic": [
-    "static\u002Fchunks\u002Fpages\u002Fdynamic-16653600b2640b11.js"
+    "static\u002Fchunks\u002Fpages\u002Fdynamic-1130fa60c10e7ac0.js"
   ],
   "/edge-ssr": [
-    "static\u002Fchunks\u002Fpages\u002Fedge-ssr-68c3847a5c552eb9.js"
+    "static\u002Fchunks\u002Fpages\u002Fedge-ssr-0796c3ad78d714ae.js"
   ],
-  "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-99a747ea3724f0c1.js"],
-  "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-20be8048af77e479.js"],
-  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-2111ee042115bcac.js"],
-  "/link": ["static\u002Fchunks\u002Fpages\u002Flink-15815e525fc2f5c9.js"],
+  "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-110482826ba1aee9.js"],
+  "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-62df938c02847a87.js"],
+  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-9292cd8356e4678e.js"],
+  "/link": ["static\u002Fchunks\u002Fpages\u002Flink-ecaf3b4e46561321.js"],
   "/routerDirect": [
-    "static\u002Fchunks\u002Fpages\u002FrouterDirect-7a2774eeac425191.js"
+    "static\u002Fchunks\u002Fpages\u002FrouterDirect-500bf61b63e3a8fb.js"
   ],
-  "/script": ["static\u002Fchunks\u002Fpages\u002Fscript-7e9d4b7fbb18ef27.js"],
+  "/script": ["static\u002Fchunks\u002Fpages\u002Fscript-5543ee91518aa361.js"],
   "/withRouter": [
-    "static\u002Fchunks\u002Fpages\u002FwithRouter-fd070883a10f183d.js"
+    "static\u002Fchunks\u002Fpages\u002FwithRouter-b8cffc459de058cd.js"
   ],
   sortedPages: [
     "\u002F",
Diff for _app-HASH.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [888],
   {
-    /***/ 3115: /***/ function(
+    /***/ 1113: /***/ function(
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/_app",
         function() {
-          return __webpack_require__(1747);
+          return __webpack_require__(2394);
         }
       ]);
       if (false) {
@@ -24,7 +24,7 @@
       return __webpack_require__((__webpack_require__.s = moduleId));
     };
     /******/ __webpack_require__.O(0, [179], function() {
-      return __webpack_exec__(3115), __webpack_exec__(6463);
+      return __webpack_exec__(1113), __webpack_exec__(4819);
     });
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for _error-HASH.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [820],
   {
-    /***/ 5374: /***/ function(
+    /***/ 3363: /***/ function(
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/_error",
         function() {
-          return __webpack_require__(4929);
+          return __webpack_require__(5797);
         }
       ]);
       if (false) {
@@ -24,7 +24,7 @@
       return __webpack_require__((__webpack_require__.s = moduleId));
     };
     /******/ __webpack_require__.O(0, [888, 179], function() {
-      return __webpack_exec__(5374);
+      return __webpack_exec__(3363);
     });
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for amp-HASH.js
@@ -1,17 +1,17 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [216],
   {
-    /***/ 8510: /***/ function(
+    /***/ 8753: /***/ function(
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) {
-      module.exports = __webpack_require__(5469);
+      module.exports = __webpack_require__(8506);
 
       /***/
     },
 
-    /***/ 7010: /***/ function(
+    /***/ 5348: /***/ function(
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -19,7 +19,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/amp",
         function() {
-          return __webpack_require__(1074);
+          return __webpack_require__(3121);
         }
       ]);
       if (false) {
@@ -28,7 +28,7 @@
       /***/
     },
 
-    /***/ 5469: /***/ function(module, exports, __webpack_require__) {
+    /***/ 8506: /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -37,9 +37,9 @@
       exports.useAmp = useAmp;
       var _interop_require_default = __webpack_require__(1322) /* ["default"] */
         .Z;
-      var _react = _interop_require_default(__webpack_require__(2947));
-      var _ampContext = __webpack_require__(8619);
-      var _ampMode = __webpack_require__(9758);
+      var _react = _interop_require_default(__webpack_require__(465));
+      var _ampContext = __webpack_require__(5758);
+      var _ampMode = __webpack_require__(3608);
       function useAmp() {
         // Don't assign the context value to a variable to save bytes
         return (0, _ampMode).isInAmpMode(
@@ -61,7 +61,7 @@
       /***/
     },
 
-    /***/ 1074: /***/ function(
+    /***/ 3121: /***/ function(
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -78,7 +78,7 @@
         /* harmony export */
       });
       /* harmony import */ var next_amp__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
-        8510
+        8753
       );
       /* harmony import */ var next_amp__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/ __webpack_require__.n(
         next_amp__WEBPACK_IMPORTED_MODULE_0__
@@ -102,7 +102,7 @@
       return __webpack_require__((__webpack_require__.s = moduleId));
     };
     /******/ __webpack_require__.O(0, [888, 179], function() {
-      return __webpack_exec__(7010);
+      return __webpack_exec__(5348);
     });
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for css-HASH.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [706],
   {
-    /***/ 860: /***/ function(
+    /***/ 6437: /***/ function(
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/css",
         function() {
-          return __webpack_require__(851);
+          return __webpack_require__(1467);
         }
       ]);
       if (false) {
@@ -18,7 +18,7 @@
       /***/
     },
 
-    /***/ 851: /***/ function(
+    /***/ 1467: /***/ function(
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,10 +26,10 @@
       "use strict";
       __webpack_require__.r(__webpack_exports__);
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
-        3268
+        9701
       );
       /* harmony import */ var _css_module_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
-        4294
+        5725
       );
       /* harmony import */ var _css_module_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/ __webpack_require__.n(
         _css_module_css__WEBPACK_IMPORTED_MODULE_1__
@@ -49,14 +49,14 @@
       /***/
     },
 
-    /***/ 4294: /***/ function(module) {
+    /***/ 5725: /***/ function(module) {
       // extracted by mini-css-extract-plugin
       module.exports = { helloWorld: "css_helloWorld__qqNwY" };
 
       /***/
     },
 
-    /***/ 6205: /***/ function(
+    /***/ 1963: /***/ function(
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -71,7 +71,7 @@
        * This source code is licensed under the MIT license found in the
        * LICENSE file in the root directory of this source tree.
        */
-      var f = __webpack_require__(2947),
+      var f = __webpack_require__(465),
         k = Symbol.for("react.element"),
         l = Symbol.for("react.fragment"),
         m = Object.prototype.hasOwnProperty,
@@ -106,7 +106,7 @@
       /***/
     },
 
-    /***/ 3268: /***/ function(
+    /***/ 9701: /***/ function(
       module,
       __unused_webpack_exports,
       __webpack_require__
@@ -114,7 +114,7 @@
       "use strict";
 
       if (true) {
-        module.exports = __webpack_require__(6205);
+        module.exports = __webpack_require__(1963);
       } else {
       }
 
@@ -127,7 +127,7 @@
       return __webpack_require__((__webpack_require__.s = moduleId));
     };
     /******/ __webpack_require__.O(0, [888, 179], function() {
-      return __webpack_exec__(860);
+      return __webpack_exec__(6437);
     });
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for dynamic-HASH.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [739],
   {
-    /***/ 3995: /***/ function(
+    /***/ 7753: /***/ function(
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/dynamic",
         function() {
-          return __webpack_require__(3135);
+          return __webpack_require__(1803);
         }
       ]);
       if (false) {
@@ -18,7 +18,7 @@
       /***/
     },
 
-    /***/ 6726: /***/ function(module, exports, __webpack_require__) {
+    /***/ 9887: /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -29,8 +29,8 @@
       var _extends = __webpack_require__(5321) /* ["default"] */.Z;
       var _interop_require_default = __webpack_require__(1322) /* ["default"] */
         .Z;
-      var _react = _interop_require_default(__webpack_require__(2947));
-      var _loadable = _interop_require_default(__webpack_require__(2096));
+      var _react = _interop_require_default(__webpack_require__(465));
+      var _loadable = _interop_require_default(__webpack_require__(7341));
       function dynamic(dynamicOptions, options) {
         let loadableFn = _loadable.default;
         let loadableOptions = {
@@ -127,7 +127,7 @@
       /***/
     },
 
-    /***/ 6738: /***/ function(
+    /***/ 2994: /***/ function(
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -140,7 +140,7 @@
       exports.LoadableContext = void 0;
       var _interop_require_default = __webpack_require__(1322) /* ["default"] */
         .Z;
-      var _react = _interop_require_default(__webpack_require__(2947));
+      var _react = _interop_require_default(__webpack_require__(465));
       const LoadableContext = _react.default.createContext(null);
       exports.LoadableContext = LoadableContext;
       if (false) {
@@ -149,7 +149,7 @@
       /***/
     },
 
-    /***/ 2096: /***/ function(
+    /***/ 7341: /***/ function(
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -163,8 +163,8 @@
       var _extends = __webpack_require__(5321) /* ["default"] */.Z;
       var _interop_require_default = __webpack_require__(1322) /* ["default"] */
         .Z;
-      var _react = _interop_require_default(__webpack_require__(2947));
-      var _loadableContext = __webpack_require__(6738);
+      var _react = _interop_require_default(__webpack_require__(465));
+      var _loadableContext = __webpack_require__(2994);
       function resolve(obj) {
         return obj && obj.default ? obj.default : obj;
       }
@@ -404,7 +404,7 @@
       /***/
     },
 
-    /***/ 3135: /***/ function(
+    /***/ 1803: /***/ function(
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -418,10 +418,10 @@
         /* harmony export */
       });
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
-        3268
+        9701
       );
       /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
-        6113
+        2677
       );
       /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/ __webpack_require__.n(
         next_dynamic__WEBPACK_IMPORTED_MODULE_1__
@@ -430,11 +430,11 @@
       const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
         () =>
           __webpack_require__
-            .e(/* import() */ 669)
-            .then(__webpack_require__.bind(__webpack_require__, 4669)),
+            .e(/* import() */ 674)
+            .then(__webpack_require__.bind(__webpack_require__, 4674)),
         {
           loadableGenerated: {
-            webpack: () => [/*require.resolve*/ 4669]
+            webpack: () => [/*require.resolve*/ 4674]
           }
         }
       );
@@ -461,7 +461,7 @@
       /***/
     },
 
-    /***/ 6205: /***/ function(
+    /***/ 1963: /***/ function(
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -476,7 +476,7 @@
        * This source code is licensed under the MIT license found in the
        * LICENSE file in the root directory of this source tree.
        */
-      var f = __webpack_require__(2947),
+      var f = __webpack_require__(465),
         k = Symbol.for("react.element"),
         l = Symbol.for("react.fragment"),
         m = Object.prototype.hasOwnProperty,
@@ -511,7 +511,7 @@
       /***/
     },
 
-    /***/ 3268: /***/ function(
+    /***/ 9701: /***/ function(
       module,
       __unused_webpack_exports,
       __webpack_require__
@@ -519,19 +519,19 @@
       "use strict";
 
       if (true) {
-        module.exports = __webpack_require__(6205);
+        module.exports = __webpack_require__(1963);
       } else {
       }
 
       /***/
     },
 
-    /***/ 6113: /***/ function(
+    /***/ 2677: /***/ function(
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) {
-      module.exports = __webpack_require__(6726);
+      module.exports = __webpack_require__(9887);
 
       /***/
     }
@@ -542,7 +542,7 @@
       return __webpack_require__((__webpack_require__.s = moduleId));
     };
     /******/ __webpack_require__.O(0, [888, 179], function() {
-      return __webpack_exec__(3995);
+      return __webpack_exec__(7753);
     });
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for edge-ssr-HASH.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [800],
   {
-    /***/ 6219: /***/ function(
+    /***/ 6027: /***/ function(
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/edge-ssr",
         function() {
-          return __webpack_require__(2562);
+          return __webpack_require__(4805);
         }
       ]);
       if (false) {
@@ -18,7 +18,7 @@
       /***/
     },
 
-    /***/ 2562: /***/ function(
+    /***/ 4805: /***/ function(
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -50,7 +50,7 @@
       return __webpack_require__((__webpack_require__.s = moduleId));
     };
     /******/ __webpack_require__.O(0, [888, 179], function() {
-      return __webpack_exec__(6219);
+      return __webpack_exec__(6027);
     });
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for head-HASH.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [645],
   {
-    /***/ 2899: /***/ function(
+    /***/ 6955: /***/ function(
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/head",
         function() {
-          return __webpack_require__(3368);
+          return __webpack_require__(26);
         }
       ]);
       if (false) {
@@ -18,7 +18,7 @@
       /***/
     },
 
-    /***/ 3368: /***/ function(
+    /***/ 26: /***/ function(
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -32,10 +32,10 @@
         /* harmony export */
       });
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
-        3268
+        9701
       );
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
-        8412
+        9046
       );
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/ __webpack_require__.n(
         next_head__WEBPACK_IMPORTED_MODULE_1__
@@ -69,7 +69,7 @@
       /***/
     },
 
-    /***/ 6205: /***/ function(
+    /***/ 1963: /***/ function(
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -84,7 +84,7 @@
        * This source code is licensed under the MIT license found in the
        * LICENSE file in the root directory of this source tree.
        */
-      var f = __webpack_require__(2947),
+      var f = __webpack_require__(465),
         k = Symbol.for("react.element"),
         l = Symbol.for("react.fragment"),
         m = Object.prototype.hasOwnProperty,
@@ -119,7 +119,7 @@
       /***/
     },
 
-    /***/ 3268: /***/ function(
+    /***/ 9701: /***/ function(
       module,
       __unused_webpack_exports,
       __webpack_require__
@@ -127,19 +127,19 @@
       "use strict";
 
       if (true) {
-        module.exports = __webpack_require__(6205);
+        module.exports = __webpack_require__(1963);
       } else {
       }
 
       /***/
     },
 
-    /***/ 8412: /***/ function(
+    /***/ 9046: /***/ function(
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) {
-      module.exports = __webpack_require__(7490);
+      module.exports = __webpack_require__(3786);
 
       /***/
     }
@@ -150,7 +150,7 @@
       return __webpack_require__((__webpack_require__.s = moduleId));
     };
     /******/ __webpack_require__.O(0, [888, 179], function() {
-      return __webpack_exec__(2899);
+      return __webpack_exec__(6955);
     });
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for hooks-HASH.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [757],
   {
-    /***/ 2304: /***/ function(
+    /***/ 7819: /***/ function(
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/hooks",
         function() {
-          return __webpack_require__(447);
+          return __webpack_require__(4776);
         }
       ]);
       if (false) {
@@ -18,7 +18,7 @@
       /***/
     },
 
-    /***/ 447: /***/ function(
+    /***/ 4776: /***/ function(
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,10 +26,10 @@
       "use strict";
       __webpack_require__.r(__webpack_exports__);
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
-        3268
+        9701
       );
       /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require_
Post job cleanup.
[command]/usr/bin/git version
git version 2.39.2
Temporarily overriding HOME='/home/runner/work/_temp/5408403f-4a74-4d80-9f77-9772158c56e4' before making global git config changes
Adding repository directory to the temporary git global config as a safe directory
[command]/usr/bin/git config --global --add safe.directory /home/runner/work/next.js/next.js
[command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand
[command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :"
[command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader
http.https://github.com/.extraheader
[command]/usr/bin/git config --local --unset-all http.https://github.com/.extraheader
[command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :"
Cleaning up orphan processes
Commit: 03fac6f6c7be4d42183411a914583bc41e1d2688

@ijjk
Copy link
Member

ijjk commented Mar 8, 2023

Failing test suites

Commit: 03fac6f

pnpm testheadless test/development/acceptance-app/unsupported-app-features.test.ts

  • Error Overlay unsupported app features > should show error exporting AMP config in app dir
Expand output

● Error Overlay unsupported app features › should show error exporting AMP config in app dir

expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  31 |       )
  32 |
> 33 |       expect(await session.hasRedbox(true)).toBe(true)
     |                                             ^
  34 |       expect(await session.getRedboxDescription()).toInclude(
  35 |         'AMP is not supported in the app directory. If you need to use AMP it will continue to be supported in the pages directory.'
  36 |       )

  at Object.<anonymous> (development/acceptance-app/unsupported-app-features.test.ts:33:45)

Read more about building and testing Next.js in contributing.md.

@balazsorban44 balazsorban44 changed the title feat(cli): introduce --tailwind flag (WIP) feat(cli): introduce --tailwind flag Mar 13, 2023
@balazsorban44 balazsorban44 marked this pull request as ready for review March 14, 2023 17:48
@anindosarker
Copy link

What a timing! I just created a tailwindcss example updated with the latest design. But I see theres work going on it.

Cureently:
create-next-app with tailwindcss example doesn't work
there is no --with tailwind flag either. Should I submit a PR for the new example??

@ctjlewis
Copy link
Contributor

Good work OP. And now, a moment of silence for #24709, whose untimely demise last May was preventable.

@OleksandrDemian
Copy link

Why should Tailwind be the default option? A lot of people doesn't use it. I think this feature is cool (I occasionally use Tailwind myself), but if I'm new to the Next and I don't want to use Tailwind, how am I supposed to know I should've opted out with --no-tailwind flag instead of having to remove tailwind configs to setup whatever I want (css-in-js, vanilla css, etc...)?

It makes way more sense to make Tailwind to be opt in feature, if I want to setup next app with Tailwind I will use --tailwind.

@ctjlewis
Copy link
Contributor

ctjlewis commented Mar 20, 2023

@OleksandrDemian - these were all of the reasons the Next team was hesitant to make that change.

The reality is that there are way too many choices that go into shipping modern websites, and Next makes this easier by doing that work for you, including by deciding what "a modern React app looks like by default."

This same choice happened with TypeScript, which was also met with (prudent) hesitancy, and now there seems to be a consensus forming around Tailwind for the styles layer.

It's very good that this is being done, and that someone who is very new to React and this ecosystem doesn't have to be forced with making a choice when they don't have enough information to choose. Or try to deal with CSS modules or something.

A catalyzing event for this I think was seeing ChatGPT also run on what is the de facto modern web stack: TypeScript, Next.js, Tailwind. This definitely matches what I've seen among companies working with Next, and seeing it confirmed with an iPhone-scale product like Chat, it's appropriate to take the hint and standardize it IMO, and probably would've made sense even last year.

@alainkaiser
Copy link
Contributor

love this!

ijjk added a commit that referenced this pull request Mar 20, 2023
### What?

- [x] fixes a bug in the CLI with the combination of `--tailwind` and
`--src-dir` flags.
- [x] fixes Tailwind CSS config when `--src-dir` is set
- [x] respect `NEXT_TEST_SKIP_CLEANUP` in test utils

### Why?

`pnpm create next-app@canary --tailwind --src-dir` should not fail.

### How?

We introduced the `app-tw` and `default-tw` templates, so we need to
respect them when working with files (in this case, the CLI was
erroneously assuming that if `template !== "app"` it must be a pages
template.)

I also noticed that the `tailwind.config.js` file need to also respect
`--src-dir` by prefixing the paths in `content`

Fixes #47236
fix NEXT-838 ([link](https://linear.app/vercel/issue/NEXT-838))

Related: #46927, #47276

---------

Co-authored-by: JJ Kasper <jj@jjsweb.site>
@jonathandewitt-dev
Copy link

jonathandewitt-dev commented Mar 20, 2023

@ctjlewis Hold up, hold up, hoooold the phone.

I get that Next is trying to limit decision fatigue, and Tailwind happens to be very popular right now. But I disagree that it makes sense to make it the new default. It's unexpected to see it so matter-of-factly stated as if there is no controversy.

NOTE: I have no qualms with offering the opt-in approach, and I commend the authors of this PR. It's specifically the default part I take issue with.

I get the sense that the sway Next has is being vastly underestimated. It's possibly the single most popular web framework, period. The only step up from here would be a browser that's implementing standards. I want to be clear, I'm not just being dramatic because I don't like Tailwind, I'm looking at how such a change is going to shape the future of the industry. This will very likely go beyond a small decision for the users of your product.

The debates for and against Tailwind are often exasperating for all parties involved, which is the issue. There's a lot of contention. We're far from a consensus, and that's a worrying factor. This is a bold and biased move coming from a place of significant influence, almost political in nature, to push a one-sided agenda that not everyone signed up for. I would urge the Next team to consider its responsibility to the industry.

Have a look at what a handful of people are already saying about this change on Twitter:

Of course, half of them (not shown) praise the decision too, but the point is this isn't as clear of a win to your users as you might think it is.

ijjk added a commit that referenced this pull request Mar 20, 2023
### What?

- fixes some typos
  - [x] getting started by editing "filename"
  - [x] match app/pages content
  - [x] fix utm params 
- [x] Reverted different text coloring in the CLI as they were hard to
read on a dark background
- [x] removes 13 ([Slack
thread](https://vercel.slack.com/archives/C03KAR5DCKC/p1679151687968809?thread_ts=1679123593.519319&cid=C03KAR5DCKC))


### Why?

Unifying the styles across all templates

### How?

Used
https://github.com/vercel/next.js/tree/canary/packages/create-next-app/templates/default/js
as the base and made sure that all other templates match its content and
styling.

Related: #46927. This PR was extracted from #47238 to make reviewing
easier.

fix NEXT-851 ([link](https://linear.app/vercel/issue/NEXT-851))

---------

Co-authored-by: JJ Kasper <jj@jjsweb.site>
@jonathandewitt-dev
Copy link

jonathandewitt-dev commented Mar 21, 2023

Let's take a look at all the options we have for CSS encapsulation, putting aside the subjective popularity for a moment.

Tailwind CSS Modules Styled-Components Vanilla-Extract Shadow DOM
Avoids specificity conflicts ✔️ ✔️ ✔️ ✔️ ✔️
Safe from naming collisions ✔️ ✔️ ✔️ ✔️
Safe from style inheritance ✔️
Transferable experience ✔️ ✔️ ✔️ ✔️
Easy grid layouts ✔️ ✔️ ✔️ ✔️
Swappable 1 ✔️ ✔️ ✔️
Tool / Framework agnostic ✔️ ✔️ ✔️ ✔️ ✔️
Colocation ✔️ ✔️ ✔️ ✔️
Avoids naming overhead 2 ✔️ ✔️
Flexible theming 3 ✔️ ✔️
Ideal to inspect in the browser ✔️ ✔️ ✔️ ✔️
Avoids runtime cost ✔️ ✔️ ✔️ ✔️
Requires minimal boilerplate ✔️ ✔️ ✔️
Popular 4 ✔️
Widely supported 5 ✔️ ✔️ ✔️ ✔️

1 Vanilla-Extract may require a small amount of extra effort to copy/paste styles, because of the JS object syntax.
2 Some tools partially mitigate naming overhead by using smaller scopes. Shadow DOM can directly select tags.
3 Some tools don't provide a theming framework, but they don't prevent them either. Tailwind doesn't provide first-class support for 3+ themes, nor rebranding ("blue" will always be some shade of blue, it can never change to yellow.)
4 Vanilla-Extract is growing in popularity among Styled-Components fans who want the same DX without the runtime cost.
5 Shadow DOM is widely supported by modern browsers, but there's still some inconsistencies in full support for all its features and related features. Declarative Shadow DOM, for example.


Right away, you'll notice all the X's in the Tailwind column. Those X's come at the cost of what Next decides "a modern React app looks like by default."

Vanilla Extract looks like a solid default, but I realize it may also be a biased and controversial change, so maybe that's too much to ask. But what's not too controversial that's right under our noses?

Yes, Shadow DOM is not too popular and its support is slow to catch up, but here's the thing: it doesn't have to require the developer to manually write all the setup and boilerplate. I know we've all but forgotten about Angular, but take a look at what they did for example. If it's really necessary, maybe throw in a polyfill, instead of a dependency. If you want, you could even provide some kind of default theming solution - I'd be willing to help with this effort, for what it's worth.

Alternatively, you could implement some kind of default scoping, as Vue and Angular have done since the beginning. Admittedly, .title[data-v-3877ef9b] is not a perfect solution, since it's more at risk of inheriting unwanted styles than transforming the class name itself. But this gives Next an opportunity to do it better. It's not new for a framework to offer some default solution for the lack of an extra dependency.

That way, you would have a sensible default, and you could let your developers voluntarily shoulder the drawbacks if they still opt-in after learning about them. Bending to the popularity, to me, is not valid enough to justify moving the industry in that direction. Imagine responding to the widespread overuse of useEffect with the rationale that, "well, it's popular, this is what modern apps look like." I feel like the actual response to that was appropriate, and should be emulated where possible and necessary.

@jeffscottward
Copy link

Let's take a look at all the options we have for CSS encapsulation, putting aside the subjective popularity for a moment.

Tailwind CSS Modules Styled-Components Vanilla-Extract Shadow DOM
Avoids specificity conflicts ✔️ ✔️ ✔️ ✔️ ✔️
Safe from naming collisions ❌ ✔️ ✔️ ✔️ ✔️
Safe from style inheritance ❌ ❌ ❌ ❌ ✔️
Transferable experience ❌ ✔️ ✔️ ✔️ ✔️
Easy grid layouts ❌ ✔️ ✔️ ✔️ ✔️
Swappable 1 ❌ ✔️ ✔️ ➖ ✔️
Tool / Framework agnostic ✔️ ✔️ ✔️ ✔️ ✔️
Colocation ✔️ ❌ ✔️ ✔️ ✔️
Avoids naming overhead 2 ✔️ ➖ ➖ ➖ ✔️
Flexible theming 3 ❌ ➖ ✔️ ✔️ ➖
Ideal to inspect in the browser ❌ ✔️ ✔️ ✔️ ✔️
Avoids runtime cost ✔️ ✔️ ❌ ✔️ ✔️
Doesn't require heavy boilerplate ❌ ✔️ ✔️ ✔️ ❌
Popular 4 ✔️ ❌ ❌ ➖ ❌
Widely supported 5 ✔️ ✔️ ✔️ ✔️ ➖
1 Vanilla-Extract may require a small amount of extra effort to copy/paste styles, because of the JS object syntax. 2 Some tools partially mitigate naming overhead by using smaller scopes. Shadow DOM can directly select tags. 3 Some tools don't provide a theming framework, but they don't prevent them either. Tailwind doesn't provide first-class support for 3+ themes, nor rebranding ("blue" will always be some shade of blue, it can never change to yellow.) 4 Vanilla-Extract is growing in popularity among Styled-Components fans who want the same DX without the runtime cost. 5 Shadow DOM is widely supported by modern browsers, but there's still some inconsistencies in full support for all its features and related features. Declarative Shadow DOM, for example.

Right away, you'll notice all the X's in the Tailwind column. Those X's come at the cost of what Next decides "a modern React app looks like by default."

Vanilla Extract looks like a solid default, but I realize it may also be a biased and controversial change, so maybe that's too much to ask. But what's not too controversial that's right under our noses?

Yes, Shadow DOM is not too popular and its support is slow to catch up, but here's the thing: it doesn't have to require the developer to manually write all the setup and boilerplate. I know we've all but forgotten about Angular, but take a look at what they did for example. If it's really necessary, maybe throw in a polyfill, instead of a dependency. If you want, you could even provide some kind of default theming solution - I'd be willing to help with this effort, for what it's worth.

Alternatively, you could implement some kind of default scoping, as Vue and Angular have done since the beginning. Admittedly, .title[data-v-3877ef9b] is not a perfect solution, since it's more at risk of inheriting unwanted styles than transforming the class name itself. But this gives Next an opportunity to do it better. It's not new for a framework to offer some default solution for the lack of an extra dependency.

That way, you would have a sensible default, and you could let your developers voluntarily shoulder the drawbacks if they still opt-in after learning about them. Bending to the popularity, to me, is not valid enough to justify moving the industry in that direction. Imagine responding to the widespread overuse of useEffect with the rationale that, "well, it's popular, this is what modern apps look like." I feel like the actual response to that was appropriate, and should be emulated where possible and necessary.

This doesn’t even take into account systems like Radix, ThemeUI, ChakraUI, etc that follow the SystemUI spec which I personally think is truly the gold standard of hitting that simplicity and scalability happy medium that is truly well thought out.

While the React docs say not to do inlineCSS from a speed perspective, I’ve found it to be far and away the most ergonomic approach and have not seen any performance hit even at scale.

I digress but the point being, is that “default” options do set precedent as someone above mentioned and we should discourage any such controversial tool from bypassing a consensus of quality. Popularity doesn’t necessarily mean GOOD. Bootstrap has fallen out of favor in the industry and with good reason. We don’t want to encourage bad practices as a “default”.

@timneutkens
Copy link
Member

Posted a reply on the tweets. This PR was misinterpreted by Flavio and is (probably unintentionally) spreading a lot of FUD. This change is specifically about adding a question to create-next-app. Tailwind CSS is not built-in to Next.js and not a default. With this change it's a question "Do you want to use Tailwind CSS yes/no", there's nothing that will prohibit you from using the CSS Modules default. There's also nothing prohibiting you from using any other styling solutions. Examples for all CSS-in-JS libraries are available in the docs: https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js

https://twitter.com/timneutkens/status/1638087513007898625

@jeffscottward
Copy link

Posted a reply on the tweets. This PR was misinterpreted by Flavio and is (probably unintentionally) spreading a lot of FUD. This change is specifically about adding a question to create-next-app. Tailwind CSS is not built-in to Next.js and not a default. With this change it's a question "Do you want to use Tailwind CSS yes/no", there's nothing that will prohibit you from using the CSS Modules default. There's also nothing prohibiting you from using any other styling solutions. Examples for all CSS-in-JS libraries are available in the docs: https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js

https://twitter.com/timneutkens/status/1638087513007898625

I think the concern still stands even when clarified. What I would like to see is a multi-select of perhaps 3-5 options, such as TW, some System-UI flavor, Styled-Components, CSS Modules.
It's not a binary choice like TS or JS.
You can leave TW at the top as "the default" if you just hit Enter very fast, but at least you'll have visibility on diff styles.
I think that's quite reasonable.

@jonathandewitt-dev
Copy link

With this change it's a question "Do you want to use Tailwind CSS yes/no"

Got it, thanks for clarifying.

I think the concern still stands even when clarified.

I also second this... although I'm not sure that showing a list would sufficiently address it. I still think the risk of hitting enter very fast is a reasonable concern.

So I'll start with this - I hope this doesn't come across too strong, I want the Next team to feel proud of what they've built and I don't want the PR author to feel bad. I just use my voice when I feel like there's a lot at stake.

Much like way back in the early 2000s, when you'd install some software and hit enter a bunch to make the wizard go away, then only later find that it had installed a Yahoo toolbar or something... having default selections still has a significant impact.

As mentioned earlier:

someone who is very new to React and this ecosystem doesn't have to be forced with making a choice when they don't have enough information to choose.

This is primarily what I'm concerned about. New developers don't understand the pros/cons, and making their easy way out into Tailwind is controversial for all the reasons previously mentioned.

there seems to be a consensus forming around Tailwind for the styles layer.

I think this conflates mass popularity with consensus of quality, because I have yet to see this consensus for myself. Everywhere I see a Tailwind thread, I see an argument. And, succinctly put:

Popularity doesn’t necessarily mean GOOD.

@ctjlewis
Copy link
Contributor

ctjlewis commented Mar 21, 2023

Yeah, it should really be stressed that it's not a "default" as much as a "setup option." It's a Yes/No prompt, it doesn't force anything on anyone.

Look, the template logic in CNA makes it possible to add a Yes/No question for any stack configuration:

Choose a CSS option: 
  - Tailwind 
  - CSS Modules

Is easily added. That's why it was written that way.

It's not the end of the world. Simply say "No" to Tailwind for now and make a feature request for the setup configs you'd like CNA to support.

@OleksandrDemian
Copy link

Next.js favoring Tailwind might be a huge blow to the CSS ecosystem, but I also understand that maintaining multiple integrations might be difficult. This entire discussion makes me also think about a broader topic: should Next.js be opinionated on some non "core" features like styling, state management, etc.?

Having an opinionated framework is definitely beneficial for the Next.js team, as they will be able to offer better developer experience with one way of doing things. However, I also believe that Angular lost against React (in terms of adoption) because it was too opinionated, as developers will always prefer more flexibility.

I also believe that having a choice between Tailwind and "whatever you want, do it yourself" might push a lot of developers to use Tailwind against their will. I can imagine a team lead setting up a new project with Tailwind because it is considered "standard", even though the rest of the team may not want to use it.

Some might argue that doing the same with Typescript (offering TS as alternative to JS) was beneficial, but it is a completely different situation, since TS is an improvement on top of JS, while Tailwind is one of many ways of styling your webapp.

PS: I would hate it if tomorrow you will ask if I want to setup Redux or not.

@ctjlewis
Copy link
Contributor

should Next.js be opinionated on some non "core" features like styling, state management, etc.?

Yes. A State Management setup option would be smart. Recoil should probably be the default.

@jeffscottward
Copy link

Recoil?? What? Zustand is in almost every YouTube video I've found in that past year.

We're getting off topic here though. Please, let's return to the original concern.

As it relates to the CSS config, I think a list, with TW at the top, is a fair compromise, even if I don't believe it to be the best solution and even encourages bad practices.

@ctjlewis
Copy link
Contributor

ctjlewis commented Mar 21, 2023

You guys are shooting the messenger and dragging the team for making a perfectly sensible change that they knew would be met with backlash.

It's unobtrusive. "Just Say No!"

In the meantime I think we agree having a multiselect for styles is best. A Radix option would also be smart.

PS: You would have been talking about how SSR was too opinionated four years ago.

@jonathandewitt-dev
Copy link

You guys are shooting the messenger and dragging the team for making a perfectly sensible change that they knew would be met with backlash.

I worry I'm being misunderstood if this is the impression. I keep saying I commend the PR author and the Next maintainers, I just come to them today with some honest concerns.

It's unobtrusive. "Just Say No!"

It's not about me, it's about setting standards that sway the industry. When such a powerful influence is controversial, it calls for some discourse.

@ctjlewis
Copy link
Contributor

ctjlewis commented Mar 21, 2023

They set a good standard here! This stack is used in most modern projects I see companies making.

That's why the ChatGPT example is useful: that's probably the most used web interface to ship in a while, and what does it run on?

They did the right thing and were hesitant to move on it, over a year since it was originally proposed, this was not some rash decision. It's good to guide projects toward this stack.

I think we both agree that this should get updated to support templates for Tailwind, CSS Modules, and probably Radix, with the question being "How would you like to manage your application styles?"

@jeffscottward
Copy link

You guys are shooting the messenger and dragging the team for making a perfectly sensible change that they knew would be met with backlash.

It's unobtrusive. "Just Say No!"

In the meantime I think we agree having a multiselect for styles is best. A Radix option would also be smart.

PS: You would have been talking about how SSR was too opinionated four years ago.

I was actually about to comment that ThemeUI is less opinionated and quite a bit more complete than Radix last time I used it but Vercel I believe uses Radix internally.

https://www.radix-ui.com/case-studies/vercel

Radix+Stitches let's you customize the shorthand rules which is super neat.
Chakra is much more Tailwind friendly/inspired.

shrugs As long as I can drop in generated SystemUI compliant theme configs I'm probably fine.

@jeffscottward
Copy link

They set a good standard here! This stack is used in most modern projects I see companies making.

That's why the ChatGPT example is useful: that's probably the most used web interface to ship in a while, and what does it run on?

They did the right thing and were hesitant to move on it, over a year since it was originally proposed, this was not some rash decision. It's good to guide projects toward this stack.

I think we both agree that this should get updated to support templates for Tailwind, CSS Modules, and probably Radix, with the question being "How would you like to manage your application styles?"

Also Styled components but yes to the list 👍
(Every single Figma to React generator assumes SC, to give you an idea of that market penetration hangover)

@jonathandewitt-dev
Copy link

They set a good standard here! This stack is used in most modern projects I see companies making.

That's why the ChatGPT example is useful: that's probably the most used web interface to ship in a while, and what does it run on?

They did the right thing and were hesitant to move on it, over a year since it was originally proposed, this was not some rash decision. It's good to guide projects toward this stack.

Yeah I mean, I guess we're at a stalemate here, because I would just end up repeating a lot of the case I made earlier.

#46927 (comment)

There's more to consider than just "who is using it? How many people are using it?" Particularly "Is there a consensus of quality? Is it good for the industry?"

@jeffscottward
Copy link

They set a good standard here! This stack is used in most modern projects I see companies making.

That's why the ChatGPT example is useful: that's probably the most used web interface to ship in a while, and what does it run on?

They did the right thing and were hesitant to move on it, over a year since it was originally proposed, this was not some rash decision. It's good to guide projects toward this stack.

Yeah I mean, I guess we're at a stalemate here, because I would just end up repeating a lot of the case I made earlier.

#46927 (comment)

There's more to consider than just "who is using it? How many people are using it?" Particularly "Is there a consensus of quality? Is it good for the industry?"

We have moved past this. Let's get to a point of implementation.
A list as stated above which includes

TailWind
Radix/Stitches
Styled Components
Css Modules
(Possibly more?)

@timneutkens can someone adjust that? New PR? I'm on vacation atm.

@jonathandewitt-dev
Copy link

jonathandewitt-dev commented Mar 22, 2023

We have moved past this.

A little more acknowledgment from the Next team would be nice. 😅 I don't want my points to be glossed over and dismissed too easily.

But I agree, we should keep the conversation productive at least.

Let's get to a point of implementation.
A list as stated above which includes

TailWind
Radix/Stitches
Styled Components
Css Modules
(Possibly more?)

I honestly wonder if we should have a different step for UI component libraries. I'd say maybe Stitches by itself and Radix in a different question.

I think Vanilla-Extract has a solid approach, but Astroturf might be even better because it removes that ➖ from the swappable category. Both have zero runtime though, so that's cool.

@ctjlewis
Copy link
Contributor

ctjlewis commented Mar 22, 2023

Someone should write the PR. The template logic is very simple: It consists of deps, devDeps, and some files - the files go in the given templates/* directory within CNA.

It will require another flag for people who want to use the CLI noninteractively, plus updating the prompts to add the multiselect. And then tests, but testing is a lot easier now.

If nobody else writes it, or the team doesn't pick it up, I'll do it in a few weeks.


Note for @leerob, @timneutkens: Ideally my original template logic would also get simplified soon, since it currently requires updates in 3 places to add a new template, and I expect templates will get added more regularly.

The move is probably to add CLI flags to the templates themselves, and register them programmatically in the CLI runtime. Just cloning examples instead is one way to bail out but it's not ideal for a lot of reasons.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 22, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants