Next.js: Importation de css correctement délimités à partir de node_modules en dehors de _app

Créé le 21 avr. 2020  ·  49Commentaires  ·  Source: vercel/next.js

Rapport d'erreur

Décrivez le bogue

L'importation d'une feuille de style depuis un package n'est pas possible dans une page, car next renvoie avec cette erreur :

Global CSS cannot be imported from files other than your Custom <App>. Please move all global CSS imports to pages/_app.tsx.
Read more: https://err.sh/next.js/css-global

Bien que je comprenne d'où cela vient, cela rend impossible le fractionnement de code. Si j'importe un composant à partir d'une bibliothèque de composants, je dois également importer le CSS. Il peut y avoir des bibliothèques qui ne délimitent pas correctement leurs sélecteurs, mais cela ne devrait pas m'empêcher d'écraser cet avertissement. Le CSS qui est importé d'une bibliothèque n'est pas intrinsèquement « global ».

Reproduire

  1. import "my-library/index.css"
  2. yarn dev
  3. j'obtiens l'erreur d'en haut

Comportement attendu

Le fichier doit être importé.

Je vois ces solutions possibles :

  • Drapeau mondial en next.config.js
  • Commentaire d'annotation sur l'importation
  • Avertir au lieu de le bloquer complètement
  • Vérifiez si le CSS ne contient que des sélecteurs de portée

Contexte supplémentaire

Il y a déjà eu des discussions à ce sujet.

Du blog

Les feuilles de style étant globales par nature, elles doivent être importées dans le Customcomposant. Ceci est nécessaire pour éviter les conflits de nom de classe et d'ordre pour les styles globaux.

Je ne suis pas d'accord avec cette affirmation, le raisonnement étant qu'une bibliothèque externe peut utiliser des modules CSS et les emballer sous forme de fichier CSS à importer. Ce qui est parfaitement valable et pratique courante et n'a pas d'effets secondaires .

#10059

Ce problème a été clos car l'importation globale dans _app est le bon choix.
Ce commentaire décrit le problème exact, mais il n'y a pas eu de réponse, car le problème est clos. Le commentaire a suscité beaucoup de réactions positives, donc je suppose que je ne suis pas le seul à avoir ce problème.

#10975

Semble être sans rapport.

#9830

C'est peut-être lié, mais je ne suis pas sûr.

Mon cas d'utilisation

J'écris de longs articles avec de nombreuses illustrations personnalisées et des illustrations interactives. Les articles utilisent des packages npm privés avec des composants de réaction qui rendent SVG avec pas mal de CSS. Ces packages utilisent des modules CSS et exportent un index.js et un index.css . L'ajout de tous les fichiers CSS à _app provoque le chargement de tous les CSS, même si les gens sont sur la page d'accueil, le formulaire de contact ou tout autre article, même s'il est 100% inutilisé. Cela va également à l'encontre du fait que le système de fichiers s'occupe de vos pages car presque chaque page correspond à un import CSS en _app .

story 8 feature request

Commentaire le plus utile

Nous allons autoriser l'importation de CSS à partir de node_modules dans n'importe quel fichier de composant au cours de la semaine prochaine (sur Canary) ! Nous publierons ici quand il sera prêt à être testé.

Tous les 49 commentaires

Je suis confronté au même problème en essayant simplement d'utiliser Linaria, qui définit ses propres noms de classe. Bien que les fichiers css qu'il produit ne se terminent pas par .module.css , ce sont des "modules". J'ai besoin d'un moyen facile de m'intégrer à la bibliothèque.

pourquoi est-ce même passé à nouveau à nextjs ?

J'aimerais également pouvoir utiliser GlobalCSS en dehors de node_modules. Cela nous aiderait à adopter progressivement les modules CSS

oui c'est très important ! de nombreux packages npm ne fonctionnent pas avec nextjs mais fonctionnent avec CRA ou d'autres frameworks

Pour toute autre personne qui essaie de l'utiliser avec l'implémentation js de dart sass pour des choses comme le support @use et les modules sass, si vous avez un autre module de nœud qui a une dépendance sur node-sass, la prochaine configuration par défaut utilisera node-sass au lieu de sass. Localement, je l'ai corrigé en procédant comme suit:

// example next.config.js
module.exports = {
webpack(config, options) {
  config.module.rules.forEach(rule => {
          if (rule.oneOf) {
            const nestedScss = rule.oneOf.find((one) => {
              return one.test
                && 'some.scss'.match(one.test) 
                && one.issuer 
                && one.issuer.include 
                && one.issuer.include.includes('_app');
            });
            if (nestedScss) {
              const sassLoader = nestedScss.use.find(u => u.loader.includes('sass-loader'));
              // Set implementation to sass instead of node-sass here.
              sassLoader.options.implementation = require('sass');
            }
          }
        })
  }
}

Vous devrez ensuite importer vos fichiers scss dans _app.js .

@smurrayatwork c'est du piratage pas du codage désolé

De plus, la restriction selon laquelle il est exclusivement _app.js est un peu lourde.

Si nous n'allons pas prendre en charge les références CSS partout, pourrions-nous faire en sorte que CSS puisse également être référencé par des dépendances directes de _app (qui ne sont référencées nulle part ailleurs) ?
c'est à dire. C'est bien si cela est requis par _app (et nulle part ailleurs) ce qui donnerait au CSS un ordre déterministe basé sur les importations.

Ce n'est pas idéal, mais le cas d'utilisation que j'ai est que j'ai une base de code partagée par plusieurs applications qui importent un module partagé qui importe du CSS partagé. Je détesterais dupliquer ces importations CSS partagées dans _app.js pour chaque application. Actuellement, pour contourner ce problème, je devrais faire de la métaprogrammation js sophistiquée, car nous ne pouvons pas exiger de css dans d'autres modules.

Au lieu de cela, je voudrais que mon approche actuelle fonctionne, c'est-à-dire que j'ai une "App Factory" qui importe tout le CSS partagé. _app utilise ensuite l'usine et importe son propre CSS en plus de ceux partagés.

J'ajoute https://github.com/vercel/next.js/discussions/13991 car je pense que cela est lié à ce problème.

+100 à cela. Je dois copier et coller les fichiers css du module de nœud dans mon projet et ajouter un .module.css dessus

Voici un autre exemple.

Dans le cas du package pdf-viewer-reactjs ses dépendances nécessitent un CSS qui doit également être importé à partir de _app.js .

Cela gonfle le CSS pour l'ensemble de l'application et je ne suis pas sûr des conflits à ce stade.

importer « react-quill/dist/quill.snow.css » ;
importer « react-image-crop/dist/ReactCrop.css » ;
importer '../../node_modules/material-design-icons/iconfont/material-icons.css' ;
importer '../../node_modules/bulma/css/bulma.css';
importer '../../node_modules/bulma-helpers/css/bulma-helpers.min.css' ;

De plus, ce qui suit est affiché sur la console :

avertir - ./node_modules/material-design-icons/iconfont/material-icons.css
Le CSS global ne peut pas être importé depuis node_modules.
Lire la suite : https://err.sh/next.js/css-npm
Emplacement : node_modules/pdf-viewer-reactjs/dist/pdf-viewer-reactjs.js

./node_modules/bulma/css/bulma.css
Le CSS global ne peut pas être importé depuis node_modules.
Lire la suite : https://err.sh/next.js/css-npm
Emplacement : node_modules/pdf-viewer-reactjs/dist/pdf-viewer-reactjs.js

./node_modules/bulma-helpers/css/bulma-helpers.min.css
Le CSS global ne peut pas être importé depuis node_modules.
Lire la suite : https://err.sh/next.js/css-npm
Emplacement : node_modules/pdf-viewer-reactjs/dist/pdf-viewer-reactjs.js

./node_modules/material-design-icons/iconfont/material-icons.css
Échec de la construction du module : erreur : le chargeur final (./node_modules/next/dist/build/webpack/loaders/error-loader.js) n'a pas renvoyé de tampon ou de chaîne

./node_modules/bulma/css/bulma.css
Échec de la construction du module : erreur : le chargeur final (./node_modules/next/dist/build/webpack/loaders/error-loader.js) n'a pas renvoyé de tampon ou de chaîne

./node_modules/bulma-helpers/css/bulma-helpers.min.css
Échec de la construction du module : erreur : le chargeur final (./node_modules/next/dist/build/webpack/loaders/error-loader.js) n'a pas renvoyé de tampon ou de chaîne

Salut ! Est-ce que quelqu'un a résolu ce problème et comment ? Tant de modules de nœuds que je ne peux pas importer à cause de cela.

Peut-être que l'utilisation de styles globaux dans les composants pourrait être activée via next.config.js , ou qu'un avertissement de console laide contre les styles globaux pourrait être affiché, au cas où l'on craindrait de rompre avec les meilleures pratiques / opinions de NextJS.

Mais cela est important pour les utilisateurs qui effectuent une conversion depuis CRA > NextJS. C'est un bloqueur pour nous car nous ne pouvons pas changer et adopter progressivement des choses comme les modules CSS.

Toujours incapable de contourner ce problème. Pour mes propres besoins, j'ai utilisé un gestionnaire CSS personnalisé, mais cela désactive la prise en charge CSS intégrée, mais ce n'est peut-être pas une bonne solution dans tous les cas. Ce qui suit est déconseillé , n'utilisez que jusqu'à ce que les auteurs du package le trient

next.config.js

const withCSS = require('@zeit/next-css');
const withPlugins = require('next-compose-plugins');
...
module.exports = withPlugins([
...
withCSS,
]);

@abdelrahmantoptal 's Savez-vous comment faire en sorte que cela fonctionne pour SASS ?

Il semble que cela fonctionnerait pour CSS, mais génère une erreur lors de la rencontre d'une importation SASS :

error - ./src/components/layouts/Footer.scss 1:0
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> <strong i="8">@import</strong> 'styles/vars';
| 
| footer {

J'ai donc essayé d' ajouter un chargeur SASS à la configuration du pack Web avant d'utiliser le plugin withCSS :

      config.module.rules.push({
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          'style-loader',
          // Translates CSS into CommonJS
          'css-loader',
          // Compiles Sass to CSS
          'sass-loader'
        ]
      });

Mais cela a causé :

error - ./src/components/App.scss
ReferenceError: self is not defined

J'ai également essayé de substituer @zeit/next-sass , mais cela a provoqué la même erreur :

error - ./src/components/App.scss
ReferenceError: self is not defined

Des suggestions sur la façon de peaufiner votre code pour utiliser SASS ?

J'ai maintenant rejeté Gatsby et bientôt Next.js à cause de leurs fonctionnalités opiniâtres petites, mais très bloquantes, telles que celle-ci. Je ne peux plus utiliser le plugin CodeBlock pour CKEditor 5 car je ne peux pas contourner cette erreur. Il devrait toujours y avoir un moyen de contourner ces configurations.

Il serait très utile d'avoir des nouvelles de @Timer ou de quelqu'un de Vercel à propos de ce problème. C'est un gros problème avec Next.js. Quelque chose est prévu pour résoudre ce problème ?

D'accord! Il est incroyablement courant d'avoir du css dans les modules de nœud. En tant que développeur, je n'ai aucun contrôle sur la façon dont les autres développeurs structurent leurs modules de nœud, et d'autres développeurs ne s'attendent pas à ce que le fait de mettre du CSS dans un module de nœud casse un framework Web.

@OssiPesonen avez-vous déjà vu cela ? Cette solution de contournement n'est pas idéale, mais elle a résolu le problème pour moi entre-temps.

@OssiPesonen avez-vous déjà vu cela ? Cette solution de contournement n'est pas idéale, mais elle a résolu le problème pour moi entre-temps.

Je ne vois pas en quoi cela aide? Le problème n'est pas que je doive importer manuellement certains fichiers CSS à partir des modules de nœud. Le problème est que les packages npm effectuent l'importation CSS en eux-mêmes. Un package qui comprend une ligne comme celle-ci :

import '../theme/stylesheet.css'

Provoquera le crash de next.js avec vengeance. Et apparemment, le conseil du mainteneur est le suivant :

Contactez le responsable et demandez-lui de publier une version compilée de sa dépendance.

Dans quel genre de pays imaginaire les gens vivent-ils où ils imaginent que vous pouvez simplement contacter les responsables pour leur demander de recompiler leur paquet pour vous à un rythme très rapide ? Cela gênera n'importe qui pendant des semaines ! Ce billet est ouvert depuis 4 mois. C'est inacceptable lorsque l'on travaille sur des projets à évolution rapide.

Nous allons autoriser l'importation de CSS à partir de node_modules dans n'importe quel fichier de composant au cours de la semaine prochaine (sur Canary) ! Nous publierons ici quand il sera prêt à être testé.

Si quelqu'un en a besoin avant la sortie, j'ai pu utiliser le plugin next-transpile-modules pour transpiler le module de node_modules qui importait du CSS. A fonctionné à merveille pour moi.

@BrandonE semble que next-transpile-modules doit toujours avoir les modules nommés *.module.css . Avez-vous trouvé un moyen de contourner cela?

@rjoaopereira Je ne peux pas dire que j'ai une compréhension approfondie de la façon dont tout cela fonctionne, mais la plupart de mes node_modules qui ont importé du CSS n'ont fonctionné qu'avec le plugin @zeit/next-css . Un seul ne l'a pas fait, à quel point la transpilation a résolu le problème. Loin d'être une solution élégante, et j'espère que les futures versions de Next.js nous permettront de passer moins de temps sur l'alchimie Babel / Webpack et plus sur la réalisation d'applications web.

Cela fonctionne presque avec les changements suivants.

suivant 9.5.3
next-transpile-modules 4.1.0
Composants de première partie avec émotion.
Composants tiers avec un mélange de modules css et de css global

scopedcomponents doit être remplacé par les composants tiers utilisés

//next.config.js
const withCustomWebpack = require("./webpack-custom.config");
const withNextCSSOverride = require("./next.config.css");
const withTM = require("next-transpile-modules")(["@scopedcomponents"]);

module.exports = withCustomWebpack(
  withTM(
    withNextCSSOverride({
      poweredByHeader: false
    })
  )
);

///next.config.css.js
const {
  getCssModuleLocalIdent
} = require("next/dist/build/webpack/config/blocks/css/loaders/getCssModuleLocalIdent");
const path = require("path");
/**
 * Stolen from https://stackoverflow.com/questions/10776600/testing-for-equality-of-regular-expressions
 */
const regexEqual = (x, y) => {
  return (
    x instanceof RegExp &&
    y instanceof RegExp &&
    x.source === y.source &&
    x.global === y.global &&
    x.ignoreCase === y.ignoreCase &&
    x.multiline === y.multiline
  );
};

module.exports = (nextConfig = {}) => {
  return Object.assign({}, nextConfig, {
    webpack(config, options) {
      const nextCssLoaders = config.module.rules.find(
        rule => typeof rule.oneOf === "object"
      );

      if (nextCssLoaders) {
        const nextCssLoader = nextCssLoaders.oneOf.find(
          rule =>
            rule.sideEffects === false &&
            regexEqual(rule.test, /\.module\.css$/)
        );

        if (nextCssLoader) {
          /***********************************************************
           * change the rule to match all scopedcomponents css files
           ***********************************************************/
          nextCssLoader.test = /(@scopedcomponents|react\-virtualized)\/.*\.css$/;

          const cssLoader = nextCssLoader.use.find(({ loader }) =>
            loader.includes("css-loader")
          );

          if (cssLoader) {
            /***********************************************************
             * Override the default behaviour for CSS modules discovery
             * auto = true makes webpack search for *.module.css
             * https://webpack.js.org/loaders/css-loader/#auto
             ***********************************************************/
            cssLoader.options.modules.auto = /@scopedcomponents\/.*\.css$/;
            /***********************************************************
             * Nextjs overrides the default mode to "Pure"
             * https://github.com/vercel/next.js/blob/v9.5.2/packages/next/build/webpack/config/blocks/css/loaders/modules.ts#L35
             * Put it back to normal
             ***********************************************************/
            cssLoader.options.modules.mode = "local";
            /***********************************************************************************************************************
             * There is a problem when using components built with css-modules with Nextjs.                                        *
             * NextJS will consume code from `lib` on the server side and from `es` on the client.                                 *
             * https://github.com/vercel/next.js/blob/v9.5.2/packages/next/build/webpack-config.ts#L374                            *
             * This raises a problem when generating the classes for different environments,                                       *
             * throwing an error of className mismatch due to the hash created being based on the file path                        *
             * https://github.com/vercel/next.js/blob/v9.5.2/packages/next/build/webpack/config/blocks/css/loaders/modules.ts#L26  *
             * https://github.com/webpack/loader-utils/blob/v1.4.0/lib/interpolateName.js#L39                                      *
             * To solve this, when generating the classNames for 3rd party components,                                                 *
             * we need to tell cssloader to always use the same path                                                               *                                                                          *
             *                                                                                                                     *
             *  https://github.com/zeit/next-plugins/issues/595                                                                    *
             ***********************************************************************************************************************/
            cssLoader.options.modules.getLocalIdent = (
              context,
              localIdentName,
              localName,
              options
            ) => {
              const newContext = { ...context };
              if (newContext.resourcePath.includes("@scopedcomponents")) {
                newContext.resourcePath = newContext.resourcePath.replace(
                  `${path.sep}es${path.sep}`,
                  `${path.sep}lib${path.sep}`
                );
              }
              return getCssModuleLocalIdent(
                newContext,
                localIdentName,
                localName,
                options
              );
            };
          }
        }
      }

      if (typeof nextConfig.webpack === "function") {
        return nextConfig.webpack(config, options);
      }

      return config;
    }
  });
};

Problèmes:

@Timer une mise à jour à ce sujet ?

Nous allons autoriser l'importation de CSS à partir de node_modules dans n'importe quel fichier de composant au cours de la semaine prochaine (sur Canary) ! Nous publierons ici quand il sera prêt à être testé.

Y aura-t-il une importation dynamique de CSS à partir d'un composant après ce correctif ?

Merci beaucoup @Timer

next@^9.5.4-canary.10 vous permet désormais d'importer Global CSS à partir de node_modules n'importe où dans votre application. Cela améliore l'interopérabilité avec les bibliothèques React tierces qui nécessitent que vous importiez leur CSS, mais ne veulent pas que cela augmente la taille de l'ensemble pour l'ensemble de votre application.

@Timer J'ai hâte d'avoir cette sortie, j'ai vraiment apprécié votre travail ️

Merci @Timer !

Cela a été un problème bloquant pour moi actuellement, mais lorsque je l'ai testé aujourd'hui, je vois toujours le même message d'erreur. Y a-t-il autre chose que la simple mise à niveau vers 9.5.4-canary-10 ? Cet exemple essaie d'utiliser la bibliothèque tierce

image

@johmike Importez -vous en utilisant la syntaxe suivante ??

import "@rmwc/avatar/avatar.css";

Avez-vous essayé de redémarrer le serveur de développement après avoir installé la dernière version de next ?

@Timer Merci beaucoup pour cette fonctionnalité. Fonctionne très bien pour importer un fichier CSS à partir du dossier node_modules .

import 'prism-themes/themes/prism-darcula.css';

Avez-vous l'intention de prendre en charge l'importation de CSS global en dehors du répertoire node_modules ?

@sasivarnan
Cela vient d'une autre bibliothèque qui importe les composants @rmwc . Cette bibliothèque utilise @require("@rmwc/avatar/avatar.css") . J'importe import {Avatar} from "library/Avatar" et cela échoue.

@sasivarnan

Cela vient d'une autre bibliothèque qui importe les composants @rmwc . Cette bibliothèque utilise @require("@rmwc/avatar/avatar.css") . J'importe import {Avatar} from "library/Avatar" et cela échoue.

J'ai compris. Je pensais qu'il avait été importé directement dans votre application. Ma faute.

À en juger par les commentaires ici, ce n'est en fait pas résolu ou cela a été résolu, mais de nombreuses personnes ici signalent un problème différent. Beaucoup de gens ne peuvent toujours pas importer de modules, qui importent du CSS à partir du packge lui-même (une instruction import style.css dans un fichier de package).

Le correctif semble permettre à l'application d'importer du CSS à partir du chemin node_modules/ , mais il existe un moyen assez simple de contourner ce problème : copiez simplement le CSS dans votre application jusqu'à ce qu'il soit corrigé. Ce n'est pas un problème de niveau de blocage. Cela n'a donc pas vraiment résolu le problème des bloqueurs auquel il n'y a pas de solution facile. Si vous importez un composant qui a une instruction d'importation dans un fichier CSS que le package contient lui-même, l'application se bloque.

@sasivarnan @OssiPesonen, vous semblez tous les deux parler d'un problème différent de celui qui a été discuté et corrigé dans ce problème du PO.

Cela corrige spécifiquement les bibliothèques qui nécessitent que vous importiez leur CSS dans votre application, par exemple :

// components/MySlider.tsx
import { Slider } from "@reach/slider";
import "@reach/slider/styles.css";

function Example() {
  return <Slider min={0} max={200} step={10} />;
}

Ce dont vous parlez est un doublon de #706 et #13282, ou la possibilité de traiter node_modules comme un code propriétaire.

@Timer Je viens de tester le cas d'utilisation attendu et cela fonctionne bien.

Lorsque j'importe le css dans un composant directement dans le cadre de la structure suivante, cela fonctionne comme prévu, sans erreur.
Cependant, si je déplace ce composant dans un autre package en dehors de la structure suivante, que je crée, puis que j'installe ce package, il revient à la même erreur qu'auparavant.

Il est possible que quelque chose d'autre se passe, car je n'utilise même pas le composant Avatar dans cet exemple, j'importe Button et pourtant Avatar est l'erreur défaillante.

image

J'ai également ajouté next-transpile-modules car nous travaillons à partir d'un monorepo, mais cela n'a pas semblé résoudre ce problème particulier.

J'ai fait fonctionner cela grâce à un fichier de configuration étrange en creusant un tas d'autres problèmes autour de next-transpile-modules .

const withCSS = require("@zeit/next-css");
module.exports = withCSS();
require.extensions[".css"] = () => {
  return;
};

J'ai éliminé next-transpile-modules et cela fonctionne. Je ne sais pas pourquoi, il semble que cela ne devrait rien faire?

J'ai parlé trop tôt ! Bien que cela fonctionne pour next dev , next build échoue avec une erreur unknown token . (point) provenant de l'un des fichiers CSS.

@Timer Des idées ? Cela devrait-il fonctionner immédiatement avec un monorepo et plusieurs packages ? Ou y a-t-il autre chose que je dois configurer pour que @team/packageA puisse importer des CSS à partir de node_modules, puis être importé dans @team/packageB ?

Vous pouvez suivre https://github.com/vercel/next.js/issues/13282 pour ce comportement.

En utilisant [email protected], il est possible d'importer du CSS n'importe où dans mon application. Mais la même chose sera-t-elle possible pour les fichiers scss ? Je souhaite importer uniquement les fichiers scss que j'utilise réellement sur une page .

// pages/_app.tsx
import '../styles/common.scss'

// pages/index.tsx j'utilise un Button
import '@mynpm/custom-ui/_Button.scss'

// pages/about.tsx J'utilise un Carrousel
import '@mynpm/custom-ui/_Carousel.scss'

L'exemple sur https://nextjs.org/docs/basic-features/built-in-css-support
Schermata 2020-10-13 alle 16 43 19

Renvoie l'erreur :
erreur - /Users/gp/dev/next-kolumbus/node_modules/@reach/dialog/styles.css
Le CSS global ne peut pas être importé depuis node_modules.
Lire la suite : https://err.sh/next.js/css-npm

L'exemple sur https://nextjs.org/docs/basic-features/built-in-css-support
Schermata 2020-10-13 alle 16 43 19

Renvoie l'erreur :
erreur - /Users/gp/dev/next-kolumbus/node_modules/@reach/dialog/styles.css
Le CSS global ne peut pas être importé depuis node_modules.
Lire la suite : https://err.sh/next.js/css-npm

Assurez-vous que vous utilisez la dernière version de Next.js.

Désolé, je ne l'ai pas précisé dans le commentaire précédent. J'ai utilisé la version 9.5.5. vient de mettre à jour à partir de npm.

J'ai effacé tout le cache .next et maintenant cela fonctionne comme prévu.

L'erreur existe toujours dans la version 9.5.5 , dans _app --> import "react-gauge-chart-nextjs-support/dist/GaugeChart/style.css";

Screenshot 2020-11-12 at 14 12 11

Cette page vous a été utile?
0 / 5 - 0 notes