全局CSS应该放在每个组件中还是根组件(Webpack入口文件)中?

10
我想知道,如果我有一个在我的组件中经常使用的外部CSS文件,是应该在每个组件中还是在根组件中导入这个外部CSS?
对于每个组件:
import React from 'react'
import '../font.css'

class MyComponent extends React.Component {
  render() {
    return <div className="fa fa-bandcamp"></div>;
  }
}

这很容易理解:因为我想使用“fa fa-bandcamp”,所以我导入“../font.css”。

这种方法与编写JS或任何其他编程语言类似,如果需要依赖项,我们也会在文件中导入它,例如:

import global from 'global'
import util from 'util'

global.foo
global.bar
util.bar
util.bar
// ...

然而,我的同事告诉我全局 CSS 不应该在每个依赖组件中导入,而应该在根组件或 webpack 的入口文件中导入。例如:

// in each component
import React from 'react'
// import '../font.css'

class MyComponent extends React.Component {
  render() {
    return <div className="fa fa-bandcamp"></div>;
  }
}

// in entry file (root component)
import React from 'react'
import '../font.css'

class App extends React.Component {
  render() {
    return <div>{this.props.children}</div>;
  }
}

每种解决方案的优缺点是什么?我想听听更多建议,感谢您的帮助。


1
你的同事是错的。这两种方法都是完全有效的,每种方法都有其优缺点。 - Chris
3个回答

10

我建议您在需要使用它的地方导入font.css文件(但不完全按照您的建议,详情请见下文),而不仅仅是在根组件中导入。我建议这样做是因为,如果和当您决定进行代码分割,您只需要该CSS存在于使用它的bundle中。

如果导入在您的根组件中,您可能会删除所有使用fa fa-bandcamp类的组件,但您的导入仍然在根目录中(因为您忘记了它不在您的组件旁边),并且您会打包未包含该CSS的CSS。

相反,当在组件级别导入时,您可能也会遇到使用这些类却忘记导入font.css的情况,因为另一个组件已经导入了全局的CSS。它看起来像是可以工作的,但如果您进行代码分割,您可能会发现您的块没有正确的字体,因为CSS导入在另一个块中。在这种情况下,将其导入到根目录中就可以解决您的问题!

我的建议:

我认为任何全局CSS都是不好的,您应该使用类似于CSS模块的东西。所以我会更进一步,创建一个<Text/>组件,类似于:

import React from 'react'
import '../font.css'
export default ({ className, children, tagName: TagName }) => <TagName className={`fa fa-bandcamp ${className}`>{ children }</TagName>;

现在你可以安全地在所有组件中使用<Text tagName="span">Hey!</Text>,因为:

  • 您不再需要一直导入CSS。
  • 如果您进行代码拆分或删除所有<Text/>,则不会留下包含根目录中未使用的CSS导入的捆绑包。
  • 不可能使用这些类并忘记导入CSS。
  • 一切都以一种模块化的方式封装,并且您的包尽可能高效。

尽管如此,我不会为reset.css之类的东西采用这种策略。

简短总结

根级别 - 潜在的低效代码拆分。 难以维护,因为CSS不能与其使用的组件共存。

单个组件级别 - 每次导入都很麻烦。 如果忘记导入全局CSS,则很容易出错,并使用不存在于某个块中的类。

“Text”组件 - 很棒。 只需确保每个人都通过此组件使用fa类,一切都很好。 模块化。 易于维护。 健壮。


我认为全局样式通常会带来问题。如果您需要从全局/第三方样式表中选择样式,请查看 https://github.com/glortho/styled-import(注意:我是作者)。 - glortho

2
当你的同事们说:“全局 CSS 应该永远不应该在每个依赖组件内导入,而应该在根组件或 Webpack 的入口文件中导入”,他们几乎是正确的。
为什么呢?
因为这样你可能最终会得到内联的 CSS 文件。以我使用 less 的一个应用程序为例,每个 import 都解析成相同的本地内联 JavaScript 文件副本,生成的 bundle.js 文件如下:

, /* 1381 */
/***/
function(module, exports, __webpack_require__) {

    eval("exports = module.exports = __webpack_require__(625)();\n// imports\nexports.push([
module.id, \"@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,600,700);\", \"\"]);
\n\n// module\nexports.push([module.id, \"/*!\\n * Bootstrap v3.3.7 (http://getbootstrap.com)\\n * 
Copyright 2011-2016 Twitter, Inc.\\n * Licensed under MIT 
(https://github.com/twbs/bootstrap/blob/master/LICENSE)\\n */\\n/*! normalize.css v3.0.3 | MIT License |
 github.com/necolas/normalize.css */\\nhtml 
{\\n  font-family: sans-serif;\\n  -ms-text-size-adjust: 100%;
\\n  -webkit-text-size-adjust: 100%;\\n}\\nbody 
{\\n  margin: 0;\\n}\\narticle,\\naside,\\ndetails,\\nfigcaption,
\\nfigure,\\nfooter,\\nheader,\\nhgroup,\\nmain,\\nmenu,\\nnav,\\nsection,
\\nsummary {\\n  display: block;\\n}\\naudio,\\ncanvas,\\nprogress,
\\nvideo {\\n  display: inline-block;\\n  vertical-align: baseline;\\n}
\\naudio:not([controls]) 
{\\n  display: none;\\n  height: 0;\\n}\\n[hidden],\\ntemplate {\\n  display: none;\\n}\\na {\\n  background-color: transparent;\\n}

   Some more things here...

    /***/
}

看到开头的Bootstrap CSS许可证了吗?但是它也使用了@import url导入的字体CSS文件。

每次导入时,它将再次包含在模块代码中。
需要使用像Extract Text Webpcak Plugin这样的工具,它基本上会扫描您的代码并将CSS提取到一个文件中,这也有助于并行加载。从而解决同一CSS文件多次导入的问题。
观察:
在我的情况下,我的Webpack使用的是less样式,因此我的加载器类似于:Webpack v1.13.*:
  {
     test: /\.less$/,
     loader: 'style!css!less'
  }

在我的情况下,需要将CSS代码添加到JavaScript函数内部,而不是添加在

我使用webpack v3创建了一个repo,但无法重现您提到的同样问题,想知道您使用的webpack版本。您可以在此处拉取我的repo,构建后,您将会发现dist/bundle.js文件中没有重复内容。此外,在<head>标签中只能找到一次<style> - Weihang Jian
@JianWeihang 我的webpack是一个旧版本 - 1.13.*。但这不应该有太大的差异,插件和新数据版本仍然有效。我也尝试了你的repo,它没有任何启动或构建脚本? - Nagaraj Tantri
npm install && ./node_modules/.bin/webpack && open dist/index.html请执行 npm install && ./node_modules/.bin/webpack && open dist/index.html 命令。 - Weihang Jian
你的结论并没有回答我的问题。是的,我知道我可以在任何地方导入样式,并且我目前正在使用extract-text-webpack-plugin在我的项目中。由于捆绑文件中不会有任何重复的代码,我想知道每种解决方案的优缺点是什么。 - Weihang Jian
@JianWeihang 是的,意识到了,跑题了。更新了结论。 - Nagaraj Tantri

2

在全局空间中添加CSS很容易,而且可以直接使用。

通过使用Webpack,您可以轻松地分别为每个组件文件导入CSS文件,如果需要,则可以将style!css!sass用于.scss导入。

它允许您按以下方式在React组件中简单地导入和使用样式: import styles from './mycomponent.scss';

export default props => <button className={styles.mycomponent.button} />

这里是相应的加载器: style-loader css-loader sass-loader

style-loader将处理开发期间的热加载,并在生产构建时捆绑输出的样式(这些被编译到您的组件模块中)。

我推荐您对css-loader使用modules option,这样您就确保了您的CSS正确作用域,并且永远不会与外部代码冲突。


谢谢您的回复,但它并没有解开我的困惑。 - Weihang Jian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接