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

<GlobalStyles /> don't work properly with next.js app folder #182

Closed
yhaskell opened this issue Jul 1, 2023 · 7 comments
Closed

<GlobalStyles /> don't work properly with next.js app folder #182

yhaskell opened this issue Jul 1, 2023 · 7 comments

Comments

@yhaskell
Copy link

yhaskell commented Jul 1, 2023

Hello and thanks for an amazing project ;)

I discovered that the GlobalStyles component's current implementation doesn't work with the next.js app folder.

I've created a reproduction case here: https://codesandbox.io/p/sandbox/nifty-glitter-hvkpmw

The styles get added, but they are not updated when the styles parameter changes.

In the current example, when the dark mode switch is activated, the new styles are added, but the original ones stay in the head list and as a result the dark mode doesn't work :)

The "magic" button removes the block with the global css. But, as this block also contains non-global css for the primary text, when we click the button. those styles are being lost.

@garronej
Copy link
Owner

garronej commented Jul 1, 2023

Hello @yhaskell,

I appreciate your diligent investigation into this significant bug that was previously unbeknownst to me. Your provision of the reproduction repository was particularly helpful.

While I could attempt a quick fix from TSS, the optimal resolution would entail rectifying the root cause directly within the emotion repository.

To facilitate this, could I kindly ask you to revise your repository to exclusively utilize @emotion/react? You can simply replace the existing code with the following:

NextAppDirEmotionCacheProvider.tsx

"use client";

import React from "react";
import createCache from "@emotion/cache";
import { useServerInsertedHTML } from "next/navigation";
import { useState } from "react";
import { CacheProvider as DefaultCacheProvider } from "@emotion/react";
import type { Options as OptionsOfCreateCache } from "@emotion/cache";
import type { EmotionCache } from "@emotion/cache";
import type { ReactNode } from "react";

export type NextAppDirEmotionCacheProviderProps = {
    /** This is the options passed to createCache() from 'import createCache from "@emotion/cache"' */
    options: Omit<OptionsOfCreateCache, "insertionPoint">;
    /** By default <CacheProvider /> from 'import { CacheProvider } from "@emotion/react"' */
    CacheProvider?: (props: {
        value: EmotionCache;
        children: ReactNode;
    }) => JSX.Element | null;
    children: ReactNode;
};

export function NextAppDirEmotionCacheProvider(
    props: NextAppDirEmotionCacheProviderProps
) {
    const { options, CacheProvider = DefaultCacheProvider, children } = props;

    const [{ cache, flush }] = useState(() => {
        const cache = createCache(options);
        cache.compat = true;
        const prevInsert = cache.insert;
        let inserted: string[] = [];
        cache.insert = (...args) => {
            const serialized = args[1];
            if (cache.inserted[serialized.name] === undefined) {
                inserted.push(serialized.name);
            }
            return prevInsert(...args);
        };
        const flush = () => {
            const prevInserted = inserted;
            inserted = [];
            return prevInserted;
        };
        return { cache, flush };
    });

    useServerInsertedHTML(() => {
        const names = flush();
        if (names.length === 0) return null;
        let styles = "";
        for (const name of names) {
            styles += cache.inserted[name];
        }
        return (
            <style
                key={cache.key}
                data-emotion={`${cache.key} ${names.join(" ")}`}
                dangerouslySetInnerHTML={{
                    "__html": styles
                }}
            />
        );
    });

    return <CacheProvider value={cache}>{children}</CacheProvider>;
}

GlobalStyles.tsx

"use client";
import React from "react";
import * as reactEmotion from "@emotion/react";
import type {
    CSSInterpolation
} from "@emotion/serialize";

export function GlobalStyles(props: { styles: CSSInterpolation }) {
    const { styles } = props;

    return <reactEmotion.Global styles={reactEmotion.css(styles)} />;
}

Please ensure that only the code necessary for reproducing the bug remains. You can refer to the @emotion/react documentation here. Please steer clear of the native css prop as it presents a challenging setup.

Regrettably, I currently lack the bandwidth to undertake this task myself, but I am here to assist should you encounter any obstacles during the repository conversion.

If solely using @emotion/react resolves the issue, it's excellent news as it would imply an error on my end that I can address. Conversely, if the problem persists, we'll proceed to open an issue in the emotion repository. If a solution isn't reached within a week, I'll personally intervene to rectify the situation.

Please feel free to share any suggestions or thoughts you may have.

I extend my deepest apologies for the less-than-ideal developer experience and sincerely hope that this hasn't consumed excessive hours of your time.

Best regards,

@yhaskell
Copy link
Author

yhaskell commented Jul 2, 2023

I've managed to reproduce it using only @emotion/* packages, and I think I found the issue:

the <Global /> component in @emotion/react expects the data-emotion attribute to be ${cache.key}-global ${serialised.name}, which tss-react doesn't have in the implementation of the CacheProvider.

@garronej
Copy link
Owner

garronej commented Jul 2, 2023

@yhaskell Cool!

That mean we can fix it quite easily.

@garronej
Copy link
Owner

garronej commented Jul 2, 2023

I'm trying to implement a fix and release a candidate

garronej added a commit that referenced this issue Jul 2, 2023
@garronej
Copy link
Owner

garronej commented Jul 2, 2023

I'm releasing 4.8.7-rc.0 right now.

If you are right in your diagnostic, it should fix it 🤞🏻

@garronej
Copy link
Owner

garronej commented Jul 2, 2023

I think I've implemented your suggestion correctly but it dosen't seem to work 😞

a87c39c

image

Any idea?

@garronej
Copy link
Owner

It's fixed, thanks a lot for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants