在同构 React 组件中导入 CSS 个文件

Importing CSS files in Isomorphic React Components

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

在某些地方,我想包含具有特定组件的特定 CSS 文件,如 react webpack cookbook

中所建议

但是,如果在任何组件文件中我需要静态 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 加载器会将其解释为另一个源并尝试将 CSS 转换为 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 - My HTML jsx component that tries to import/require the CSS. This is an isomorphic app (using Fluxbile),因此需要将实际的 HTML 作为渲染组件。在我的应用程序的任何部分中使用此文件中看到的 require 语句都会给出所述错误。

好像跟grunt有关系。如果我只是用 webpack --config webpack.common.js 编译,那么我不会出错。

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

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

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

原版POST

Webpack 使用 require,而 Babel 允许您使用 ES6 中的 import,它们主要做同样的事情(Babel 将导入转换为 require 语句),但它们不可互换。 Webpacks require 函数不仅可以指定模块名称,还可以指定加载器,这是 ES6 imports 无法做到的。所以如果你想加载一个 CSS 文件,你应该使用 require 而不是 import.

原因是 Babel 只是 ES6 中的转译器,而 ES6 不允许导入 CSS 文件。所以 Babel 也不允许你这样做。

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

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

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

感谢所有建议,我会 post 更多 if/when 我想出了如何在同构应用程序中拥有每个组件的样式表。

您不能在服务器上呈现的组件中要求 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 的 Isomorphic500 应用程序中看到这一点。

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

这个小细节有助于确保用户在首次呈现页面时看到您的内容带有样式。这是我正在构建的 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 {

你也可以试试这个 https://github.com/halt-hammerzeit/webpack-isomorphic-tools

或者这个 https://github.com/halt-hammerzeit/webpack-react-redux-isomorphic-render-example

我在做服务端渲染的时候也遇到了同样的问题

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

您不需要直接 css。

您需要 css 类名 js 文件。

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

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

你可以试试!

我使用这个 babel plugin 成功解决了 less、svg 和图像的类似问题。但它应该适用于任何非 js 资产。

它将所有导入的资产重写到变量中,所以只要你 运行 编译后的代码只是在服务器上并且有一个用 webpack 为客户端构建的包,它应该没问题。

唯一的缺点是它只适用于命名导入,所以你必须:

import styles from './styles.css';

为了让它发挥作用。

我们的同构应用程序遇到了类似的问题(还有很多其他问题,您可以找到 details here). As for the problem with CSS import, at first, we were using process.env.BROWSER. Later we've switched to babel-plugin-transform-require-ignore。它与 babel6 完美配合。

您只需要在 .babelrc 中包含以下部分

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

之后 运行 您的应用 BABEL_ENV='node'。像那样:

BABEL_ENV='node' node app.js.

Here is 生产配置的示例。

用这个解决了...

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