I am wondering that if I have an external CSS file which is frequently used in my components, should I import this external CSS inside each component or the root component?
For each component:
import React from 'react'
import '../font.css'
class MyComponent extends React.Component {
render() {
return <div className="fa fa-bandcamp"></div>;
}
}
This is self-explanatory: because I want to use 'fa fa-bandcamp', I import '../font.css'.
This methodology is just like programming JS or any other programming languages. If we need a dependency, we import it in that file as well, for example:
import global from 'global'
import util from 'util'
global.foo
global.bar
util.bar
util.bar
// ...
However, my colleague told me that global css should never be imported inside every depending components, instead, it should be imported inside a root component or in the entry file of webpack, for example:
// 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>;
}
}
What's the pros and cons of each solution? I would like to hear more advices and appreciate your help.
I'd import your font.css
file when and where you use it (but not exactly the way you suggest, see below) and not just in the root component. I suggest this because when and if you decide to code split, you would only want that CSS to exist in the bundle that uses it.
If the import is in your root component, you might remove all components that are using the fa fa-bandcamp
classes but your import remains in the root (because you forget it's there and not alongside your component) and you'd be bundling in CSS that is not even in the chunk that uses it.
On the contrary though, when importing at the component level you could also end up in a situation where you use those classes and forget to import that font.css
because ANOTHER component has imported the global CSS already. It looks like it works but if you code split you might find that your chunk does not have the right font because the CSS import is in another chunk. In this case importing it in the root would have solved your issue!
What I would do:
I would argue that any global css is bad and you should be using something like CSS modules. So I'd go one step further and create a <Text/>
component that is something like:
import React from 'react'
import '../font.css'
export default ({ className, children, tagName: TagName }) => <TagName className={`fa fa-bandcamp ${className}`>{ children }</TagName>;
Now you can use the <Text tagName="span">Hey!</Text>
in all your components safely because:
<Text/>
you won't be left with a bundle that contains unused CSS imports in the root that you forgot about.I wouldn't employ this kind of strategy for something like a reset.css though. Obviously.
TL;DR Summary
Root level - Potential inefficient code splitting. Harder to maintain as CSS does not live along side the component that uses it.
Individual component level - Pain to import all the time. Fragile as you can end up using a class that doesn't exist in a chunk if forgetting to import the global CSS.
"Text" component - Awesome. Just make sure everybody uses the fa
classes via this component and everything is golden. Modular. Easy to maintain. Robust.
They are almost right when your colleagues say:
that global css should never be imported inside every depending components, instead, it should be imported inside a root component or in the entry file of webpack
Why?
Because then you might end up having inline css files, giving an example, in one of my application, where I used less
, every import resolved into a local copy of the same inline into javascript file, the generated bundle.js
file in my case, Snippet:
, /* 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...
/***/
}
See the bootstrap css license at the start? But then it also uses @import url
for fonts css which was imported in the file.
So every time you import, it would be included in the module code again and again.
Things to use
If you use something like Extract Text Webpcak Plugin, which basically scans your code and extracts the css
into a file which also helps in parallel load. Thus solving your same css file import multiple times solution.
Observation:
In my case my webpack uses a less
styling and hence my loader is something like:
Webpack v1.13.*:
{
test: /\.less$/,
loader: 'style!css!less'
}
Which in my case is adding it not under a style
tag, but embedded inside the javascript function.
In your case, you are using a style-loader
which by definition is:
style-loader - Injects the CSS, that is exported by the JavaScript module, into a tag at runtime
Now, if you verify, by importing the same global.css
in your case, a single <style>
is created which would be the one time definition.
Showing your bundle.js
pushes the same, when you generate it:
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(3)(undefined);
// imports
// module
exports.push([module.i, ".red {\n color: red;\n}\n\n.blue {\n color: blue;\n}\n", ""]);
// exports
/***/ }),
That is why in your index.html you will see the <style>
tag added by bundel.js:
function insertStyleElement (options, style) {
....
}
Conclusion:
Global importing the styles
pros: is a good practice in case you have base css like
bootstrap.css
andfont-awesome
, because it is a lot neater to know, that your entire application adheres to that rule of css.cons: None. In case the css are common, then I don't see any cons of importing it globally
Local importing of styles
pros: It will always be lot easier to debug in case you know which css is affecting the component when you want to drill down to any bug. These css files are the ones that you would be implementing.
cons: There are a very few being, in case there was a bug of
border
issue, and while debugging, you realized that it points to a css file imported locally, but you failed to realize that it affects other components then it would be causing an unwanted change in your UI. Also it would be lot slower for the styles to be extracted during build time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With