twin.macro: Using Next 13's app directory with `withTwin` setup causing `"use client"` to be removed
I’m currently migrating a Next 13 project from the /pages
directory setup to the new /app
directory. As part of that it defaults to components being server components, and you must specify "use client"
at the top of a file to make it a client side component.
As @ben-rogerson helpfully pointed out (🙏), there’s a guide on how to use styled-components
with this new setup, requiring a /lib/registry.ts
file.
I got that working in another project (using the /pages
directory), but when using with the /app
setup the initial "use client"
line is stripped out by the build process.
To try to get to the bottom of it I’ve created a fresh next 13 install using yarn create next-app --typescript
as detailed here.
Then I went about following the guidance of integrating withTwin
to allow for both SWC and webpack to run side by side, as shown here.
Unfortunately I’m still seeing the build process remove the "use client"
line, producing this error:
./src/lib/registry.tsx
ReactServerComponentsError:
You're importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
,-[/Users/fredrivett/code/FR/next-13-use-client-issue/src/lib/registry.tsx:1:1]
1 | import { jsxDEV as _jsxDEV, Fragment as _Fragment } from "react/jsx-dev-runtime";
2 | import React, { useState } from "react";
: ^^^^^^^^
3 | import { useServerInsertedHTML } from "next/navigation";
4 | import { ServerStyleSheet, StyleSheetManager } from "styled-components";
5 | export default function StyledComponentsRegistry({ children }) {
`----
Maybe one of these should be marked as a client entry with "use client":
src/lib/registry.tsx
src/app/layout.tsx
I’m unsure how to get around this, as this is quite a minimal setup. I’m sure it’s a simple config issue but I’m unsure which setting to tweak. With this being reproduced in a pretty vanilla project I thought this might also trip up others, and so an issue here benefit them too.
👉 The project reproducing this issue can be found here: https://github.com/fredrivett/next-13-use-client-issue
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 2
- Comments: 22 (6 by maintainers)
Commits related to this issue
- Add improved configuration See https://github.com/ben-rogerson/twin.macro/issues/788#issuecomment-1909385071 for more info — committed to ben-rogerson/twin.examples by ben-rogerson 5 months ago
Hey Fred
Without having quite gotten to the bottom of this, I thought I’d share my findings anyway as someone may be able to help pick this up and find a full solution.
I found there’s a setting in the
withTwin.js
file that’s causing the error.In the defaultLoaders the
hasServerComponents
option is causing the error:Right now I’m unsure why
hasServerComponents: true
causes theuse client;
directive to be stripped, but I was able to patch the loader like this:I’m not sure of the implications of this but the repo you posted now builds and can be served.
No worries, yeah keep us in the loop on this if you can. I’m keen to keep this open as the
app
directory feature looks to be where next is heading. 🤞 the patch is a good fix - it may be possible to even removeoptions.defaultLoaders.babel
from the array altogether without issues.I believe I’ve fixed the error for Next.js 14. Furthermore,
twin.macro
now works with server components!Note that I am using ESM. My
withTwin.mjs
:@ben-rogerson Any ideas to work on nextjs 14?
Patched using the above. Not sure what
hasReactRefresh
does, but it seems hot reload still works.This is ace, thanks so much for investigating this and your work in general here @ben-rogerson, it’s much appreciated.
I can confirm that fix also works in my actual project where I first bumped into this issue.
It’s an odd one, I’ve had a quick search myself and couldn’t see anything else mentioning this or anything similar, so may be one that’s best to be left open until the root explanation is found? Up to you.
If anything strange comes up due to this I’ll report back.
Thanks again.
@macalinao Huge thanks for your work with the improved/fixed config 🎉 . I’ve verified it’s working too and I’ve updated the following next examples with the improvements:
styled-components / styled-components (ts) / emotion / emotion (ts) / stitches (ts)
To add to the notes above:
babel-plugin-styled-components
for jsx syntax support..mjs
for the next.config and withTwin files only to avoid therequire
imports. You’re still able to use.js
versions of these files, just switch back to therequire
imports.babel-plugin-twin
innext.config.mjs
but kept it commented out - this should make it easier to setup if needed.Closing this thread as I think we’ve finally found a good solution.
Sorry for re-openning this but none of the examples work with server components. Even your example uses
"use client"
everywhere.@rdgr I’ve updated the next-emotion-typescript example to use the app dir + emotion latest. We need to use the jsx pragma at the moment - here are my findings.
I’ve updated the twin examples with the fix mentioned above and moved all of them to use the app directory - no issues so far.
@ben-rogerson I think the next and t3app examples need to be updated also
Agreed. The example work in “client component” file (with “use client”). But when use tw`` in “server component”, it still got the same error " createContext only works in Client Components. Add the “use client” directive at the top of the file to use it."
Thank you for continuing to research the issue and updating the example project for next.js 14!
However, it seems that errors similar to the above continuously occur in the example project of next.js 14.
I tried to reproduce the error by creating a simple counter page project using useState on the example project(next-emotion-typescript).
If you are interested, please take a look and help those who are experiencing the same error🥹
Thanks for the response. I also faced a similar issue as faced by @rdgr as I degit the next-styled-components template yesterday. It worked fine all along, till I created a layout file for a route group. I had to add “use client” to the top of the page.tsx and layout.tsx files for the error to go away. But it doens’t feel right. Am I supposed to “use client” on each page.tsx and layout.tsx that is has components styled with tw and css?
Thanks for the amazing work on this project though ❤️
@ben-rogerson I degit the
next-emotion-typescript
sample but I’m having an error on the first run ofnpm run dev
.On the other hand,
next-styled-components-typescript
works. It seems this is a known limitation from emotion, whose appDir support isn’t ready yet.