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

Importing CSS files in Isomorphic React Components

本文关键字:导入 CSS 文件 组件 同构 React      更新时间:2023-09-26

我有一个用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'}
    ]
  }

查看完整的webpack配置文件

详细信息如下:

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

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

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

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

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

你不能在你在服务器上呈现的组件中要求css。处理它的一种方法是在要求css之前检查它是否为浏览器。

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

为了使它成为可能,你应该在服务器上设置process.env.BROWSERfalse(或删除它) server.js

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

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

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

你可以在gpbl的Isomorphic500应用程序中看到这一点。

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

这个小妙处有助于确保用户在页面第一次呈现时看到带有样式的内容。下面是我利用这种技术构建的一个同构应用程序示例。只需搜索@withStyles的代码库,看看它是如何使用的。它就像这样:

import React, { Component, PropTypes } from 'react';
import styles from './ScheduleList.css';
import withStyles from '../../decorators/withStyles';
@withStyles(styles)
class ScheduleList extends Component {

我们的同构应用程序也有类似的问题(以及许多其他问题,您可以在这里找到详细信息)。至于CSS导入的问题,一开始我们使用process.env.BROWSER。后来我们改用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.

下面是一个产品配置的示例。

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

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

我使用这个babel插件成功地解决了一个类似的问题与少,svg和图像。但它应该可以与任何非js资源一起工作。

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

唯一的缺点是它只适用于命名导入,所以你必须:
import styles from './styles.css';

以使其工作。

确保你使用的是webpack配置中的加载器:

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

您可能在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文件。所以巴别塔也不允许你这么做。

我终于意识到这个错误不是起源于编译阶段,而是在运行时。因为这是一个同构应用,所以组件和它们的任何依赖都会首先在服务器上被解析(即在node中)。这就是导致错误的原因。

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

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

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

你不需要直接使用css

你需要你的css classname js文件。

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

此外,这个插件还使用你的类名和文件路径来生成唯一的哈希,以解决css的作用域问题。

你可以试试!

解决这个…

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

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

在.babelrc中包含插件

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

和导入Css.....Like This Anywhere You Want

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

参见This…除了Css文件 ........................................................ .https://www.npmjs.com/package/babel-plugin-transform-assets