vanilla-extract-css / vanilla-extract

Zero-runtime Stylesheets-in-TypeScript
https://vanilla-extract.style
MIT License
9.6k stars 293 forks source link

NonErrorEmittedError when used in next.js and monorepo project #850

Closed Kalesberg closed 1 year ago

Kalesberg commented 2 years ago

Describe the bug

Summary Loading Vanilla vars externally from monorepo package results in error when used in next.js project

Environment next.js: 12.x vanilla-extract/css: 1.7+ lerna: 5.4

Reproduce Just clone the repo and run yarn dev

Screenshot

Screen Shot 2022-09-28 at 04 51 31

Highlighted snippets src/pages/styles.css.ts

import { style } from '@vanilla-extract/css';
import { vars } from '@kalesberg/uikit';

export const textSample = style({
  color: vars.color.secondary
});

And when using textSample class in next.js page ends up with the error posted above.

Reproduction

https://github.com/Kalesberg/vanilla-issue-demo

System Info

System:
    OS: macOS 12.1
    CPU: (8) arm64 Apple M1
    Memory: 1.07 GB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.13.0 - ~/.nvm/versions/node/v16.13.0/bin/node
    Yarn: 1.22.19 - ~/.yarn/bin/yarn
    npm: 8.1.0 - ~/.nvm/versions/node/v16.13.0/bin/npm
  Browsers:
    Brave Browser: 104.1.42.88
    Chrome: 105.0.5195.125
    Safari: 15.2
  npmPackages:
    @vanilla-extract/css: ^1.9.1 => 1.9.1
    @vanilla-extract/next-plugin: ^2.1.0 => 2.1.0

Used Package Manager

yarn

Logs

No response

Validations

peterfoeng commented 1 year ago

Hi @Kalesberg did you ever figure out what's happening?

roginfarrer commented 1 year ago

I'm actually getting a very similar error, but with the Webpack plugin (which the next plugin uses)

NonErrorEmittedError: (Emitted value instead of an instance of Error) TypeError: Cannot read property 'colors' of undefined

This is happening in an app that has a dependency that has vars. The stacktrace points to this line https://github.com/vanilla-extract-css/vanilla-extract/blob/master/packages/webpack-plugin/src/loader.ts#L61

I think it could possibly be related to this? https://github.com/vanilla-extract-css/vanilla-extract/issues/963

askoufis commented 1 year ago

Closing this as I'm pretty sure it's the same issue described in https://github.com/vanilla-extract-css/vanilla-extract/issues/1043. See this comment for an explanation.

TL;DR: Exporting both classnames and components from the same barrel file (index.ts in your reproduction) causes issues with the react refresh webpack plugin.

One possible solution could be to export your styles (vars and sprinkles) from a nested entrypoint in your package, e.g. @kalesberg/uikit/theme, and then only export components from the top-level entrypoint, i.e. @kalesberg/uikit. I tried this out in your reproduction and it fixed the error.

Dessader commented 1 year ago

Closing this as I'm pretty sure it's the same issue described in #1043. See this comment for an explanation.

TL;DR: Exporting both classnames and components from the same barrel file (index.ts in your reproduction) causes issues with the react refresh webpack plugin.

One possible solution could be to export your styles (vars and sprinkles) from a nested entrypoint in your package, e.g. @kalesberg/uikit/theme, and then only export components from the top-level entrypoint, i.e. @kalesberg/uikit. I tried this out in your reproduction and it fixed the error.

Hello @askoufis,

If you don't have any difficulty, could you please provide a basic reproduction of exactly how you fixed this error? I would be very grateful.

askoufis commented 1 year ago

@Dessader

If you're not publishing the package with the issue, i.e. you just have an app, then the simplest way would just be to ensure you separate the file that exports your components from the file that exports your styles.

E.g.

// src/components/index.ts
export { MyComponent } from './MyComponent';
// src/styles/index.ts
export { vars } from './theme.css';
export { sprinkles } from './sprinkles.css';

In your consuming code, you would then just import directly from those files:

// src/App.tsx
import { MyComponent } from './components';
import { vars, sprinkles } from './styles';

If you have a component+styles package (e.g. as a separate package or within a monorepo), then the best approach would be to set up some entrypoints via package.json exports:

// package.json
{
  "name": "design-system",
  "exports": {
    ".": {
      // This is not a full example, please read the package.json exports docs linked above
      // This example assumes you are not bundling your package or just consuming it within a monorepo
      "import": "./src/components/index.ts"
    },
    // You can name this entrypoint whatever you like
    "./styles": {
      "import": "./src/styles/index"
    }
  }
}

You would then consume this the components and styles like this (after adding the design-system package as a dependency to your app):

import { MyComponent } from 'design-system';
import { vars, sprinkles } from 'design-system/styles';

Hope that helps.

Dessader commented 1 year ago

@Dessader

If you're not publishing the package with the issue, i.e. you just have an app, then the simplest way would just be to ensure you separate the file that exports your components from the file that exports your styles.

E.g.

// src/components/index.ts
export { MyComponent } from './MyComponent';
// src/styles/index.ts
export { vars } from './theme.css';
export { sprinkles } from './sprinkles.css';

In your consuming code, you would then just import directly from those files:

// src/App.tsx
import { MyComponent } from './components';
import { vars, sprinkles } from './styles';

If you have a component+styles package (e.g. as a separate package or within a monorepo), then the best approach would be to set up some entrypoints via package.json exports:

// package.json
{
  "name": "design-system",
  "exports": {
    ".": {
      // This is not a full example, please read the package.json exports docs linked above
      // This example assumes you are not bundling your package or just consuming it within a monorepo
      "import": "./src/components/index.ts"
    },
    // You can name this entrypoint whatever you like
    "./styles": {
      "import": "./src/styles/index"
    }
  }
}

You would then consume this the components and styles like this (after adding the design-system package as a dependency to your app):

import { MyComponent } from 'design-system';
import { vars, sprinkles } from 'design-system/styles';

Hope that helps.

I'm using a Turborepo based monorepository that has a consuming application and a package that needs to provide tokens.

From that package, in this example I am not exporting anything other than the result of the createGlobalTheme function, so ideally in this case there is no need to create a separate entry point for exporting as nothing else is exported.

However, when I try to use these styles, I get an error in the NextJS application:

import { cssVars } from "@example-monorepo/design-system";

export const homePageRoot = style({
    background: "teal",
    color: "white",
        // ^^
    padding: cssVars.spacing["spacing-2x"],
});

./src/styles/app.css.ts NonErrorEmittedError: (Emitted value instead of an instance of Error) ReferenceError: document is not defined

I could probably be wrong somewhere, but from the looks of it you have experience organizing styles created with vanilla-extract in separate packages.

Could you take a look at a reproducible example and suggest what the problem might be?

Repository with a reproducible example

Thanks.