fullcalendar: "Global CSS cannot be imported from within node_modules." error in Next.js
Bug Reports
<FullCalendar
initialView="timeGridWeek"
allDaySlot={false}
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin, listPlugin]}
locale={deLocale}
/>
./node_modules/@fullcalendar/core/main.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
Location: node_modules/@fullcalendar/core/main.js
I think the issue sits here https://github.com/fullcalendar/fullcalendar/blob/d3a2b13db43cfe9a450091776da3be25a0ca15c0/packages/common/src/main.ts#L1.
I recommend to not require styles in the core. It should be included by the package consumer.
More info https://github.com/zeit/next.js/blob/master/errors/css-npm.md
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 12
- Comments: 41 (16 by maintainers)
Commits related to this issue
- use FullCalendar bundle Workaround til this gets resolved: https://github.com/fullcalendar/fullcalendar/issues/5393 — committed to breadsystems/rtc-care-schedule by deleted user 4 years ago
@berekuk Yes you’re right, we have had some problems with CSS being applying different in production than in dev. Anyways thanks for the workaround! Hope the Fullcalendar team offers a less hacky way to support Next.
Here’s my workaround for this. It’s ugly and it’ll probably break on future Next.js upgrades, but it works.
(I had to dig into next-transpile-modules and Next.js code to figure it out.)
Also, I learned that Next.js is more right about their stance “CSS order is unpredictable, so we’ll forbid imports outside of pages/_app” than I expected. In my case, CSS applied differently in dev and in production, and I had to patch my styled-components wrapper with CSS overrides to fix some related issues which didn’t reveal themselves in dev.
It turns out my proposed solution won’t work because Next actually uses the
modulefield when it’s available.FullCalendar v5 must still continue to distribute its CSS in the current way because A) developers in other environments enjoy this behavior and B) I can’t introduce a breaking change until v6, so…
Users of Next.js will need to explicitly exclude FullCalendar’s CSS files from inclusion. And then they must include the stylesheets manually. I’ve written an examples of the best way to do this using a Babel transform (see below).
Separately, Next.js doesn’t process third-party ES modules and you must trick it into doing this using next-transpile-modules. I’ve written an example (see below).
Fixing SSR was the final hurdle in getting FullCalendar to work with Next.js (cc @c27cochran). I’ve fixed all SSR issues in v5.2.0
EXAMPLE PROJECT: (the newly released v5.2.0 is required) https://github.com/fullcalendar/fullcalendar-example-projects/tree/master/next#workarounds-explained
A Cleaner Solution in the Future
When the features mentioned above are implemented, no more hacks will be required to get FullCalendar working with Next. In my opinion, Next is an overly restrictive environment for third-party packages that is not keeping up to date with the latest JS ecosystem developments, creating headaches for package authors like myself. I’ve spent an inordinate amount of time addressing Next incompatibilities, more than I have with any other framework or environment. Even Nuxt (the Vue-based cousin of Next) more-or-less works out of the box.
I’m closing this issue because I’ve provided semi-satisfactory workaround, which I’ve included in FullCalendar’s documentation.
@arshaw Here you go: https://codesandbox.io/s/upbeat-tdd-d54q1?file=/pages/index.tsx
The
dynamicpart is just to tell Next not to server-side render Fullcalendar, otherwise throws a “window is not defined” error.I see that as bad practice when a library which is fully customizable via CSS enforce the consumer side to proceed other files than js. Just document how to include the default theme. This reduce size and increase flexibility.
This all makes sense. FullCalendar is published as ES modules, and
next-transpile-modulesdid the converting from ESM->CJS. That being said,next-transpile-modulesdoes NOT go as far as to compile the imported CSS file, thus the error, and thus the need for the crazy webpack workaround.@StarpTech I bet you never encountered the need to transpile from ESM->CJS because you ran into the problem while using one of the v5 beta versions, which was compiled CJS.
ANYWAY, I’m pretty sure I’ve come up with a solution that will satisfy all. I’ll publish BOTH an ESM and a CJS. Each of FullCalendar’s packages’
package.jsonwill look like this:The straightforward JS loaders like Webpack, Parcel, and Rollup will know to use the ESM because they are configured by default to look for the non-standard
moduleentry. All other environments will look formain. Luckily Next.js, and Nuxt, and Jest … all the environments that were choking while importing a CSS file … all usemainby default.The crux of this solution is that the ESM will import the CSS file whereas the CJS will not. I know it’s a little weird to make two different module formats that have slightly different execution behavior, but another way to think about it is that the
main.cjs.jsis a gracefully-degraded version ofmain.esm.jsthat does not know how to import CSS.Does this sound like a good solution to people?
A followup question: in the CJS file that Next consumes, would you like me to embed the styles via a dynamically-injected
<style>tag? This would alleviate the need to import all of FullCalendar’s CSS files manually. The downside is that you couldn’t use PostCSS to customize FullCalendar’s CSS variables nor do any other PostCSS transformations.Any update on this @arshaw? It would be nice to use V5 in next without these complications.
I read your article and I’m still not convinced. I see it more than a disadvantage because it produces incompatibilities. The described issues can be easily fixed with proper documentation.
Next.js already supports
cssandsassimports but it refuses to import global CSS/SASS files in modules other than in the app root component because the import order can’t be guaranteed. The design decision will make your module incompatible with Next.js a very popular react framework.Found a fix…thought I’d share.
Break your calendar out into its own component and dynamically load it. Works perfect.
And, in CalendarPage:
@acobster, I need to make each package output a CJS module in addition to the ESM it’s already outputting. It will require quite a bit more configuration in the rollup config that is run when FullCalendar is built. BTW, I’ll also be needing to add more config for a JS global dist file as well.
It sounds like the solution described in this ticket will help your situation as well.
I plan to release this in about 2 weeks, but might take a bit longer. Maybe simply removing the .css import will be a good workaround in the meantime. Though if you could somehow convince the ClosureScript transpiler to ignore .css imports, that’d be the ideal workaround for now.
@StarpTech, yes, I know, you’ve made that point very clear, and the solution I’m proposing will allow you to do exactly that. I can’t tell whether you’re agreeing with me or disagreeing with me.
Anybody had any luck with this? I’ve taken a look to
next-transpile-modulesbut like @arshaw says it has nothing to do withnode_modules; it’s really a shame it does not work out-of-the-box with Next since V5 seems to solve all the issues we had with V4.