styled-components: createGlobalStyle creates memory leak in Next.js
Environment
Binaries:
- Node: 13.7.0 - ~/.nvm/versions/node/v13.7.0/bin/node
- Yarn: 1.21.1 - /usr/local/bin/yarn
- npm: 6.13.6 - ~/.nvm/versions/node/v13.7.0/bin/npm
npmPackages:
- babel-plugin-styled-components: ^1.10.7 => 1.10.6
- styled-components: ^5.0.1 => 5.0.1
Problem
We are using styled-components and Next.js (7.2.1) and we have experienced memory leaks in our app for some time, so I started to investigate it, in the process I found other issues here about:
- using the css helper when composing styling partials to be interpolated into a styled component
- not to use
@import
insidecreateGlobalStyle
- not dynamically create components
So I went through the whole app making sure to avoid these. I deployed a new version but the memory leak was still present. As seen on the graph below:
After inspecting the node server I found out it was createGlobalStyle
in our _app.js
(Next.js file) that caused the memory to rise. In the createGlobalStyle
we used fontFace
/normalize
from polished), and around 50 other lines of reset css (nothing special).
Removing createGlobalStyle
solved the memory leak (or at least reduced to a minimum).
See the graph below:
Did we use createGlobalStyle
wrong or do someone have some insight to this?
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 32
- Comments: 43 (9 by maintainers)
So I’m giving up on properly solving this issue, I can’t figure out how to pass context in my particular case with
getDataFromTree(<Tree />, ctx)
, because I’m not sure where to even take it. But issue is definitely as I described here. I still wonder why masterSheet exists, because it’s singleton which is never cleaned up, at least from my understanding.Nevertheless I have found a workaround to mitigate this issue:
Just wrapping it with
StyleManager
will make it use newStyleSheet
every time. Not sure if there will be any harmful side effects here.@probablyup, the issue is still there 😦
Packages versions: “styled-components”: “^5.0.1” “next”: “9.2.2”
One of our global styles:
Memory usage with
createGlobalStyle
^^:Memory usage without
createGlobalStyle
:For sure we have some other small memory leaks, but
createGlobalStyle
produces the biggest one. This is how our memory usage looks usingcreateGlobalStyle
:Constructor:
#__next{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;height:100vh;/*\|*/}
:The object referred to the constructor ^^:
As you can see the memory is being actively spammed on each page render by CSS string produced by
createGlobalStyle
output. This is a huge issue. Possible solutions:import '../global.css'
createGlobalStyle
ASAPThis is not related to Next.js. We’re experiencing the same problems with a custom built React SSR implementation. Downgrading to version 4 solved the issue.
Seeing the same picture in my debugger as https://github.com/styled-components/styled-components/issues/3022#issuecomment-612628550
Has anyone been able to resolve this?
I wonder if the issue is specifically with Next.js rather than styled-components. For example would any large string located in
_app.js
cause a memory leak?We were also forced to downgrade to 4.4.3. This is our memory consumption before and after styled-components v5, I am sure you can pinpoint the points where the version changed 😃).
Yes we are having the same issue in our Next app as well. Only difference is that we are using latest Next version.
I’m not common with the code base, but investigating it further led to Sheet.js, this particular line:
New style sheets are allocated later with this unique number in
const styleSheet = useStyleSheet();
, polluting thenames
map entry:Why this happening and what is the reasoning behind incrementing in
allocateGSInstance
I don’t know. Will investigate further, but it would be great if someone with better styled-components project knowledge could take a look at it.Just a string in style tag, put in head:
Using Typescript, so had to cast an any type to use this component as before
UPD: One can also use just a .css file (in case of Next, which supports them out of the box), but we have variables there, so was not an option in my case.
We are running StoryShots over our 2000+ stories and after upgrading to Styled Components v5 our tests are timing out. I’ve been able to bring down the test time drastically by stripping our global styles (with
createGlobalStyle
) down to just a few simple css rules. At one point adding a single rule on an element selector increased test time from 12 minutes to 17 minutes. Adding more increased it to 55 minutes, and that wasn’t even our complete set of global styles. Before upgrading, our tests took only 3 minutes or so, with the complete set of global styles from@storybook/design-system
.@Oikio that’s fine to do, it’s essentially what
sheet.collectStyles
does anywayAllocation always increments id here:
But previous id for
createGlobalStyle
is never cleared, here is the flow of therenderStyles
:At least it looks like the issue. I’m not sure where to fix it. Why does
allocateGSInstance
increments numerical part of id, isn’t id hash unique? Where shouldremoveStyles()
be called for previous allocated styles?Still not much progress in finding our why
this.names
field is reused, though ServerStylesheet is recreated on every request. We are using integration from examples of Next.js:It looks pretty straightforward and I wanted to blame Next.js first, until I saw that version 4 was fine and also there is a comment from peeter-tomberg above, having same issue with non Next.js project. Will continue to investigate, help appreciated.
BTW, @peeter-tomberg if you can share how styled-components are integrated in your app without Next, it would great for invsetigating the issue.
We ran into a similar issue where stylis
trim
function was causing a mem leak. Downgrading to 4.4.0, validating on server.EDIT: Confirmed.
EDIT 2: retracting confirmed, the memory is still rising on our server, but slightly slower.
EDIT 3: A heap snapshot:
EDIT 4: mistook the last one, it was still on SC 5.0 due to one of our component libraries.
This is the memory snapshot from 4.4.0:
Yep works fine when deployed: