在Isomorphic React组件中导入CSS文件

时间:2015-05-20 10:59:59

标签: javascript reactjs webpack babeljs

我有一个使用ES6编写的组件的React应用程序 - 通过Babel和Webpack进行编译。

在某些地方,我想按照react webpack cookbook

的建议,在特定组件中加入特定的CSS文件

但是,如果在任何组件文件中我需要静态CSS资源,例如:

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

然后编译失败并出现错误:

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)

似乎如果我尝试在组件文件中需要一个CSS文件,那么Babel加载器会将其解释为另一个源并尝试将CS​​S转换为Javascript。

这是预期的吗?有没有办法实现这一点 - 允许转换文件显式引用不被转换的静态资产?

我已经为.js / jsx和CSS资产指定了加载器,如下所示:

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

查看full webpack config file

以下详细信息:

webpack.common.js - 我使用的基本webpack配置,因此我可以在开发和生产之间共享属性。

Gruntfile.js - 用于开发的Gruntfile。正如您所看到的,它需要上面的webpack配置并为其添加一些开发属性。这会导致问题吗?

Html.jsx - 我的HTML jsx组件试图导入/需要CSS。这是一个同构应用程序(使用Fluxbile),因此需要将实际的HTML作为呈现的组件。使用此文件中的require语句,在我的应用程序的任何部分中,都会给出所描述的错误。

这似乎与grunt 有关。如果我只是用webpack --config webpack.common.js编译,那么我没有错误。

简短回答:这是一个节点运行时错误。尝试在同构应用程序中加载服务器上的CSS并不是一个好主意。

10 个答案:

答案 0 :(得分:66)

您无法在要在服务器上呈现的组件中使用css。处理它的一种方法是在要求css之前检查它是否是浏览器。

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

为了使其成为可能,您应该在服务器上将process.env.BROWSER设置为false(或删除它) server.js

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

并将其设置为true以用于浏览器。你可以在配置中使用webpack的DefinePlugin来实现 - webpack.config.js

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

您可以在gpbl&#39; Isomorphic500应用中看到这一点。

答案 1 :(得分:9)

如果您正在使用ES6构建同构应用程序并希望在服务器上呈现时包含CSS(重要的是可以在第一个HTTP响应中将基本样式发送到客户端),请查看@withStyles ES7 React Starter Kit中使用的装饰器。

这个小小的美容有助于确保用户在首次呈现页面时看到带有样式的内容。这是example isomorphic app我正在利用这种技术建造的。只需在@withStyles的代码库中搜索,看看它是如何使用的。它有点像这样:

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

@withStyles(styles)
class ScheduleList extends Component {

答案 2 :(得分:6)

答案 3 :(得分:6)

我们的同构应用程序遇到了类似的问题(还有很多其他问题,你可以找到details here)。至于CSS导入的问题,起初我们使用的是process.env.BROWSER。后来我们切换到babel-plugin-transform-require-ignore。它与babel6完美配合。

您只需要在.babelrc

中包含以下部分
"env": {
   "node": {
     "plugins": [
       [
         "babel-plugin-transform-require-ignore", { "extensions": [".less", ".css"] }
       ]
     ]
   }
}

之后使用BABEL_ENV =&#39;节点&#39;运行您的应用。像那样:

BABEL_ENV='node' node app.js.

Here is生产配置的外观示例。

答案 4 :(得分:2)

我使用此babel plugin成功解决了与less,svg和images相似的问题。但它应该适用于任何非js资产。

它将所有资产导入重写为变量,因此只要您在服务器上运行已编译的代码并使用webpack为客户端构建一个包,就应该没问题。

唯一的缺点是它只与命名导入一起使用,因此您必须:

import styles from './styles.css';

为了使其发挥作用。

答案 5 :(得分:1)

您的Webpack配置中可能有一个错误,您对所有文件使用babel-loader,而不仅仅是.js个文件。您想为.css文件使用css加载程序。

但是你不应该使用import来加载除Javascript模块之外的任何其他模块,因为一旦在浏览器中实现导入,你将只能导入Javascript文件。如果您需要Webpack特定功能,请使用require

原始帖子

Webpack使用require,而Babel允许您使用来自ES6的import,它们主要执行相同的操作(并且Babel将导入转换为require语句),但它们不可互换。 Webpacks require函数允许您指定的不仅仅是模块名称,它还允许您指定加载器,而不能使用ES6 import。因此,如果您要加载CSS文件,则应使用require代替import

原因是Babel只是改编ES6中的内容,而ES6不允许您导入CSS文件。因此,巴贝尔也不会允许你这样做。

答案 6 :(得分:1)

确保您在webpack配置中使用加载器:

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

答案 7 :(得分:0)

我终于意识到这个错误不是源于编译阶段,而是源于运行时。因为这是一个异形应用程序,所以它们具有的组件和任何依赖项将首先在服务器上解析(即在节点中)。正是这导致了错误。

感谢所有建议,如果/当我弄清楚如何在同构应用程序中使用每个组件样式表时,我会发布更多内容。

答案 8 :(得分:0)

当我想进行服务器端渲染时,我也遇到了同样的问题。

所以我写了一个postcss插件,postcss-hash-classname

您不需要直接使用css。

您需要css classname js文件。

因为你需要的只是js文件,你可以像往常一样进行服务器端渲染。

此外,此插件还使用您的类名和文件路径生成唯一的哈希来解决CSS范围问题。

你可以尝试一下!

答案 9 :(得分:0)

解决了这个问题...

https://github.com/michalkvasnicak/babel-plugin-css-modules-transform

$ npm install --save-dev babel-plugin-css-modules-transform

在.babelrc中包含插件

{
    "plugins": ["css-modules-transform"]
}

然后导入Css .....在任何您想要的地方

const styles = require('./test.css');
OR
import css from './styles.css'

也请参阅此...除了CSS文件.................................. ................... https://www.npmjs.com/package/babel-plugin-transform-assets