kriasoft / isomorphic-style-loader

CSS style loader for Webpack that is optimized for isomorphic (universal) web apps.

Home Page:https://reactstarter.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for next.js

ajayjaggi97 opened this issue · comments

Can you pls share the insights of using isomorphic-style-loader with next.js. How can we pass the required context value of insertCss??

@ajayjaggi97 I've tried for the last 3 days to get it to work with next.js and I'm finally happy to use it.
First of all: I want to use it for a component-library and not directly in next.js. I think for direct usage, next.js already has a nice system through the *.module.scss/css-files.

This is where the magic happens: Here is the content of my _app.tsx:

export default function MyApp({ }: AppProps) {
    const styles: string[] = useMemo(() => [], []);

    const addStyles = useCallback(
        (...newStyles) => {
            if (typeof document === 'undefined') {
                styles.push(...newStyles.map((s) => s._getCss()));
            } else {
                newStyles.forEach((s) => s._insertCss());
            }
        },
        [styles]
    );

    return (
        <>
            <StyleProvider value={{ insertCss: addStyles }}>
                <ColorInput />
            </StyleProvider>
            <StyleRenderer styles={styles} />
        </>
    );
}

and my StyleRenderer.tsx:

export type StyleRendererProps = { styles: string[] };

export function StyleRenderer({ styles }: StyleRendererProps) {
    return (
        <Head>
            <style>{styles.join()}</style>
        </Head>
    );
}

Note that I use useMemo in order to save the styles and StyleRenderer, which only displays the styles. This is because of how nextjs works. Once the rendermethod is done, you can't trigger an rerender on the server, regardless what you do (or at least I could not trigger one). But subcomponents are still rendering. Since the components are called top-down, the ColorInput is called before the StyleRenderer. Inside the ColorInput I use the useStyles hook, which calls addStyles from _app.tsx. Since I used useMemo for styles, it is the same instance inside addStyles as is passed to StyleRenderer,
Since StyleRenderer renders last, it will render all the styles needed inside the server rendering.
On the client, I just use the s._insertCss() method without any problems.

And also note that I did not use StyleContext.Provider but StyleProvier which is an reexport of StyleContext.Provider from my component-library. This is needed or else the context used from useStyles inside the library is a different one than the one provides through StyleContext.Provider inside next.js

Hey @Ainias .Thanks for the solution. I had the similar use case where we had a components library.

commented

Do you have a specific example for reference? thank you

@Ainias @ajayjaggi97 can you give a example? I'm very curious about how to actually implement this🤪.