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

Error when updating Next.js to 14.2.2 version while using lodash-es in a @vanilla-extract/css file #1393

Open
2 tasks done
sbahaddi opened this issue Apr 23, 2024 · 3 comments
Labels
nextjs Issue related to NextJS

Comments

@sbahaddi
Copy link

sbahaddi commented Apr 23, 2024

Describe the bug

I encountered an error when updating my Next.js version from 14.1.4 to 14.2.2 while using lodash-es in a @vanilla-extract/css file. The error seems to be related to the usage of lodash-es in conjunction with @vanilla-extract/css.

Code Sample:

import { style } from "@vanilla-extract/css";
import { cloneDeep } from "lodash-es";

const test = cloneDeep;

export const demo = style({
  color: "red",
});

this branch has nextjs 14.1.4 and its working fine
https://github.com/zecka/next-vanilla-extract-example/tree/chore/add-lodash-es

Steps to Reproduce:

Create a Next.js project.
Install @vanilla-extract/css.
Create a CSS file using @vanilla-extract/css and import lodash-es in the same file.
Update Next.js to version 14.2.2
Attempt to build or run the project.

Expected Behavior:

The project should build or run successfully without any errors, as it did with Next.js version 14.1.4.

Reproduction

https://github.com/zecka/next-vanilla-extract-example/tree/chore/lodash-es-next14.2.2-bug

System Info

Build Error
Failed to compile

Next.js (14.2.2)
./src/app/components/demo.css.ts
NonErrorEmittedError: (Emitted value instead of an instance of Error) ReferenceError: $RefreshReg$ is not defined

Used Package Manager

yarn

Logs

No response

Validations

@6mint
Copy link

6mint commented Apr 23, 2024

I found a workaround that is based on this comment from react-refresh-webpack-plugin which seems to be the precursor of the one that next js is using internally.

next.config.js

const { createVanillaExtractPlugin } = require("@vanilla-extract/next-plugin");

const withVanillaExtract = createVanillaExtractPlugin();

/** @type {import('next').NextConfig} */
let nextConfig = {
    webpack(config, { nextRuntime, webpack }) {
        if (!nextRuntime) {
            config.plugins.push(
                new webpack.BannerPlugin({
                    banner: `$RefreshReg$ = () => {};\n$RefreshSig$ = () => () => {};\n`,
                    raw: true,
                    entryOnly: true,
                    include: /\.css.ts$/,
                }),
            );
        }
        return config;
    },
};

nextConfig = withVanillaExtract(nextConfig);

module.exports = nextConfig;

@askoufis
Copy link
Contributor

Something about the lodash-es package in particular seems to be causing this. Or perhaps something to do with esbuild + ESM. Not completely sure. However, I did try out just using regular lodash, and it seems to work fine. AFAIK next.js optimizes lodash imports for better tree-shaking, so it would be fine to use if you don't need to use lodash-es for some specific reason.

@6mint
Copy link

6mint commented Nov 23, 2024

I took a look into it and it seems that next js adds only es module exports to the react-refresh/runtime registry. [1][2]
If the export is a function starting with a capital letter react-refresh/runtime assumes it to be a react component.[3]

So each time a react component imports a .css.ts file which imports a capitalized function from an es module we run into this issue. (lodash-es for example exports the LodashWrapper function)

This issue is mentioned in react-refresh-webpack-plugin (which behaves similar to the next js internals and also relies on react-refresh/runtime)

Ensure all exports within the indirect code path are not named in PascalCase. This will tell the Babel plugin to do nothing when it hits those files.

...

In the entry of your indirect code path (e.g. some index.js), add the following two lines:

self.$RefreshReg$ = () => {};
self.$RefreshSig$ = () => () => {};

This basically acts as a "polyfill" for helpers expected by react-refresh/babel, so the worker can run properly.

Next js seems to use a similar noop approach on initialization.

So it might be a good idea to add these noops to .css.ts files when using the vanilla extract next-plugin, especially since the number of "esm only" packages keeps increasing.
(The simplest method I could find was using webpacks own BannerPlugin like in my comment above)

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

No branches or pull requests

3 participants