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

[examples] Update styled-components to use SWC #34770

Merged
merged 11 commits into from Mar 2, 2022
5 changes: 3 additions & 2 deletions errors/react-hydration-error.md
Expand Up @@ -41,8 +41,9 @@ Common causes with css-in-js libraries:

- When using Styled Components / Emotion
- When css-in-js libraries are not set up for pre-rendering (SSR/SSG) it will often lead to a hydration mismatch. In general this means the application has to follow the Next.js example for the library. For example if `pages/_document` is missing and the Babel plugin is not added.
- Possible fix for Styled Components: https://github.com/vercel/next.js/tree/canary/examples/with-styled-components
- If you want to leverage Styled Components with the new Next.js Compiler in Next.js 12 there is an [experimental flag available](https://github.com/vercel/next.js/discussions/30174#discussion-3643870)
- Possible fix for Styled Components:
- If you want to leverage Styled Components with SWC in Next.js 12.1+ you need to [add it to your Next.js config under compiler options](https://nextjs.org/docs/advanced-features/compiler#styled-components): https://github.com/vercel/next.js/tree/canary/examples/with-styled-components
- If you want to use Styled Components with Babel, you need `pages/_document` and the Babel plugin: https://github.com/vercel/next.js/tree/canary/examples/with-styled-components-babel
- Possible fix for Emotion: https://github.com/vercel/next.js/tree/canary/examples/with-emotion
- When using other css-in-js libraries
- Similar to Styled Components / Emotion css-in-js libraries generally need configuration specified in their examples in the [examples directory](https://github.com/vercel/next.js/tree/canary/examples)
Expand Down
34 changes: 34 additions & 0 deletions examples/with-styled-components-babel/.gitignore
@@ -0,0 +1,34 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel
84 changes: 84 additions & 0 deletions examples/with-styled-components-babel/README.md
@@ -0,0 +1,84 @@
# Example app with styled-components using babel

This example features how you use a different styling solution than [styled-jsx](https://github.com/vercel/styled-jsx) that also supports universal styles. That means we can serve the required styles for the first render within the HTML and then load the rest in the client. In this case we are using [styled-components](https://github.com/styled-components/styled-components).

For this purpose we are extending the `<Document />` and injecting the server side rendered styles into the `<head>`, and also adding the `babel-plugin-styled-components` (which is required for server side rendering). Additionally we set up a global [theme](https://www.styled-components.com/docs/advanced#theming) for styled-components using NextJS custom [`<App>`](https://nextjs.org/docs/advanced-features/custom-app) component.

## Preview

Preview the example live on [StackBlitz](http://stackblitz.com/):

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-styled-components-babel)

## Deploy your own

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-styled-components-babel&project-name=with-styled-components-babel&repository-name=with-styled-components-babel)

## How to use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:

```bash
npx create-next-app --example with-styled-components-babel with-styled-components-babel-app
# or
yarn create next-app --example with-styled-components-babel with-styled-components-babel-app
```

Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

### Try it on CodeSandbox

[Open this example on CodeSandbox](https://codesandbox.io/s/github/vercel/next.js/tree/canary/examples/with-styled-components-babel)
leerob marked this conversation as resolved.
Show resolved Hide resolved

### Notes

When wrapping a [Link](https://nextjs.org/docs/api-reference/next/link) from `next/link` within a styled-component, the [as](https://styled-components.com/docs/api#as-polymorphic-prop) prop provided by `styled` will collide with the Link's `as` prop and cause styled-components to throw an `Invalid tag` error. To avoid this, you can either use the recommended [forwardedAs](https://styled-components.com/docs/api#forwardedas-prop) prop from styled-components or use a different named prop to pass to a `styled` Link.
leerob marked this conversation as resolved.
Show resolved Hide resolved

<details>
<summary>Click to expand workaround example</summary>
<br />

**components/StyledLink.js**

```javascript
import Link from 'next/link'
import styled from 'styled-components'

const StyledLink = ({ as, children, className, href }) => (
<Link href={href} as={as} passHref>
<a className={className}>{children}</a>
</Link>
)

export default styled(StyledLink)`
color: #0075e0;
text-decoration: none;
transition: all 0.2s ease-in-out;

&:hover {
color: #40a9ff;
}

&:focus {
color: #40a9ff;
outline: none;
border: 0;
}
`
```

**pages/index.js**

```javascript
import StyledLink from '../components/StyledLink'

export default () => (
<StyledLink href="/post/[pid]" forwardedAs="/post/abc">
First post
</StyledLink>
)
```

</details>
18 changes: 18 additions & 0 deletions examples/with-styled-components-babel/package.json
@@ -0,0 +1,18 @@
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-is": "^17.0.2",
"styled-components": "^5.2.3"
},
"devDependencies": {
"babel-plugin-styled-components": "^1.12.0"
}
}
26 changes: 26 additions & 0 deletions examples/with-styled-components-babel/pages/_app.js
@@ -0,0 +1,26 @@
import { createGlobalStyle, ThemeProvider } from 'styled-components'

const GlobalStyle = createGlobalStyle`
body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
`

const theme = {
colors: {
primary: '#0070f3',
},
}

export default function App({ Component, pageProps }) {
return (
<>
<GlobalStyle />
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
</>
)
}
10 changes: 10 additions & 0 deletions examples/with-styled-components-babel/pages/index.js
@@ -0,0 +1,10 @@
import styled from 'styled-components'

const Title = styled.h1`
font-size: 50px;
color: ${({ theme }) => theme.colors.primary};
`

export default function Home() {
return <Title>My page</Title>
}
4 changes: 3 additions & 1 deletion examples/with-styled-components/README.md
Expand Up @@ -2,7 +2,9 @@

This example features how you use a different styling solution than [styled-jsx](https://github.com/vercel/styled-jsx) that also supports universal styles. That means we can serve the required styles for the first render within the HTML and then load the rest in the client. In this case we are using [styled-components](https://github.com/styled-components/styled-components).

For this purpose we are extending the `<Document />` and injecting the server side rendered styles into the `<head>`, and also adding the `babel-plugin-styled-components` (which is required for server side rendering). Additionally we set up a global [theme](https://www.styled-components.com/docs/advanced#theming) for styled-components using NextJS custom [`<App>`](https://nextjs.org/docs/advanced-features/custom-app) component.
For this purpose we are using the [Next.js SWC compiler](https://nextjs.org/docs/advanced-features/compiler#styled-components).
leerob marked this conversation as resolved.
Show resolved Hide resolved

Currently, only the `ssr` and `displayName` transforms have been implemented. These two transforms are the main requirement for using `styled-components` in Next.js.

## Preview

Expand Down
10 changes: 10 additions & 0 deletions examples/with-styled-components/next.config.js
@@ -0,0 +1,10 @@
/** @type {import('next').NextConfig} */

const nextConfig = {
reactStrictMode: true,
compiler: {
styledComponents: true,
},
}

module.exports = nextConfig
3 changes: 0 additions & 3 deletions examples/with-styled-components/package.json
Expand Up @@ -11,8 +11,5 @@
"react-dom": "^17.0.2",
"react-is": "^17.0.2",
"styled-components": "^5.2.3"
},
"devDependencies": {
"babel-plugin-styled-components": "^1.12.0"
}
}
4 changes: 0 additions & 4 deletions examples/with-typescript-styled-components/.babelrc

This file was deleted.

10 changes: 10 additions & 0 deletions examples/with-typescript-styled-components/next.config.js
@@ -0,0 +1,10 @@
/** @type {import('next').NextConfig} */

const nextConfig = {
reactStrictMode: true,
compiler: {
styledComponents: true,
},
}

module.exports = nextConfig
3 changes: 1 addition & 2 deletions examples/with-typescript-styled-components/package.json
Expand Up @@ -17,7 +17,6 @@
"@types/react": "17.0.4",
"@types/react-dom": "17.0.3",
"@types/styled-components": "5.1.9",
"babel-plugin-styled-components": "^1.12.0",
"typescript": "4.2.4"
"typescript": "^4.5.5"
}
}
30 changes: 0 additions & 30 deletions examples/with-typescript-styled-components/pages/_document.tsx

This file was deleted.

@@ -1,5 +1,5 @@
import { runTests } from './utils'

describe('yarn PnP', () => {
runTests('with-styled-components')
runTests('with-styled-components-babel')
})