Javascript 在同构 React 组件中导入 CSS 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30347722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Importing CSS files in Isomorphic React Components
提问by duncanhall
I have a React application with Components written in ES6 - transpiled via Babel and Webpack.
我有一个带有用 ES6 编写的组件的 React 应用程序 - 通过 Babel 和 Webpack 转译。
In some places I would like to include specific CSS files with specific Components, as suggested in react webpack cookbook
在某些地方,我想包含具有特定组件的特定 CSS 文件,如react webpack 食谱中所建议的
However, if in any Component file I require a static CSS asset, eg:
但是,如果在任何组件文件中我需要一个静态 CSS 资产,例如:
import '../assets/css/style.css';
import '../assets/css/style.css';
Then the compilation fails with an error:
然后编译失败并出现错误:
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)
It seems that if I try and require a CSS file in a Component file, then the Babel loader will interpret that as another source and try to transpile the CSS into Javascript.
似乎如果我尝试在组件文件中需要一个 CSS 文件,那么 Babel 加载器会将其解释为另一个源并尝试将 CSS 转换为 Javascript。
Is this expected? Is there a way to achieve this - allowing transpiled files to explicitly reference static assets that are not to be transpiled?
这是预期的吗?有没有办法实现这一点 - 允许转译的文件显式引用不需要转译的静态资产?
I have specified loaders for both .js/jsx and CSS assets as follows:
我为 .js/jsx 和 CSS 资产指定了加载器,如下所示:
module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel'}
]
}
View the full webpack config file
FULL DETAILS BELOW:
详细信息如下:
webpack.common.js- A base webpack config I use, so I can share properties between dev and production.
webpack.common.js- 我使用的基本 webpack 配置,因此我可以在开发和生产之间共享属性。
Gruntfile.js- Gruntfile used for development. As you can see it requires the webpack config above and adds some development properties to it. Could this be causing the problem?
Gruntfile.js- 用于开发的 Gruntfile。如您所见,它需要上面的 webpack 配置并为其添加一些开发属性。这会导致问题吗?
Html.jsx- My HTML jsx component that tries to import/require the CSS. This is an isomorphic app (using Fluxbile), hence needing to have the actual HTML as a rendered component. Using the require statement seen in this file, in any part of my application, gives the error described.
Html.jsx- 我尝试导入/需要 CSS 的 HTML jsx 组件。这是一个同构的应用程序(使用Fluxbile),因此需要将实际的 HTML 作为渲染组件。使用此文件中的 require 语句,在我的应用程序的任何部分,都会给出所描述的错误。
It seems to be something to do with grunt. If I just compile with webpack --config webpack.common.jsthen I get no errors.
这似乎与 grunt 有关。如果我只是编译,webpack --config webpack.common.js那么我不会出错。
Short answer: It's a node runtime error. Trying to load CSS on the server in isomorphic apps is not a good idea.
简短回答:这是一个节点运行时错误。尝试在同构应用程序中的服务器上加载 CSS 不是一个好主意。
回答by Viacheslav
You can't require css in the component that you are rendering on the server. One way to deal with it is to check if it's a browser before requiring css.
您不能在服务器上呈现的组件中要求 css。处理它的一种方法是在需要 css 之前检查它是否是浏览器。
if (process.env.BROWSER) {
require("./style.css");
}
In order to make it possible you should set process.env.BROWSERto false(or delete it) on the server
server.js
为了使人们有可能,你应该设置process.env.BROWSER到false(或删除)在服务器
server.js
delete process.env.BROWSER;
...
// other server stuff
and set it to truefor the browser. You do it with webpack's DefinePlugin in the config -
webpack.config.js
并将其设置true为浏览器。你可以在配置中使用 webpack 的 DefinePlugin -
webpack.config.js
plugins: [
...
new webpack.DefinePlugin({
"process.env": {
BROWSER: JSON.stringify(true)
}
})
]
You can see this in action in gpbl's Isomorphic500app.
您可以在行动gpbl我们看看这个Isomorphic500应用。
回答by Josh Habdas
If you're building an isomorphic app with ES6 and want to include CSS when rendering on the server (important so basic styles can be sent down to the client in the first HTTP response) check out the @withStylesES7 decorator used in React Starter Kit.
如果您正在使用 ES6 构建同构应用程序,并希望在服务器上渲染时包含 CSS(重要的是可以在第一个 HTTP 响应中将基本样式发送到客户端),请查看@withStylesReact Starter Kit 中使用的ES7 装饰器。
This little beauty helps ensure users see your content with styleswhen the page is first rendered. Here's an example isomorphic appI'm building leveraging this technique. Just search the codebase for @withStylesto see how it's used. It goes a little something like this:
这种小小的美感有助于确保用户在首次呈现页面时看到具有样式的内容。这是我正在利用这种技术构建的同构应用程序示例。只需搜索代码库@withStyles以查看它的使用方式。它有点像这样:
import React, { Component, PropTypes } from 'react';
import styles from './ScheduleList.css';
import withStyles from '../../decorators/withStyles';
@withStyles(styles)
class ScheduleList extends Component {
回答by catamphetamine
You can also try this https://github.com/halt-hammerzeit/webpack-isomorphic-tools
你也可以试试这个 https://github.com/halt-hammerzeit/webpack-isomorphic-tools
or this https://github.com/halt-hammerzeit/webpack-react-redux-isomorphic-render-example
或者这个 https://github.com/halt-hammerzeit/webpack-react-redux-isomorphic-render-example
回答by koorchik
We had a similar problem with our isomorphic app (and a lot of other problems, you can find 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. It works perfectly with babel6.
我们的同构应用程序也有类似的问题(还有很多其他问题,您可以在此处找到详细信息)。至于CSS导入的问题,一开始我们用的是process.env.BROWSER。后来我们切换到babel-plugin-transform-require-ignore。它与 babel6 完美配合。
All you need is to have the following section in your .babelrc
您只需要在 .babelrc 中包含以下部分
"env": {
"node": {
"plugins": [
[
"babel-plugin-transform-require-ignore", { "extensions": [".less", ".css"] }
]
]
}
}
After that run your app with BABEL_ENV='node'. Like that:
之后,使用 BABEL_ENV='node' 运行您的应用程序。像那样:
BABEL_ENV='node' node app.js.
Here isan example of how a production config can look like.
这是生产配置的外观示例。
回答by Raul Matei
I used this babel pluginwith success to solve a similar issue with less, svg and images. But it should work with any non js assets.
我成功地使用这个babel 插件解决了一个类似的问题,包括 less、svg 和图像。但它应该适用于任何非 js 资产。
It rewrites all assets imports into variables, so as long as you run the compiled code just on the server and have a bundle built with webpack for the client, it should be fine.
它将所有资产导入重写为变量,因此只要您仅在服务器上运行已编译的代码并为客户端构建了一个使用 webpack 的包,就可以了。
The only drawback is that it onlyworks with named imports, so you'll have to:
唯一的缺点是它仅适用于命名导入,因此您必须:
import styles from './styles.css';
in order to make it work.
为了使它工作。
回答by Anders Ekdahl
You probably have an error in your Webpack config where you're using the babel-loaderfor all files, and not just .jsfiles. You want to use a css loader for .cssfiles.
您的 Webpack 配置中可能存在错误,您使用的是babel-loaderfor 所有文件,而不仅仅是.js文件。您想对.css文件使用 css 加载器。
But you shouldn't use importfor loading any other module than Javascript modules, because once imports are implemented in browsers, you will only be able to import Javascript files. Use requireinstead in cases where you need Webpack specific functionality.
但是你不应该import用于加载除 Javascript 模块之外的任何其他模块,因为一旦在浏览器中实现了导入,你将只能导入 Javascript 文件。require在需要 Webpack 特定功能的情况下使用。
ORIGINAL POST
原帖
Webpack uses requireand Babel lets you use importfrom ES6 which mostly do the same thing (and Babel transpiles the import to a require statement), but they are not interchangable. Webpacks requirefunction lets you specify more than just a module name, it lets you specify loaders as well, which you cannot do with ES6 imports. So if you want to load a CSS file, you should use requireinstead of import.
Webpack 使用require而 Babel 允许您import从 ES6使用它们,它们主要做同样的事情(Babel 将导入转换为 require 语句),但它们不可互换。Webpacksrequire函数不仅可以指定模块名称,还可以指定加载器,这是 ES6 无法做到import的。所以,如果你想加载一个CSS文件,你应该使用require代替import。
The reason is that Babel is just a transpiler for what's coming in ES6, and ES6 will not allow you to import CSS files. So Babel won't allow you to do that either.
原因是 Babel 只是 ES6 中即将到来的内容的转译器,而 ES6 不允许您导入 CSS 文件。所以 Babel 也不允许你这样做。
回答by gpbl
Make sure you are using the loaders in your webpack config:
确保您在 webpack 配置中使用加载器:
module: {
loaders: [
{ test: /\.jsx$/, exclude: /node_modules/, loader: "babel" },
{ test: /\.css$/, loader: "style!css" }
]
}
回答by duncanhall
I've finally realised that this error is not originating at the compile stage, but rather at runtime. Because this is an ismorphic app, the components and any dependencies they have will first be parsed on the server (ie, in node). It is this that is causing the error.
我终于意识到这个错误不是源于编译阶段,而是源于运行时。因为这是一个同构应用程序,组件和它们拥有的任何依赖项将首先在服务器上(即在节点中)进行解析。这是导致错误的原因。
Thanks for all the suggestions, I will post more if/when I figure out how to have per-component stylesheets in an isomorphic application.
感谢所有的建议,如果/当我弄清楚如何在同构应用程序中拥有每个组件的样式表时,我会发布更多。
回答by Chen-Tai
I also met the same problem when I want to do the server-side render.
当我想做服务器端渲染时,我也遇到了同样的问题。
So I write a postcss plugin, postcss-hash-classname.
所以我写了一个 postcss 插件postcss-hash-classname。
You don't require css directly.
您不需要直接使用 css。
You require your css classname js file.
你需要你的 css 类名 js 文件。
Because all you require is js file, you can do the server-side render as usual.
因为你只需要 js 文件,你可以像往常一样进行服务器端渲染。
Besides, this plugin also use your classname and file path to generate unique hash to solve css scope problem.
此外,这个插件还使用您的类名和文件路径来生成唯一的哈希来解决 css 范围问题。
You can try it!
你可以试试看!
回答by Aniket Sharma
Solved With This...
用这个解决了...
https://github.com/michalkvasnicak/babel-plugin-css-modules-transform
https://github.com/michalkvasnicak/babel-plugin-css-modules-transform
$ npm install --save-dev babel-plugin-css-modules-transform
Include plugin in .babelrc
在 .babelrc 中包含插件
{
"plugins": ["css-modules-transform"]
}
And Import Css..... Like This Anywhere You Want
并导入 CSS..... 像这样任何你想要的
const styles = require('./test.css');
OR
import css from './styles.css'
Also See This... Apart From Css Files........................................................ . https://www.npmjs.com/package/babel-plugin-transform-assets
另请参阅此...除了 Css 文件...................................... …………………… https://www.npmjs.com/package/babel-plugin-transform-assets

