web-dev-qa-db-fra.com

Importation de fichiers CSS dans les composants Isomorphic React

J'ai une application React avec des composants écrits en ES6 - transpilés via Babel et Webpack.

Dans certains endroits, je souhaiterais inclure des fichiers CSS spécifiques avec des composants spécifiques, comme suggéré dans react webpack cookbook

Cependant, si dans un fichier de composant, j'ai besoin d'un actif CSS statique, par exemple:

import '../assets/css/style.css';

Ensuite, la compilation échoue avec une erreur:

SyntaxError: <PROJECT>/assets/css/style.css: Unexpected character '#' (3:0)
    at Parser.pp.raise (<PROJECT>\node_modules\babel-core\lib\acorn\src\location.js:73:13)
    at Parser.pp.getTokenFromCode (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:423:8)
    at Parser.pp.readToken (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:106:15)
    at Parser.<anonymous> (<PROJECT>\node_modules\babel-core\node_modules\acorn-jsx\inject.js:650:22)
    at Parser.readToken (<PROJECT>\node_modules\babel-core\lib\acorn\plugins\flow.js:694:22)
    at Parser.pp.nextToken (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:98:71)
    at Object.parse (<PROJECT>\node_modules\babel-core\lib\acorn\src\index.js:105:5)
    at exports.default (<PROJECT>\node_modules\babel-core\lib\babel\helpers\parse.js:47:19)
    at File.parse (<PROJECT>\node_modules\babel-core\lib\babel\transformation\file\index.js:529:46)
    at File.addCode (<PROJECT>\node_modules\babel-core\lib\babel\transformation\file\index.js:611:24)

Il semble que si j'essaie d'exiger un fichier CSS dans un fichier Component, le chargeur Babel l'interprétera comme une autre source et tentera de transcrire le CSS en Javascript.

Est-ce prévu? Y a-t-il un moyen d'y parvenir: autoriser les fichiers transpilés à faire explicitement référence à des actifs statiques qui ne doivent pas être transpilés?

J'ai spécifié des chargeurs pour les actifs .js/jsx et CSS comme suit:

  module: {
    loaders: [
      { test: /\.css$/, loader: "style-loader!css-loader" },
      { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel'}
    ]
  }

Voir le fichier de configuration complet du webpack

Détails complets ci-dessous:

webpack.common.js - Une configuration Webpack de base que j'utilise pour pouvoir partager les propriétés entre dev et production.

Gruntfile.js - Gruntfile utilisé pour le développement. Comme vous pouvez le constater, la configuration Webpack ci-dessus est nécessaire et certaines propriétés de développement y sont ajoutées. Cela pourrait-il causer le problème?

Html.jsx - Mon composant jsx HTML qui tente d'importer/requiert le CSS. Ceci est une application isomorphe (en utilisant Fluxbile ), nécessitant donc d'avoir le code HTML réel en tant que composant rendu. L'utilisation de l'instruction require vue dans ce fichier, quelle que soit la partie de mon application, donne l'erreur décrite. 

Cela semble avoir quelque chose à voir avec le grunt. Si je compile simplement avec webpack --config webpack.common.js, alors je ne reçois aucune erreur. 

Réponse courte: il s'agit d'une erreur d'exécution du noeud. Essayer de charger CSS sur le serveur dans des applications isomorphes n’est pas une bonne idée. 

40
duncanhall

Vous ne pouvez pas exiger de CSS dans le composant que vous restituez sur le serveur. Une façon de régler ce problème consiste à vérifier si c'est un navigateur avant de demander le format CSS.

if (process.env.BROWSER) {
  require("./style.css");
}

Pour rendre cela possible, vous devez définir process.env.BROWSER sur false (ou le supprimer) sur le serveur server.js

delete process.env.BROWSER;
...
// other server stuff

et réglez-le sur true pour le navigateur. Vous le faites avec le DefinePlugin de Webpack dans le config -webpack.config.js

plugins: [
    ...
    new webpack.DefinePlugin({
        "process.env": {
            BROWSER: JSON.stringify(true)
        }
    })
]

Vous pouvez le voir en action dans Isomorphic500 app de gpbl.

64
Viacheslav

Si vous construisez une application isomorphe avec ES6 et souhaitez inclure CSS lors du rendu sur le serveur (il est important de pouvoir envoyer les styles de base au client dans la première réponse HTTP), consultez le décorateur @withStyles ES7 utilisé Réactif Starter Kit.

Cette petite beauté permet aux utilisateurs de voir votre contenu avec les styles lors du premier rendu de la page. Voici un exemple d'application isomorphe Je construis en tirant parti de cette technique. Il suffit de chercher @withStyles dans la base de code pour voir comment il est utilisé. C'est un peu comme ça:

import React, { Component, PropTypes } from 'react';
import styles from './ScheduleList.css';
import withStyles from '../../decorators/withStyles';

@withStyles(styles)
class ScheduleList extends Component {
8
Josh Habdas
6
asdfasdfads

Nous avons eu un problème similaire avec notre application isomorphe (et beaucoup d'autres problèmes, vous pouvez trouver details ici ). En ce qui concerne le problème d’importation CSS, nous utilisions d’abord process.env.BROWSER. Plus tard, nous sommes passés à babel-plugin-transform-require-ignore . Cela fonctionne parfaitement avec babel6. 

Tout ce dont vous avez besoin est d’avoir la section suivante dans votre .babelrc

"env": {
   "node": {
     "plugins": [
       [
         "babel-plugin-transform-require-ignore", { "extensions": [".less", ".css"] }
       ]
     ]
   }
}

Après cela, lancez votre application avec BABEL_ENV = 'node'. Comme ça:

BABEL_ENV='node' node app.js.

Voici un exemple de la manière dont une configuration de production peut ressembler.

5
koorchik

J'ai utilisé ce plugin babel avec succès pour résoudre un problème similaire avec less, svg et des images. Mais cela devrait fonctionner avec tous les actifs non js.

Il réécrit toutes les importations d'actifs dans des variables. Par conséquent, tant que vous exécutez le code compilé uniquement sur le serveur et créez un ensemble construit avec Webpack pour le client, tout devrait bien se passer.

Le seul inconvénient est qu'il ne fonctionne qu'avec des importations nommées, vous devez donc:

import styles from './styles.css';

afin de le faire fonctionner.

2
Raul Matei

Assurez-vous que vous utilisez les chargeurs dans votre configuration Webpack: 

  module: {
     loaders: [
        { test: /\.jsx$/, exclude: /node_modules/, loader: "babel" },
        { test: /\.css$/, loader: "style!css" }
     ]
  }
1
gpbl

Vous avez probablement une erreur dans votre configuration Webpack dans laquelle vous utilisez le babel-loader pour tous les fichiers, et pas seulement les fichiers .js. Vous souhaitez utiliser un chargeur CSS pour les fichiers .css.

Mais vous ne devriez pas utiliser import pour charger un autre module que les modules Javascript, car une fois les importations implémentées dans les navigateurs, vous ne pourrez importer que des fichiers Javascript. Utilisez plutôt require dans les cas où vous avez besoin de fonctionnalités spécifiques à Webpack.

ORIGINAL POST

Webpack utilise require et Babel vous permet d’utiliser import de ES6 qui font généralement la même chose (et Babel transforme l’import en une instruction require), mais ils ne sont pas interchangeables. La fonction Webpacks require vous permet de spécifier davantage que le nom d'un module, elle vous permet également de spécifier des chargeurs, ce que vous ne pouvez pas faire avec ES6 imports. Donc, si vous voulez charger un fichier CSS, vous devriez utiliser require au lieu de import.

La raison en est que Babel est simplement un transpiler pour ce qui va arriver dans ES6, et ES6 ne vous autorisera pas à importer des fichiers CSS. Babel ne vous permettra pas non plus de le faire.

1
Anders Ekdahl

J'ai finalement réalisé que cette erreur ne provient pas de la compilation, mais de l'exécution. Comme il s'agit d'une application ismorphic, les composants et leurs dépendances seront d'abord analysés sur le serveur (c'est-à-dire dans le nœud). C'est ce qui cause l'erreur.

Merci pour toutes les suggestions. J'en posterai plus si/quand je découvrirai comment avoir des feuilles de style par composant dans une application isomorphe. 

0
duncanhall

J'ai également rencontré le même problème lorsque je souhaite effectuer le rendu côté serveur.

J'écris donc un plugin postcss, postcss-hash-classname .

Vous n'avez pas besoin de css directement.

Vous avez besoin de votre fichier js css classname.

Comme tout ce dont vous avez besoin est un fichier js, vous pouvez effectuer le rendu côté serveur comme d'habitude.

En outre, ce plugin utilise également votre nom de classe et votre chemin de fichier pour générer un hachage unique afin de résoudre le problème de portée css.

Tu peux l'essayer!

0
Chen-Tai Hou