I'm building a react component library with styled components. I have a <GlobalStyles /> component for projects consuming the library. In the SASS that I'm migrating from, I had a root index.scss file, within which I was doing:
#import '~bootstrap/scss/bootstrap';
I gather I cannot just put this in my global styles:
import { createGlobalStyle } from "styled-components"
const GlobalStyles = createGlobalStyle`
#import '~bootstrap/scss/bootstrap';
`
How can I make sure that any project including <GlobalStyles /> will also receive the bootstrap stylesheets?
You cannot import the bootstrap scss stylesheet without processing it for obvious reasons.
But you can import the bootstrap stylesheet. Unfortunately createGlobalStyle does not handle these imports as the underlying CSSDOM imports do not handle this well. The easiest implementation would be to import the bootstrap CSS files into your library like:
import 'bootstrap/dist/css/bootstrap.min.css';
But note that this will generate an extra CSS file that users of your library will have to include with something similiar to this too.
If you would want to create this dynamically, you could try adding this from a CDN.
import { useEffect } from "react";
function App() {
useEffect(() => {
const head = document.head;
const link = document.createElement('link');
link.href = `https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css`;
link.rel = `stylesheet`;
head.append(link);
}, []);
}
But consider the fact that these will have to be include on all components, but should not be included more than once. One way you can do this is by adding an ID to the link tag and querying the DOM before adding a new one.
Related
Let's say I have two React components:
import { React } from "react";
import "./styles.css";
function ComponentA() {
...
}
export default ComponentA;
import { React } from "react";
import "./styles.css";
function ComponentB() {
...
}
export default ComponentB;
Both of these components are importing the same CSS file styles.css. Now let's say that in my app, I'm importing both of these components, so App.js looks something like this:
import { ComponentA } from "./ComponentA";
import { ComponentB } from "./ComponentB";
function App() {
return (
<div className="App">
<ComponentA />
<ComponentB />
</div>
);
}
export default App;
What exactly happens here? Does my app import the same CSS file twice? And if so, do I just make the import on the App.js file instead?
It's as if it was only imported once.
When a module bundler like Webpack sees an import, it puts the following path in the list of files to process, if the path doesn't exist already. The file is only processed once, no matter how many times it's imported.
Note that with React apps, you will often see
import React from "react";
in tens or hundreds of files - React isn't created anew hundreds of times. Rather, the module is processed once, and then files that import it are given access to what React has exported.
Importing CSS files works the same way, in that they're only processed once no matter how many times an import exists for them (though they don't really have exports, just side-effects).
If both ComponentA and ComponentB depend on styles.css, feel free to keep importing styles.css in both - it doesn't hurt, and will make things easier to manage when you can see at a glance that both components directly depend on that CSS.
I am trying to import my jss file to React component (.jsx) and I have this error :
I looked through related questions and I tried all solutions, mostly about updating versions of material-ui. Here is my package.json file:
the way I write jss file :
import { makeStyles } from '#material-ui/styles';
const useStyles = makeStyles((theme) => ({
root:
{
margin: '10px'
}
}));
export default useStyles;
And jsx file :
import React from 'react';
import DateBar from './DateBar';
import Grid from '#material-ui/core/Grid';
import useStyles from './Board.jss';
export default function Board()
{
const classes = useStyles();
return(
...
Am I missing something or Do I need additional packages for using jsx and jss in React?
I have been trying all the solutions but didn't work..
Note: When I put the code inside of Jss into Jsx file, code works fine. Importing/Exporting might be an issue..
Edit: Still couldn't fix even though I created a new app and installed dependancies from the beginning..
Ok I've looked everywhere and there is no documentation on this Babel module
--babel-plugin-named-asset-import
can someone please explain what it is for and how it works.
Looks like its purpose is to import named exports from non JS/CSS assets. Currently, within the CRA, it appears to only be implemented for svg assets. The goal is to offer another way to import SVGs as React components versus the standard import as a url that needs to be applied to an img element.
Without plugin (default import)
import * as React from 'react';
import logo from './logo.png'; // import file as a url
function Header() {
return <img src={logo} alt="logo" />;
}
export default Header;
With plugin (named import)
import * as React from 'react';
import { ReactComponent as Logo } from './logo.svg'; // import file as a React component
function Header() {
return <Logo />;
}
export default Header;
Update
Going deeper, it appears that the plugin aids in importing svg files in the following ways:
import logo from "logo.svg"; // default import
import { logoUrl } from "logo.svg"; // named import
import { ReactComponent as Logo } from "#svgr/webpack?-svgo!logo.svg"; // ReactComponent import
The CRA specifically targets svg file formats as shown in their test suites. As to whether or not it supports other non-js files, not likely (especially since the babel plugin is only utilized once in the CRA webpack config).
As mentioned in the svgr docs:
SVGR can be used as a webpack loader, this way you can import your SVG directly as a React Component.
This particular plugin aims to import any svg file as the default export.
Please note that by default, #svgr/webpack will try to export the React Component via default export if there is no other loader handling svg files with default export.
Whereas the CRA appears to utilize file/url loader for the default/named exports and specifically maps a ReactComponent named export to the svgr webpack plugin.
Is there a way to import a CSS file into a styled component?
One of my dependencies, React Quill Editor, is themeable by importing their CSS as a base and applying changes on top of it. All of my components are styled components, and I'd like to keep the CSS localized to the JS component rather than import the CSS as a 'global' style.
Right now I've take to copying their CSS into my own file in the following form.
I've written a brief example below.
/** editorCSS.js **/
import { css } from 'styled-components';
export default css`
/* copied CSS here */
.class-to-extend {
color: green;
}
`
/** EditorComponent.js **/
import styled from 'styled-components';
import ReactQuill from 'react-quill';
import editorCSS from './editorCSS';
const StyledReactQuill = styled(ReactQuill)`
${editorCSS}
/** Additional customization if necessary (e.g. positioning) */
`
export default StyledReactQuill;
`
I'd much rather import reference their css file in the scope of the styled component vs copying it.
If I do import ReactQuillCSS from 'react-quill/dist/quill.snow.css'; it will still apply my css globally due to the css-loader plugin.
Best,
Daniel
You could use raw-loader to load the quill.snow.css stylesheet and then include it in your styled component.
/** EditorComponent.js **/
import styled from 'styled-components';
import ReactQuill from 'react-quill';
import quillCSS from '!!raw-loader!react-quill/dist/quill.snow.css';
const StyledReactQuill = styled(ReactQuill)`
${quillCSS}
/** Additional customization if necessary (e.g. positioning) */
`
export default StyledReactQuill;
Per the raw-loader docs, you can use !! to prevent the styles being added globally via css-loader
Adding !! to a request will disable all loaders specified in the configuration
You can add a module rule to import styles locally from a CSS file into a styled component.
E.g. import all third party .css files from node_modules as raw string, others as usual:
// webpack.config.js
const config = {
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"], // load project styles via style-loader
exclude: /node_modules/,
},
{
test: /\.css$/,
use: ["to-string-loader", "css-loader"], // use to-string-loader for 3rd party css
include: /node_modules/,
},
// ...
],
},
// ...
}
Usage:
import styled from 'styled-components';
import ReactQuill from 'react-quill';
import ReactQuillCSS from 'react-quill/dist/quill.snow.css' // no custom webpack syntax
const StyledReactQuill = styled(ReactQuill)`
${ReactQuillCSS}
// ... other styles
`
Don't forget to install to-string-loader, if not used yet.
This has some advantages over #jonathanhculver's solution:
One central config file determines, how to process .css files
Follow Webpack recommendations:
Use module.rules whenever possible, as this will reduce boilerplate in your source code and allow you to debug or locate a loader faster if something goes south. (docs)
Avoid ESLint errors - take a look at the Codesandbox demo
css-loader can still resolve #import and url() for external CSS files, raw-loader won't
In order to achieve that you would need to use a different loader than css-loader. You could write an different loader which prepares it for styled-components rather than adding it to the global style sheet.
If you need css-loader, you would however need to define which css files are handled by it and which ones are loaded for styled-components, which makes it not really practical imho.
This is how I did:
Code
import React, { Component } from "react";
import ReactDOM from "react-dom";
import Styled from "styled-components";
const fetchStyles = () =>
fetch(
"https://gist.githubusercontent.com/bionicvapourboy/61d3d7a8546cb42e0e3194eb9505f48a/raw/5432218dd83320d53d1cbc2f230b81c765183585/style.css"
).then(response => response.text());
class App extends Component {
state = {
style: ""
};
componentDidMount() {
fetchStyles().then(data => this.setState({ style: data }));
}
Wrapper = () => Styled.div`
${this.state.style}
`;
render() {
const Wrapper = this.Wrapper();
return (
<div className="App">
<Wrapper>
<h1>Styled</h1>
</Wrapper>
<h1>Not Styled</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Demo
https://codesandbox.io/s/yw7xmx6x3x
As far as I know there is no way to import regular CSS just in scope. The way I have combined styled-components with CSS from libraries so far is to give your own styled component a className in the jsx.
const MyStyledComponent = styled(ComponentFromLibrary)`
color: red;
`;
// and in the render function
return (
<MyStyledComponent className="libraryClassname" />
);
Another example can be found in the official documentation:
https://www.styled-components.com/docs/advanced#existing-css
What you are proposing would work if editorCSS is just a string of the styles you want to apply to the component.
From my understanding styled-components is just essentially template literals anyways.
Your only issue should be that the imported css is defined as an object when you try to place it into your components css. Have you tried typecasting it to a string first?
/** EditorComponent.js **/
import styled from 'styled-components';
import ReactQuill from 'react-quill';
import editorCSS from './editorCSS';
const newCSS = editorCSS.toString();
export default Styled(ReactQuill)`
${newCSS}
`;
I have a bunch of React components in a folder and I can import each one individually like this:
import Component1 from '../components/component1/component1';
import Component2 from '../components/component2/component2';
Using the components like this works fine. However, when I bundle all the components using Webpack, the following code returns an empty object when I try to import the component.
import Component1 from '../dist/bundle.js';
I can't render this component. How do I export the components when bundling files?
Simply put you cannot import any modules from a bundle.
You need to include this code inside the source and then bundle it together
Actually you can do that. In my situation I needed react components in backbone application so what I did:
In react exposed components that should be importable by exporting them in entry point (usually index.js) like:
import React from 'react';
import ReactDOM from 'react-dom';
import Header from './components/Header/Header';
export {
React,
ReactDOM,
Header
};
Made my bundle output as library:
output: {
path: /some/path/of/your/lib,
library: 'reactapp',
libraryTarget: 'umd',
filename: `app${jsExtension}`,
},
Then bind name to file path in requirejs config:
reactapp: '/some/path/of/your/lib/app.js'
Then in code I can import that bundle as reactapp like:
define(["reactapp"], function(reactapp) {
// reactapp is object containing React, ReactDOM, Header
});