preact: Lazy loading styled-components component triggers warning message incorrectly

Reproduction

https://github.com/TLadd/preact-styled-components-lazy-load-warning. The relevant files are

preact@10.4.4

Steps to reproduce

Load the app and observe the following warning message is printed:

The component styled.div with the id of “sc-AxjAm” has been created dynamically. You may see this warning because you’ve called styled inside another component. To resolve this only create new StyledComponents outside of any render method and function component.

This warning occurs only when lazy loading a styled component or lazy loading something that renders a styled component with preact. The warning message is not printed if a dynamic import is not used or if using React instead of preact.

Looking at styled-components, it’s triggering this warning message if calling useRef doesn’t throw when declaring the component.

Expected Behavior

The warning message should not be printed.

Actual Behavior

The warning message is printed.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Comments: 27 (13 by maintainers)

Most upvoted comments

Hiya 👋

I’ve put in the warning and it triggers when we a hook doesn’t throw during StyledComponent creation. I’m not sure what context this permissiv behaviour happens in, but it does seem like a tiny issue in preact/compat to me as during the time of import we shouldn’t be inside any component context; that being said it’s safe to ignore.

The reason why I’ve proposed the change and we’ve added it is that this is still a common mistake when styled-components are used. We get a lot of issues that relate to dynamically created components: unexpected edge cases that are usually impossible, memory leaks on the client-side and in SSR, out of memory errors, rerender bugs triggered by this, etc.

After having seen probably hundreds of these issues and comments, it’s clear that once people create more than a thousand components, telling them to track down the few cases where they’re dynamically created (and explaining this to beginners) is a daunting ask.

Hence this warning was introduced to rule this mistake out entirely, which has mostly eliminated this category of issues entirely 😅

@heymartinadams that “total hack” how you call it seems a bit off to me. Adding the react-refresh runtime manually doesn’t feel right. @JoviDeCroock spent quite some time to create prefresh - the react-refresh alternative for preact. It even features a next.js plugin (https://github.com/JoviDeCroock/prefresh/tree/main/packages/next).

As @developit mentioned I maintain a next.js plugin that will take care of the aliasing of react to preact and also includes prefresh: https://github.com/sventschui/next-plugin-preact . I guess this plugin would be your best bet for a stable setup. If you experience any issues with that and styled-components it would be helpful if you could share a small reproduction project where we could take a closer look.

@marvinhagemeister After having installed the last version of preact-render-to-string with your fix, the errors have disappeared for both my small reproduction example and our larger codebase where we use preact with next in the real world. 🎉 🎉 🎉

Thanks again for looking into this.

@heymartinadams ~that seems like a React error, not a Preact error.~ You’re likely missing preact/debug. Here’s how to enable it in Next.js: https://github.com/developit/nextjs-preact-demo/blob/77f928b754910f8d44687a3a6eb38c3e08f646c3/next.config.js#L33-L40

There’s also a plugin that does all this automatically, which we’re likely going to be marking as an official Preact project: https://github.com/sventschui/next-plugin-preact

@marvinhagemeister okay that’s very interesting. I just tried also to completely delete the node_modules folder, reinstall with both npm and yarn, but i keep getting the error, especially when navigating between the /about route and the home route. This never happens the first time a page is loaded, but usually the second time,after i refresh the page. I’ve also completely cleared the local .next folder to ensure that this isn’t some cache related issue as well…

I’ll try to investigate some more and ask some of my colleagues next week to try this out on their machines as well, to rule out that there is something fishy going on with my system.

EDIT: Also to clarify those errors are occurring during SSR on the server, so look out for them in the terminal that’s running the dev server, not on the client. (see below)

terminal

@tbgse did the following:

next.config.js

const withPlugins = require('next-compose-plugins')
const withPreact = require('next-plugin-preact')

module.exports = withPlugins(
  [withPreact, /* other plugins */, {/* Your NextJS config */}]
)

package.json

{
  "dependencies": {
    "next-compose-plugins": "^2.2.0",
    "next-plugin-preact": "^3.0.2",
    "preact": "^10.5.5",
    "preact-render-to-string": "^5.1.11",
    "react": "npm:@preact/compat",
    "react-dom": "npm:@preact/compat",
    "react-ssr-prepass": "npm:preact-ssr-prepass@^1.0.1",
  }
}

@heymartinadams the next-plugin-preact already includes prefresh/next and thus you do not have to add it manually.

Ok, I think I got to the bottom of this. We correctly throw an error when preact/debug is present. Without any preact/debug imports we won’t display any messages or errors only intended for debugging purposes.

This issue can be resolved by adding import "preact/debug" at the top of the main entry file.

import "preact/debug"; // <-- This enables debugging warnings/errors
import React from "react";
import ReactDOM from "react-dom";

// ...