【问题标题】:Importing CSS files in Isomorphic React Components在同构 React 组件中导入 CSS 文件
【发布时间】:2015-08-01 14:03:10
【问题描述】:

我有一个使用 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 加载器会将其解释为另一个源并尝试将 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 - 我的 HTML jsx 组件尝试导入/需要 CSS。这是一个同构应用程序(使用Fluxbile),因此需要将实际的 HTML 作为渲染组件。在我的应用程序的任何部分使用此文件中看到的 require 语句,都会给出描述的错误。

好像和咕噜声有关。如果我只是用webpack --config webpack.common.js 编译,那么我不会收到任何错误。

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

【问题讨论】:

  • 你的配置没问题。我尝试在包含 css 的应用程序上运行它并且它有效。检查其他东西-也许您使用完全不同的配置文件运行 webpack :) 或者软件包有问题。发布更多信息 - 你的 package.json,你如何运行 webpack 等等。也许我们会弄清楚。
  • 谢谢,我在上面提供了更多信息。这个问题似乎是在咕噜声中引起的,因为直接通过 webpack 编译就可以了。
  • 在 gruntfile 中 console.log() 你的 webpackConfig 可能会很有趣

标签: javascript reactjs webpack babeljs


【解决方案1】:

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

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

原帖

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

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

【讨论】:

  • 谢谢 - 不幸的是,情况似乎并非如此。用 require 语句替换 import 语句会给出完全相同的错误。这主要是我所期望的 - 如果 Babel 将 import 转换为 require 然后我们看到错误,首先使用 require 会产生相同的错误。
  • 您的 Webpack 配置中可能有一个错误,您将 babel-loader 用于所有文件,而它应该只用于 .js 文件。
  • babel-loader 不解析需要,webpack 可以。所以 import 一个 css 文件是可以的,只要 webpack 使用 css 加载器。
  • @gpbl 非常正确,我的错误。我会更新帖子,但 importrequire 仍然不能互换,因为一旦它们被支持,你就不能使用真正的 ES6 导入。
  • 谢谢,请查看对显示我的装载机的原始帖子的编辑。我有两种文件类型的加载器,但仍然看到需要/导入的错误。
【解决方案2】:

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

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

【讨论】:

  • 谢谢,问题不在于缺少 laoder,我有这些。问题是 Babel 看到 import / require 语句并试图将 CSS 作为“可转换”源资产导入。
  • 没有一些代码/配置很难说,但似乎 webpack 正在将 .css 文件传递​​给 babel-loader:它不应该。如果是这样,我相信你的配置有问题。
  • 谢谢,我在原帖中添加了完整配置文件的链接。如果您能看到其中的任何问题,我们将不胜感激。
【解决方案3】:

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

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

【讨论】:

  • 你最终选择了什么样的解决方案——装饰器、条件逻辑或其他? Imo 条件逻辑似乎有点 hacky,装饰器看起来有点不对劲。我觉得可能有一个解决方案可以通过配置 babel 来处理这个问题。
【解决方案4】:

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

【讨论】:

  • 一百万次是的!谢谢。
  • 我想我遇到了同样的问题,但是必须用这样的条件逻辑包装 .css 导入似乎真的很难看。还有其他解决方案吗? @snegostup
  • 我相信有一种方法可以在服务器端导入 css 等,但需要使用单独的配置将您的服务器端代码与 Webpack 捆绑到客户端 bundle.js 我不使用的配置中我不喜欢使用装饰器的选项,我也不喜欢在最终用户禁用 Javascript 的情况下只能在客户端要求非 JS 模块的想法。我目前正在研究 Webpack Server-Side 的细节
  • stackoverflow.com/questions/60473782/…。请也回答这个问题,或者对此查询的任何见解表示赞赏。
【解决方案5】:

如果您正在使用 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 {

【讨论】:

    【解决方案6】:

    【讨论】:

    • 惊讶于这个答案没有更多的支持,似乎 webpack-isomorphic-tools 是理想的解决方案
    【解决方案7】:

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

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

    您不需要直接使用 css。

    您需要您的 css 类名 js 文件。

    因为你只需要js文件,你可以照常进行服务端渲染。

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

    你可以试试!

    【讨论】:

      【解决方案8】:

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

      它将所有资产导入重写为变量,因此只要您仅在服务器上运行已编译的代码并为客户端使用 webpack 构建捆绑包,就可以了。

      唯一的缺点是它仅适用于命名导入,因此您必须:

      import styles from './styles.css';
      

      为了让它工作。

      【讨论】:

        【解决方案9】:

        我们的同构应用程序也遇到了类似的问题(还有很多其他问题,您可以找到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='node' 运行您的应用。像这样:

        BABEL_ENV='node' node app.js.
        

        Here is 一个生产配置的示例。

        【讨论】:

        • 或者您可以在为服务器加载的 'babel-register's 选项中启用它(以免与环境变量混淆): require("babel-register")({ plugins: [ [ "transform -require-ignore", {"extensions": [".css"]} ] ] })
        【解决方案10】:

        解决了这个...

        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

        【讨论】:

        • 这并不能解决我最初描述的问题,据我所知,这可能会使情况变得更糟。您不应该将 CSS 注入服务器端运行时。
        猜你喜欢
        • 2017-02-12
        • 2021-04-11
        • 2016-11-02
        • 2018-04-18
        • 1970-01-01
        • 2021-01-30
        • 2021-03-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多