Replies: 1 comment
-
|
I suppose the CLI might be a way to work around this. But as far as I know there are still open issues with the CLI handling external packages? (#731 ) |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This is a companion to my earlier discussion (#1499) about webpack resolving transitive imports when running the StyleX babel plugin on
node_modulespackages. That post covers a webpack runtime conflict caused by a specific Highcharts packaging issue. This post describes a second, independent problem that affects any browser-only dependency in a StyleX component library's import graph.Setup (same as #1499)
We have a Next.js app consuming a shared component library that ships uncompiled StyleX. We run
babel-loader+@stylexjs/babel-pluginon the library insidenode_modulesvia a custom webpack rule. The library includes chart components that depend on Highcharts (a browser charting library).The problem
During
next build, Next.js compiles the bundles (webpack step) and then executes the compiled server bundle in Node.js to prerender static pages. Because our webpack rule targets the component library insidenode_modules, webpack follows the library's full import graph — including into@highcharts/reactandhighcharts. These end up in the server bundle.When Node.js executes the server bundle to generate static HTML, Highcharts tries to initialize. It accesses browser globals (
window,document,SVGElement) at module evaluation time. In Node.js, those globals don't exist, and the build crashes:This happens even when the chart components are only used on client-rendered pages. The issue is that webpack bundled them into the server entry because it followed the import chain from the library.
Why
'use client'doesn't helpOur chart component source files have
'use client'at the top. Normally, Next.js uses this directive as a boundary — modules marked'use client'and their imports stay out of the server bundle.But the StyleX babel-loader rule operates independently of Next.js's client/server analysis. It tells webpack: "process all files matching
@acme/component-library." Webpack resolves and bundles those files' imports regardless of any'use client'directive. The directive gets compiled away as part of the babel transform, and Next.js never sees it.Even if we preserved the directive, the webpack rule would still cause the imports to be followed. The
includepattern controls loader execution, not module resolution.Our workaround
We made all Highcharts imports dynamic and guarded them with
typeof window === 'undefined':Chart components use a
useHighchartsInit()hook that calls this function in auseEffectand renders a placeholder until the components are ready.This works —
next buildsucceeds, charts render on the client, non-chart consumers are unaffected. But it's a workaround for the fact that the StyleX compilation step forces webpack to pull browser-only code into the server bundle.The broader pattern
This isn't specific to Highcharts. Any StyleX component library that wraps a browser-only dependency (charting libraries, map libraries, rich text editors, etc.) will hit this. The library needs StyleX compilation at consumer build time, which forces webpack to follow the full import graph, which drags browser-only code into server-side execution.
Libraries that don't use StyleX avoid this because their pre-built output is treated as an opaque dependency — webpack doesn't follow their internal imports. The
'use client'boundary works as designed in that case.The question
Is there a path toward StyleX compilation that doesn't force the consumer's webpack to resolve the library's full import graph?
Some possibilities that come to mind:
Any of these would let StyleX libraries wrap browser-only dependencies without requiring lazy-init workarounds. Is anything like this on the roadmap, or is the dynamic import pattern the expected approach for this case?
Beta Was this translation helpful? Give feedback.
All reactions