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

[NEXT-1308] Css is imported multiple times and out of order in /app dir #51030

Open
1 task done
ssijak opened this issue Jun 9, 2023 · 94 comments
Open
1 task done

[NEXT-1308] Css is imported multiple times and out of order in /app dir #51030

ssijak opened this issue Jun 9, 2023 · 94 comments
Assignees
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template. linear: next Confirmed issue that is tracked by the Next.js team.

Comments

@ssijak
Copy link

ssijak commented Jun 9, 2023

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.5.0: Mon Apr 24 20:52:24 PDT 2023; root:xnu-8796.121.2~5/RELEASE_ARM64_T6000
    Binaries:
      Node: 18.12.1
      npm: 8.19.2
      Yarn: 1.22.19
      pnpm: 7.18.1
    Relevant packages:
      next: 13.4.5-canary.9
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.1.3

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true)

Link to the code that reproduces this issue or a replay of the bug

https://github.com/ssijak/next-css-issue-not-working-simple

To Reproduce

Just start the app and check the styling on the buttons. Styles are imported multiple times wherever Button was used (page and layout) and order is also not deterministic, so it can be imported in different order on different app runs.

This is another/same simple repro difference is just that it uses turbo and transpiles the UI lib, I started with that but figured that the issue is happening without it too https://github.com/ssijak/next-css-issue-not-working

Describe the Bug

-Same styles are imported multiple times
-Order of imports is not deterministic

Screenshot: https://share.cleanshot.com/nq35j7vh

Expected Behavior

Same styles should be imported once. Starting the app multiple times should not produce different results (ordering of CSS, impacting specificity)

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

From SyncLinear.com | NEXT-1308

@ssijak ssijak added the bug Issue was opened via the bug report template. label Jun 9, 2023
@github-actions github-actions bot added the area: app App directory (appDir: true) label Jun 9, 2023
@ssijak
Copy link
Author

ssijak commented Jun 9, 2023

This PR #50406 seems like it should have fixed this issue, but I see the problem in my repro repositories

@ssijak
Copy link
Author

ssijak commented Jun 9, 2023

CSS modules seem to be working ok. Removed vanilla-extract from this repro, and imported the same CSS from CSS module in the page and layout, and set it on the <button>, and it imports the CSS once.

Edit: it works like that if both the page and layout are RSC. When I use use client directive on the page it imports the same CSS twice https://share.cleanshot.com/HjhMJhCy

@igordanchenko
Copy link

This issue is still present in the latest canary (13.4.7-canary.1)

  1. Same styles are imported multiple times
  2. The order of imports is not deterministic

Here is a minimal repro with easy-to-reproduce test cases.

https://codesandbox.io/p/sandbox/next-51030-hlj722?file=%2Fapp%2Fpage.tsx%3A1%2C1

@tinleym
Copy link

tinleym commented Jun 21, 2023

The current order of imports wreaks havoc when CSS Cascade Layers are being used. The defined layer precedence that belongs in the root layout file gets read after the application of layers in child components. This causes the defined layer precedence to be ignored in favor of something random (https://css-tricks.com/css-cascade-layers/#aa-establishing-a-layer-order), and can make routes unusable.

This issue surfaced for me when updating up from 13.4.4 to 13.4.5 or 13.4.6.

@ddoan
Copy link

ddoan commented Jun 22, 2023

One workaround I'm currently using is to make the children CSS more specific: button.button instead of .button or div.something instead of .something.

@shuding shuding added the linear: next Confirmed issue that is tracked by the Next.js team. label Jun 23, 2023
@shuding shuding self-assigned this Jun 23, 2023
@shuding shuding changed the title Css is imported multiple times and out of order in /app dir [NEXT-1308] Css is imported multiple times and out of order in /app dir Jun 23, 2023
@shuding
Copy link
Member

shuding commented Jun 23, 2023

For https://codesandbox.io/p/sandbox/next-51030-hlj722?file=%2Fapp%2Fpage.tsx%3A1%2C1, it becomes very tricky if your CSS code itself has conflicts and some behaviors are undefined. For example when a dynamic component has loaded, its CSS might cause side effects to other parts of the page, which is expected.

For example, if you have a layout like this:

import style1 from 'a.module.css'
import style2 from 'b.module.css'

<button className={style1.btn + ' ' + style2.btn}>

The styles that imports later will override previous ones, so b.module.css will take precedence. However, if we have a page component that imports a.module.css again, it will take precedence over b.module.css again because page's styles have higher priority than the layout's. This is also a cause of duplicated styles.

In general, we recommend you to use CSS @layer, or try to make CSS selectors as pure and specific as possible.

@igordanchenko
Copy link

@shuding, I appreciate you taking the time to look into this example.

it becomes very tricky if your CSS code itself has conflicts and some behaviors are undefined.

I wouldn't call styles override a conflict. Overriding base component styles in a descendant component is a pretty common technique. Isn't that what "C" in CSS stands for?

For example when a dynamic component has loaded, its CSS might cause side effects to other parts of the page, which is expected.

The above example is a module-scoped CSS that doesn't have any global side-effects.

The styles that imports later will override previous ones, so b.module.css will take precedence.

Yes, you are absolutely correct, and that's the desired behavior that we are unfortunately not able to achieve under the app router.

However, if we have a page component that imports a.module.css again, it will take precedence over b.module.css again because page's styles have higher priority than the layout's. This is also a cause of duplicated styles.

In theory, yes. But it's not the case in the above example, isn't it?

@tinleym
Copy link

tinleym commented Jun 24, 2023

@shuding if you'll please read my comment below, @layer is not working.

The indeterministic order of imports wreaks havoc when CSS Cascade Layers are being used. The defined layer precedence that belongs in the root layout file gets read after the application of layers in child components. This causes the defined layer precedence to be ignored in favor of something random (https://css-tricks.com/css-cascade-layers/#aa-establishing-a-layer-order), and can make routes unusable.

This issue surfaced for me when updating up from 13.4.4 to 13.4.5 or 13.4.6.

@shuding
Copy link
Member

shuding commented Jun 24, 2023

Thanks! I'll go through all the reproductions and think about an improvement in the next couple of days!

I understand that the confusion caused by the new architecture. In general scoped CSS itself doesn't have conflicts, but the order and duplication might cause the styles to conflict (override each other). I'll give you an example:

layout: → layout.css
page: → page.css

If the module that contains the .btn class is imported lastly, it will override the styles defined in .base. If only layout is rendered, that's the expected behavior.

However when page is rendered, page.css will be loaded and it has only .base. This CSS file will occur after layout.css and override the .btn styles in that file.

Previously in the pages directory, all styles will be packed into one CSS file. But here we need to generate one CSS per layout and page because they can be loaded separately.

That said, we still have some ideas to improve it. Like changing the CSS modules hashing algorithm to make it base on the layer, or deduplicate styles that are already in its parent layer. Will keep you updated in this issue.

@boatilus
Copy link

That said, we still have some ideas to improve it. Like changing the CSS modules hashing algorithm to make it base on the layer, or deduplicate styles that are already in its parent layer.

If I understand the latter suggestion correctly, this seems to me like the right approach. If a build system produces hashed rule/class names based on the rule contents (e.g., ._129ac00b) in layout.css, it'd be unnecessary to duplicate that rule in page.css, and that duplication causes the unexpected precedence fighting. The basic idea here would be if (selector in layout.css) strip from page.css. Although I say that with that big caveat that I don't know the implications when overriding a rule generated in page.css that's intentional and how to signify that.

To your point, if there's perfect purity, this won't be a problem, but it's also reasonably unrealistic that there wouldn't be things like rules applied to descendent selectors (and probably some non-negigible number of other scenarios) on class names that have a high likelihood of their precedence being trumped by the same properties in a rule duplicated in page.css.

@sleepdotexe
Copy link
Contributor

sleepdotexe commented Jul 18, 2023

I'm also encountering the same behaviour.

For my use case, I'm creating standard UI/layout components that I want to use across multiple pages and components – these components have *.module.css styles. This allows me to add default custom stylings to these UI components and only load them if the component is used on the page. I also allow an additional className to be added for additional styling at a per-component level.

The problem is, as mentioned above, changing between routes/different app runs can result in different CSS load orders in addition to a huge amount of duplicate CSS.

For example:

// components/layout/Section.tsx

import styles from '../../styles/layout/Section.module.css';

interface Props extends React.ComponentProps<'section'> {
	fullWidth?: boolean;
}

export default function Section(props: Props) {
	const { fullWidth, ...remainingProps } = props;
	return (
		<section
			{...remainingProps}
			className={[styles['section'], props.className].join(' ')}
			data-fullwidth={fullWidth}
		>
			{props.children}
		</section>
	);
}

Navigating from Page A, to Page B, back to Page A cause Page A to display differently the second time round. Refreshing manually causes Page A to revert to its original layout.

For now, as a partial fix, I have managed to use css @layer to lower the CSS specificity of all the UI components' styles, however it still results in large amounts of duplicate css being added to each page, especially if the UI component is used frequently (such as a custom button).

Would be interested to know if there is a better way to go about this. I can provide more detailed examples/reproductions if necessary.

@jep-a
Copy link

jep-a commented Jul 21, 2023

@tinleym

The current order of imports wreaks havoc when CSS Cascade Layers are being used. The defined layer precedence that belongs in the root layout file gets read after the application of layers in child components. This causes the defined layer precedence to be ignored in favor of something random (https://css-tricks.com/css-cascade-layers/#aa-establishing-a-layer-order), and can make routes unusable.

This issue surfaced for me when updating up from 13.4.4 to 13.4.5 or 13.4.6.

Have a quick hack fix for the css layer order here #16630 (comment)

LeonardYam added a commit to LeonardYam/personal-portfolio that referenced this issue Aug 9, 2023
This reverts commit af98261.

Currently, importing 'normalize.css' is causing inconsistent styles (see: vercel/next.js#51030)
@katiasmet-93
Copy link

Is there already a solution for css that is loaded multiple times if you use the "use client" mode?
I use css modules and have f.e. several buttons or inputs on 1 page. The css (modules) are loaded multiple times in version 13.4.19.

@monolithed
Copy link

Is there a way to consolidate all styles into one file, so that the minifier automatically removes duplicates? I can't estimate the scale of the issue in kilobytes, but I see that each of my components (a total of 31) duplicates styles three times, and this is in production.

Screenshot 2023-09-05 at 01 37 57

@boatilus
Copy link

boatilus commented Sep 5, 2023

I just ended up writing a simple Webpack plugin that removes duplicate rules by their class names (which isn't a good idea in pratice, but has worked well enough for my needs). I've only tested this with CSS generated with Vanilla Extract, and it doesn't support route groups, but someone may find it useful.

@Stillonov
Copy link

Stillonov commented Sep 7, 2023

I have the same problems and it's awful. My app is very fragile.
It happens when I navigate through pages containing common components.

Screenshot 2023-09-08 at 01 24 15

@katiasmet-93
Copy link

Maybe not the best solution for now, but converting to the pages router fixed it for me.

@monolithed
Copy link

monolithed commented Sep 8, 2023

Maybe not the best solution for now, but converting to the pages router fixed it for me.

@katiasmet-93, your solution might be suitable for projects with a small codebase where there's no need for testing investments. But such thoughts really make one reconsider completely dropping Next.

@nikita2090
Copy link

I have the same problem when using shared components in layouts and pages (next 13.4.19). It doesn't work correctly both when using CSS modules and when using tailwind.

@olalonde
Copy link

Same issue with mantine #16630 (comment)

@mysticflute
Copy link

mysticflute commented Apr 30, 2024

I updated to the latest and am still seeing this issue. Whenever the layout file uses a component that has use client, all of the global css imported in the layout is ordered randomly, instead of in the order specified in the layout file. Happens in both dev and prod.

@brianmorin-ef
Copy link

To help with this issue, we're inserting our layer order onto every css file so the import order won't affect layer via next config and the BannerPlugin:

import webpack from "webpack";

const nextConfig = {
    webpack: (config) => {
        config.plugins.push(
            new webpack.BannerPlugin({
                banner: '@layer reset, ui, components;',
                test: /\.css$/,
                raw: true,
                entryOnly: false,
            })
        );

        return config;
    },

@terrymun
Copy link

terrymun commented May 1, 2024

I also read up about using :where() selector (that has zero specificity) as a possible alternative to using CSS layers, especially when working with component libraries that you have control over, but I haven't tested that out at the time of writing.

@kliatskiidenis
Copy link

I also have problems with duplicating styles when using scss modules. After making the build, the styles are still duplicated, I don't know what to do, because how will all this behave when the site is in production.
Please let me know if this problem will be solved and if it affects the css size?
Знімок екрана 2024-05-02 о 14 11 36

@codeaid
Copy link

codeaid commented May 3, 2024

I just spotted an issue where the order of my global imports is screwed up as soon as I use Link in one of my components instead of a, which doesn't make any sense.

I have the following two lines in my main layout:

import 'normalize.css';
import './global.css';

The latter file overrides some of the heading styles and this is what I get without using Link:

image

and after I switch the a usage to Link:

image

eduardoformiga added a commit to vtex/faststore that referenced this issue May 6, 2024
## What's the purpose of this pull request?

This PR aims to: 

- [x] add the tsconfig needed to run Next 13. It also set
`"strictNullChecks": false` to make the Section Override v2 API work as
previously.
- [x] Fix styles order problem by adding webpack config in
next.config.js. See
vercel/next.js#51030 (comment)
- [x] adds the initial prefix folder, root layout and initial page
layout

## How to test it?

run locally and you should see the initial structure under:
http://localhost:3000/fs-next-update

### Starters Deploy Preview

<!--- Add a link to a deploy preview from `gatsby.store` AND
`nextjs.store` with this branch being used. --->

<!--- Tip: You can get an installable version of this branch from the
CodeSandbox generated when this PR is created. --->

## References

Next 13 file conventions
https://nextjs.org/docs/app/api-reference/file-conventions/layout

CSS order issues:

[[NEXT-1308] Css is imported multiple times and out of order in /app dir
· Issue #51030 ·
vercel/next.js](vercel/next.js#51030 (comment))
[Verify CSS import ordering · Issue #16630 ·
vercel/next.js](vercel/next.js#16630)
[CSS "@import <file> layer()" isn't working · Issue #55763 ·
vercel/next.js](vercel/next.js#55763)
[[NEXT-1308] Css is imported multiple times and out of order in /app dir
· Issue #51030 ·
vercel/next.js](vercel/next.js#51030 (comment))

strictNullChecks
vercel/next.js#39942
https://www.typescriptlang.org/tsconfig/#strictNullChecks
@Netail
Copy link
Contributor

Netail commented May 10, 2024

I was struggling with this issue as well, and found a solution where all css is in one single file. While it might not be optimal, at least the styles are applied correct. This is what I added to the webpack config in the next config

config.optimization = {
      ...config.optimization,
      splitChunks: {
        cacheGroups: {
          styles: {
            name: "styles",
            type: "css/mini-extract",
            chunks: "all",
            enforce: true,
          },
        },
      },
    };

Does not seem to work great; when switching between pages, it's missing styles from the css bundle. Only once the page has been rendered at least once, it will be in the bundle

@samcx
Copy link
Member

samcx commented Jun 4, 2024

Hi everyone!

We landed some fixes with v15.0.0-canary.10.

Taking a look at some :repro:s now if I can still replicate CSS issues!

@Netail
Copy link
Contributor

Netail commented Jun 4, 2024

Hi @samcx ,
I've tested the canary version right after publishing, but it seems like my issue with the following test setup; https://github.com/Netail/app-dir-css-order is still facing duplicate css / incorrect css order :(

@samcx
Copy link
Member

samcx commented Jun 4, 2024

@Netail Yeah can confirm we're still seeing issues—I've already let the team know and we're digging (:dig-deeper:) :frog-thumbsup:

@Netail
Copy link
Contributor

Netail commented Jun 12, 2024

@samcx do you happen to know if it's possible to fallback on non-streaming CSS (the original way) for now? Where it would send a single CSS file per path

@samcx
Copy link
Member

samcx commented Jun 12, 2024

@Netail Not 100% sure if this will help you, but you can try this in your next.config.js. →

experimental: {
  cssChunking: 'strict',
}

x-ref: #63157

@Netail
Copy link
Contributor

Netail commented Jun 12, 2024

@samcx Sadly not, feels like it makes it even worse if I look at the css order. So basically a server component uses a certain component styling, with some overwriting, these get added to the bundle. Then a client component renders which also uses the component styling, so this styling then gets added at the bottom (while it was already in the bundle), thus overwriting the overwrited component styling to the original styling.

But was more looking for a fallback solution (till this get sorted) where it would bundle the full page css in 1 css file, like the old school days. It ofc creates a bigger payload, but at least fixes the issue for now

Maybe I have some time tomorrow to help create some test cases in here, which can help you guys when fixing the issue?

eduardoformiga added a commit to vtex/faststore that referenced this issue Jun 13, 2024
This PR aims to:

- [x] add the tsconfig needed to run Next 13. It also set
`"strictNullChecks": false` to make the Section Override v2 API work as
previously.
- [x] Fix styles order problem by adding webpack config in
next.config.js. See
vercel/next.js#51030 (comment)
- [x] adds the initial prefix folder, root layout and initial page
layout

run locally and you should see the initial structure under:
http://localhost:3000/fs-next-update

<!--- Add a link to a deploy preview from `gatsby.store` AND
`nextjs.store` with this branch being used. --->

<!--- Tip: You can get an installable version of this branch from the
CodeSandbox generated when this PR is created. --->

Next 13 file conventions
https://nextjs.org/docs/app/api-reference/file-conventions/layout

CSS order issues:

[[NEXT-1308] Css is imported multiple times and out of order in /app dir
· Issue #51030 ·
vercel/next.js](vercel/next.js#51030 (comment))
[Verify CSS import ordering · Issue #16630 ·
vercel/next.js](vercel/next.js#16630)
[CSS "@import <file> layer()" isn't working · Issue #55763 ·
vercel/next.js](vercel/next.js#55763)
[[NEXT-1308] Css is imported multiple times and out of order in /app dir
· Issue #51030 ·
vercel/next.js](vercel/next.js#51030 (comment))

strictNullChecks
vercel/next.js#39942
https://www.typescriptlang.org/tsconfig/#strictNullChecks
@Netail
Copy link
Contributor

Netail commented Jun 14, 2024

Tried to make a test case in the next.js repo for my issue in, but wasn't able to reproduce it in there as tests first build a production build before the test are ran? My issue only applies to development mode

@Netail
Copy link
Contributor

Netail commented Jun 24, 2024

Hi @samcx, I was wondering if there was any progress made internally the past 2 weeks 😅
And wondering if #66500 will be backported into v14

@joshunger
Copy link

joshunger commented Jun 25, 2024

@samcx Thank you! When does cssChunking come out of experimental and get documentation around when to use it? EDIT: found this ...

   * CSS Chunking strategy. Defaults to 'loose', which guesses dependencies
   * between CSS files to keep ordering of them.
   * An alternative is 'strict', which will try to keep correct ordering as
   * much as possible, even when this leads to many requests.

@kotAPI
Copy link

kotAPI commented Jun 27, 2024

I am a maintainer on an open-source UI library, here's the docs website that runs on next 14 and is having this issue that's been discussed since over a year, we've no idea how to fix this

https://github.com/rad-ui/website

@Netail
Copy link
Contributor

Netail commented Jun 27, 2024

I am a maintainer on an open-source UI library, here's the docs website that runs on next 14 and is having this issue that's been discussed since over a year, we've no idea how to fix this

https://github.com/rad-ui/website

Yeah this issue has been going on since v13 (2 major versions) already :(

@ssijak
Copy link
Author

ssijak commented Jun 27, 2024

I don't understand how this issue is not prioritised. It breaks so many projects in unpredictable ways, basically everything that does not import one CSS file like Tailwind.

@kutsan
Copy link

kutsan commented Jun 27, 2024

Sorry to ping everyone, but @shuding, @leerob, @samcx do you have any updates on this? It is affecting a lot of projects, and I also have questions about why it still hasn't been resolved.

@khanakia
Copy link

I have import styles from './Spinner.module.scss' and this CSS is loading two times like this

These both files contains the same spinner code I just can't figure why is it like this

layout.css
page.css

@samcx
Copy link
Member

samcx commented Jul 1, 2024

@kutsan The team was recently had an offsite, and then I was PTO for a week—we're back to tackling this issue! Sorry for the lack of an update.

I don't understand how this issue is not prioritised. It breaks so many projects in unpredictable ways, basically everything that does not import one CSS file like Tailwind.

We are indeed prioritizing this!

@terrymun
Copy link

terrymun commented Jul 1, 2024

A report back from the last time I commented: I am working on a greenfield project and therefore has the ability to put in some mandates early on, and it seems that implementing CSS @layer resolve 99% of the issues we experienced.

This still only fixes the symptoms of having duplicate CSS being loaded, but now that all our components have mandatory @layer at-rule requirement (enforced with an in-house stylelint rule), we no longer experience issues with styles overriding each other.

Our next.js config looks like this:

/**
 * @type {import('@nx/next/plugins/with-nx').WithNxOptions}
 */
const nextConfig = {
  ...restOfTheConfig,
  webpack: (config) => {
    config.plugins = [
      ...(config.plugins ?? []),
      new webpack.BannerPlugin({
        banner: `@layer ${CSS_LAYER_NAMES.join(', ')};`,
        test: /\.s?css$/,
        raw: true,
        entryOnly: false,
      }),
    ];

    return config;
  },
};

And CSS_LAYER_NAME is simply an array of CSS layers we have defined somewhere in a constant, as it is shared by our developer tooling and docs generation, but it looks like this:

export const CSS_LAYER_NAMES = [
  'reset',
  'headless',
  'design-system',
  'component',
  'app'
] as const;

Our CSS reset looks like this:

@layer reset {
  *, *::before, *::after {
    box-sizing: border-box;
  }
}

And our *.module.scss files are may look like one of the following depending on what they are used for:

@layer design-system { ... }

/* Used by components built on top of design system */
@layer component { ... }

/* Used by page/layout.tsx as a top-level override */
@layer app { ... }

@MONTYYYYY
Copy link

@Netail Not 100% sure if this will help you, but you can try this in your next.config.js. →

experimental: {
  cssChunking: 'strict',
}

x-ref: #63157

This worked for me !!! Many thanks!

@samcx
Copy link
Member

samcx commented Jul 2, 2024

Ok back with a report!

import * as React from "react";
import "./global.css"; // switched this to be above the Component, so the global css comes first
import { Component } from "./Component";

export default function Layout(props: React.PropsWithChildren) {
  return (
    <html lang="en">
      <body>
        {props.children}
        <Component />
      </body>
    </html>
  );
}

This :pr: #67373 is going to land as well, which fixes #64773. This may fix some of the other :repro: I may have missed.

So far, I think the pressing issues that are actively known with confirmed :repro:s are:

  1. Server ↔ Client components are not respecting CSS import order
  2. CSS is leaking between Layouts in Route Groups (getting :fixed: by avoid merging global css in a way that leaks into other chunk groups #67373). Not 100% sure if avoiding merging the global.css will fix other issues, but will be taking a look!

@Netail
Copy link
Contributor

Netail commented Jul 2, 2024

(I believe this is what you're referring to)

Yes :) Might be related to one of the other reported issues tho, but not 100% sure

@kotAPI
Copy link

kotAPI commented Jul 3, 2024

cssChunking: 'strict',

On Next 14 🫠

Invalid next.config.js options detected: 
 ⚠     Unrecognized key(s) in object: 'cssChunking' at "experimental"

@klonwar
Copy link

klonwar commented Jul 3, 2024

For the longest time, I didn't realize (my bad) that the import order matters for CSS. So there was no issue with this :repro:. Just switch the global.css file up.

@samcx Man, you're my hero, thank you! Eslint simple-import-sort plugin screwed me over 🥲 Disabled it in layout.tsx with // eslint-disable-next-line simple-import-sort/imports

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template. linear: next Confirmed issue that is tracked by the Next.js team.
Projects
None yet
Development

No branches or pull requests