Next.js: Importación de CSS con el alcance correcto de node_modules fuera de _app

Creado en 21 abr. 2020  ·  49Comentarios  ·  Fuente: vercel/next.js

Informe de error

Describe el error

No es posible importar una hoja de estilo de un paquete en una página, porque a continuación se produce este error:

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

Si bien entiendo de dónde proviene esto, hace que la división de código sea imposible. Si importo un componente de una biblioteca de componentes, también necesito importar el CSS. Puede haber bibliotecas que no alcancen correctamente sus selectores, pero eso no debería impedirme sobrescribir esta advertencia. El CSS que se importa de una biblioteca no es inherentemente "global".

Reproducir

  1. import "my-library/index.css"
  2. yarn dev
  3. Me sale el error de arriba

Comportamiento esperado

El archivo debe importarse.

Veo estas posibles soluciones:

  • Bandera global en next.config.js
  • Comentario de anotación en la importación
  • Advertir en lugar de bloquearlo por completo
  • Compruebe si el CSS solo contiene selectores de ámbito

Contexto adicional

Ha habido discusiones previas sobre esto.

Del blog

Dado que las hojas de estilo son globales por naturaleza, deben importarse en elcomponente. Esto es necesario para evitar conflictos de orden y nombre de clase para estilos globales.

No estoy de acuerdo con esta declaración, el razonamiento es que una biblioteca externa puede usar módulos CSS y empaquetarlos como un archivo CSS para importar. Lo cual es una práctica perfectamente válida y común y no tiene efectos secundarios .

N.º 10059

Este problema se cerró porque la importación global en _app es la opción correcta allí.
Este comentario describe el problema exacto, pero no ha habido ninguna respuesta, ya que el problema está cerrado. Sin embargo, el comentario obtuvo muchas reacciones positivas, así que supongo que no soy el único con este problema.

N.º 10975

Parece no tener ninguna relación.

# 9830

Puede estar relacionado, pero no estoy seguro.

Mi caso de uso

Escribo artículos extensos con muchas ilustraciones personalizadas e ilustraciones interactivas. Los artículos utilizan paquetes npm privados con componentes react que renderizan SVG con bastante CSS. Estos paquetes usan módulos CSS y exportan index.js y index.css . Agregar todos los archivos CSS a _app hace que se cargue todo el CSS, incluso si las personas están en la página de inicio, el formulario de contacto o cualquier otro artículo, aunque esté 100% sin usar. También va en contra de que el sistema de archivos se encargue de sus páginas porque casi todas las páginas corresponden a una importación de CSS en _app .

story 8 feature request

Comentario más útil

¡Vamos a permitir la importación de CSS desde node_modules a cualquier archivo de componentes durante la próxima semana (en canary)! Publicaremos aquí cuando esté listo para probar.

Todos 49 comentarios

Estoy enfrentando este mismo problema simplemente tratando de usar Linaria, que tiene sus propios nombres de clase. Aunque los archivos css que produce no terminan en .module.css , son "módulos". Necesito una forma sencilla de integrarme con la biblioteca.

¿Por qué incluso cambiaste a nextjs de nuevo?

También me gustaría poder usar GlobalCSS fuera de node_modules. Esto nos ayudaría a adoptar módulos CSS de forma incremental.

¡Sí, esto es muy importante! muchos paquetes npm no funcionan con nextjs pero funcionan con CRA u otros marcos

Para cualquier otra persona que esté tratando de usar esto con la implementación js de dart sass para cosas como @use soporte y módulos sass, si tiene -cualquier- otro módulo de nodo que tiene una dependencia en node-sass, la siguiente configuración predeterminada usará node-sass en lugar de sass. Localmente lo solucioné haciendo lo siguiente:

// 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');
            }
          }
        })
  }
}

Luego, deberá importar sus archivos scss en _app.js .

@smurrayatwork esto es hackear no codificar lo siento

Además, la restricción de que sea exclusivamente _app.js es un poco engorrosa.

Si no vamos a admitir referencias CSS en todas partes, ¿podríamos hacer que CSS también pueda ser referenciado por dependencias directas de _app (que no están referenciadas en ningún otro lugar)?
es decir. Está bien si lo requiere _app (y en ningún otro lugar), lo que le daría al CSS un orden determinista basado en las importaciones.

No es ideal, sin embargo, el caso de uso que tengo es que tengo una base de código compartida por varias aplicaciones que importan un módulo compartido que importa CSS compartido. Odiaría duplicar esas importaciones CSS compartidas en _app.js para cada aplicación. Actualmente, para evitar eso, tendría que hacer una metaprogramación js elegante porque no podemos requerir css en otros módulos.

En su lugar, me gustaría trabajar con mi enfoque actual, que es que tengo una "Fábrica de aplicaciones" que importa todo el CSS compartido. _app luego usa la fábrica e importa su propio CSS además de los compartidos.

Estoy agregando https://github.com/vercel/next.js/discussions/13991 ya que creo que se relaciona con este problema.

+100 a esto. Tengo que copiar y pegar archivos css del módulo de nodo en mi proyecto y agregar un .module.css en ellos

He aquí otro ejemplo.

En el caso del paquete pdf-viewer-reactjs sus dependencias requieren CSS que también debe importarse desde _app.js .

Esto está inflando el CSS para toda la aplicación y no estoy seguro de los conflictos en esta etapa.

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

Además, lo siguiente se envía a la consola:

advertir - ./node_modules/material-design-icons/iconfont/material-icons.css
No se puede importar CSS global desde dentro de node_modules.
Leer más: https://err.sh/next.js/css-npm
Ubicación: node_modules / pdf-viewer-reactjs / dist / pdf-viewer-reactjs.js

./node_modules/bulma/css/bulma.css
No se puede importar CSS global desde dentro de node_modules.
Leer más: https://err.sh/next.js/css-npm
Ubicación: node_modules / pdf-viewer-reactjs / dist / pdf-viewer-reactjs.js

./node_modules/bulma-helpers/css/bulma-helpers.min.css
No se puede importar CSS global desde dentro de node_modules.
Leer más: https://err.sh/next.js/css-npm
Ubicación: node_modules / pdf-viewer-reactjs / dist / pdf-viewer-reactjs.js

./node_modules/material-design-icons/iconfont/material-icons.css
Error de compilación del módulo: Error: el cargador final (./node_modules/next/dist/build/webpack/loaders/error-loader.js) no devolvió un búfer o una cadena

./node_modules/bulma/css/bulma.css
Error de compilación del módulo: Error: el cargador final (./node_modules/next/dist/build/webpack/loaders/error-loader.js) no devolvió un búfer o una cadena

./node_modules/bulma-helpers/css/bulma-helpers.min.css
Error de compilación del módulo: Error: el cargador final (./node_modules/next/dist/build/webpack/loaders/error-loader.js) no devolvió un búfer o una cadena

Hola ! ¿Alguien resolvió esto y cómo? Tantos módulos de nodo que no puedo importar por eso.

Tal vez el uso de estilos globales en los componentes podría activarse a través de next.config.js , o podría mostrarse una advertencia de consola desagradable contra los estilos globales, en caso de que haya preocupación por romper con las mejores prácticas / opiniones de NextJS.

Pero esto es importante para los usuarios que realizan conversiones de CRA> NextJS. Es un bloqueador para nosotros porque no podemos cambiar y luego adoptar incrementalmente cosas como módulos CSS.

Todavía no puedo evitar esto. Para mis propias necesidades, utilicé un controlador CSS personalizado, pero esto deshabilita el soporte CSS incorporado, pero puede que no sea una buena solución para todos los casos. Se desaconseja lo siguiente , utilícelo solo hasta que los autores del paquete lo resuelvan

next.config.js

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

@abdelrahmantoptal 's ¿Sabes cómo hacer que eso funcione para SASS?

Parece que funcionaría para CSS, pero arroja un error al encontrar una importación de 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 {

así que intenté agregar un cargador SASS a la configuración del paquete web antes de usar el complemento 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'
        ]
      });

Pero eso causó:

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

También intenté sustituir @zeit/next-sass , pero eso causó el mismo error:

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

¿Alguna sugerencia sobre cómo modificar su código para usar SASS?

Ahora he descartado a Gatsby y pronto a Next.js debido a sus características pequeñas, pero muy bloqueadoras, obstinadas como esta. Ahora no puedo usar el complemento CodeBlock para CKEditor 5 porque no puedo evitar este error. Siempre debería haber alguna forma de rodear estas configuraciones.

Sería muy útil tener noticias de @Timer o alguien de Vercel sobre este problema. Este es un gran problema con Next.js. ¿Algo está planeado para solucionar esto?

¡Acordado! Es increíblemente común tener CSS en módulos de nodo. Como desarrollador, no tengo control sobre cómo otros desarrolladores estructuran sus módulos de nodo, y otros desarrolladores no esperan que poner css en un módulo de nodo rompa un marco web.

@OssiPesonen, ¿ ya has visto esto ? Esta solución no es ideal, pero me resolvió el problema mientras tanto.

@OssiPesonen, ¿ ya has visto esto ? Esta solución no es ideal, pero me resolvió el problema mientras tanto.

¿No veo cómo esto ayuda? El problema no es que tenga que importar manualmente algunos archivos CSS de los módulos de nodo. El problema es que los paquetes npm hacen la importación de CSS por sí mismos. Un paquete que incluye una fila como esta:

import '../theme/stylesheet.css'

Hará que next.js se bloquee con fuerza. Y aparentemente el consejo del mantenedor es:

Comuníquese con el mantenedor y pídale que publique una versión compilada de su dependencia.

¿En qué tipo de país de fantasía vive la gente en el que imagina que puede ponerse en contacto con los mantenedores y pedirles que recompilen su paquete para usted a un ritmo muy rápido? ¡Esto obstaculizará a cualquiera durante semanas! Este boleto ha estado abierto durante 4 meses. Eso es inaceptable cuando se trabaja en proyectos que se mueven rápidamente.

¡Vamos a permitir la importación de CSS desde node_modules a cualquier archivo de componentes durante la próxima semana (en canary)! Publicaremos aquí cuando esté listo para probar.

Si alguien necesita esto antes del lanzamiento, pude usar el complemento next-transpile-modules para transpilar el módulo de node_modules que estaba importando CSS. Funcionó como un encanto para mí.

@BrandonE parece que next-transpile-modules aún necesita tener los módulos llamados *.module.css . ¿Encontraste una forma de evitar eso?

@rjoaopereira No puedo decir que tenga un conocimiento profundo de cómo funciona esto, pero la mayoría de mis node_modules que importaron CSS solo funcionaron con el complemento @zeit/next-css . Solo uno no lo hizo, momento en el que la transpilación solucionó el problema. Lejos de ser una solución elegante, y espero que las futuras versiones de Next.js nos permitan dedicar menos tiempo a la alquimia de Babel / Webpack y más a la creación de aplicaciones web.

Conseguí esto casi funcionando con los siguientes cambios.

siguiente 9.5.3
siguiente-transpile-módulos 4.1.0
Componentes de primera parte con emoción.
Componentes de terceros con una combinación de módulos CSS y CSS global

scopedcomponents se reemplazará con los componentes de terceros que se estén utilizando

//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;
    }
  });
};

Problemas:

@Timer ¿ alguna actualización sobre esto?

¡Vamos a permitir la importación de CSS desde node_modules a cualquier archivo de componentes durante la próxima semana (en canary)! Publicaremos aquí cuando esté listo para probar.

¿Habrá una importación dinámica de CSS desde un componente después de esta corrección?

Muchas gracias @Timer

next@^9.5.4-canary.10 ahora le permite importar CSS global desde node_modules en cualquier lugar de su aplicación. Esto mejora la interoperabilidad con bibliotecas React de terceros que requieren que importe su CSS, pero no quiere que aumente el tamaño del paquete para toda su aplicación.

@Timer No puedo esperar a tener ese lanzamiento, realmente aprecio tu trabajo 💯 ❤️

¡Gracias @Timer !

Este ha sido un problema de bloqueo para mí actualmente, sin embargo, cuando lo probé hoy, todavía veo el mismo mensaje de error. ¿Hay algo más que simplemente actualizar a 9.5.4-canary-10? Este ejemplo está intentando utilizar lib @rmwc de terceros

image

@johmike ¿Está importando utilizando la siguiente sintaxis?

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

¿Intentó reiniciar el servidor de desarrollo después de instalar la última versión de next ?

@Timer Muchas gracias por esta función. Funciona muy bien para importar archivos CSS desde la carpeta node_modules .

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

¿Algún plan para admitir la importación de CSS global fuera del directorio node_modules ?

@sasivarnan
Esto proviene de otra biblioteca que está importando los componentes de @rmwc . Esa biblioteca está usando @require("@rmwc/avatar/avatar.css") . Estoy importando import {Avatar} from "library/Avatar" y eso está fallando.

@sasivarnan

Esto proviene de otra biblioteca que está importando los componentes de @rmwc . Esa biblioteca está usando @require("@rmwc/avatar/avatar.css") . Estoy importando import {Avatar} from "library/Avatar" y eso está fallando.

Entendido. Pensé que se había importado directamente a su aplicación. Mi error.

A juzgar por los comentarios aquí, esto en realidad no está resuelto o se resolvió, pero muchas personas aquí informan un problema diferente. Mucha gente todavía no puede importar módulos, que importan CSS desde el propio paquete (una declaración import style.css dentro de un archivo de paquete).

La solución parece permitir que la aplicación importe CSS desde la ruta node_modules/ , pero hay una manera bastante fácil de evitar esto: simplemente copie el CSS en su aplicación por ahora hasta que se solucione. No es un problema de nivel de bloqueador. Por lo tanto, no resolvió realmente el problema del bloqueador para el que no hay una solución fácil. Si importa un componente que tiene una declaración de importación a un archivo CSS que contiene el paquete, la aplicación se bloquea.

@sasivarnan @OssiPesonen , ambos parecen estar hablando de un problema diferente al que se discutió y solucionó en este problema de OP.

Esto corrige específicamente las bibliotecas que requieren que importe su CSS en su aplicación, por ejemplo:

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

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

De lo que estás hablando es de un duplicado de # 706 y # 13282, o de la capacidad de tratar node_modules como un código propio.

@Timer Acabo de probar el caso de uso esperado y de hecho funciona bien.

Cuando importo el css en un componente directamente como parte de la siguiente estructura, funciona como se esperaba, sin errores.
Sin embargo, si muevo ese componente a otro paquete fuera de la siguiente estructura, compilo y luego instalo ese paquete, vuelve al mismo error que antes.

Es posible que esté sucediendo algo más, ya que ni siquiera estoy usando el componente Avatar en este ejemplo, estoy importando Button y, sin embargo, Avatar es el error.

image

También agregué next-transpile-modules ya que estamos trabajando desde un monorepo, pero eso no pareció ayudar con este problema en particular.

Conseguí que esto funcionara mediante un archivo de configuración extraño al buscar en un montón de otros problemas relacionados con next-transpile-modules .

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

Eliminé next-transpile-modules y esto funciona. No tengo idea de por qué, parece que no debería hacer nada.

¡Hablé demasiado pronto! Si bien eso funciona para next dev , next build falla con un error unknown token . (punto) de uno de los archivos CSS.

@Timer ¿ Alguna idea? ¿Debería funcionar de inmediato con un monorepo y varios paquetes? ¿O hay algo más que necesito configurar para que @ team / packageA pueda importar css desde node_modules y luego ser importado a @ team / packageB?

Puede seguir https://github.com/vercel/next.js/issues/13282 para conocer ese comportamiento.

Usando [email protected] es posible importar css en cualquier lugar de mi aplicación. Pero, ¿será posible lo mismo para los archivos scss? Me gustaría importar solo los archivos scss que estoy usando en una página .

// páginas / _app.tsx
import '../styles/common.scss'

// páginas / index.tsx uso un botón
import '@mynpm/custom-ui/_Button.scss'

// pages / about.tsx Yo uso un carrusel
import '@mynpm/custom-ui/_Carousel.scss'

El ejemplo en https://nextjs.org/docs/basic-features/built-in-css-support
Schermata 2020-10-13 alle 16 43 19

Devuelve el error:
error - /Users/gp/dev/next-kolumbus/node_modules/@reach/dialog/styles.css
No se puede importar CSS global desde dentro de node_modules.
Leer más: https://err.sh/next.js/css-npm

El ejemplo en https://nextjs.org/docs/basic-features/built-in-css-support
Schermata 2020-10-13 alle 16 43 19

Devuelve el error:
error - /Users/gp/dev/next-kolumbus/node_modules/@reach/dialog/styles.css
No se puede importar CSS global desde dentro de node_modules.
Leer más: https://err.sh/next.js/css-npm

Asegúrese de tener la última versión de Next.js.

Lo siento, no lo especifiqué en el comentario anterior. Usé la versión 9.5.5. recién actualizado de npm.

Borré todo el caché .next y ahora funciona como se esperaba.

El error sigue estando en la versión 9.5.5 , en _app -> import "react-gauge-chart-nextjs-support/dist/GaugeChart/style.css";

Screenshot 2020-11-12 at 14 12 11

¿Fue útil esta página
0 / 5 - 0 calificaciones