CSS Reset with PostCSS autoreset - reactjs

I'm trying out postCSS on a project using the create-react-app starter repo with postCSS and importing .css files for each component. That is, each component includes a import 'styles/componentA.css';, or several.
In order to create consistent styles across browsers I'd like to import a CSS reset. I've tried a few things:
Importing a .css file containing a standard CSS Reset based on Eric Meyer's reset.
Using the autoreset plugin for postCSS.
For the first option , in dev mode the CSS imports are added as <style> tags to the document. The CSS Reset appears last in the list of <style> tags, though it's imported in the top-level component. Ideally the CSS Reset would be imported first. Being last means it would overwrite any styles I apply to base elements (like h1 {font-size: 40px;})
For the 2nd option (using autoreset), it doesn't appear there's a way to apply specific rules to specific elements. For example, I want to apply list-style: none only to ul and ol elements.
Is it possible to use the autoreset plugin to do a Eric Meyer-like CSS Reset in postCSS? Or am I going in a completely wrong direction and misunderstanding the purpose of it?

I don't use react but I faced a similar issue when using components and resets alongside PostCSS (I'm building things as described here: http://ecss.io/chapter7.html). I didn't want a reset loaded for each component, just a global one as would be used traditionally.
Therefore, I went with a 'component' purely for 'globalCSS'. This is the first component that gets loaded and loads in the reset (and also global PostCSS variables and mixins) so subsequent components have access to them without redeclaring.
Is that an approach you could use/adapt?

Related

How can I compile my React component's styles (JSX and CSS Modules) to be used statically — as a simple imported .css file?

Background
I'm creating a public Node package which consists of some React UI. I'm currently using CSS Modules to scope the styles to the component, and it's all being successfully bundled with Webpack. The bundle outputs a main.css file.
The ask
Since I intend to use this packaged component across many projects with different frameworks, I cannot guarantee that CSS Modules will be available. Thus, I would like to "flatten" the compiled JSX, such that the generated CSS Module classNames are always added at build time, rather than being conditionally added based on whether or not the CSS modules are being imported. From there I should be able to just import the compiled CSS file and call it a day.
What I've found
This tool seems to solve my problem, specifically using CSS Modules. This is not actively maintained though, and I wonder if there's a better solution out there.
https://cef62.github.io/css-modules-compiler/
https://cef62.github.io/css-modules-compiler/quick-start.html
I do wonder if this is doable with some sort of PostCSS routine or a preexisting PostCSS plugin.

Use single StylesContext when importing component from custom MUI-based library

I have an application (let's call it frontend) importing a custom library of React components (design-system) that's Material UI based.
In the frontend app, I have a ShadowDOM-contained component (using react-shadow) that I want to import a Button component from design-system to. I wrapped the whole tree inside ShadowDOM with StylesProvider that I passed a custom instance of jss to (with different injectionPoint, so the styles from inside that tree are attached not at the head of the document, but inside the ShadowDOM.
The issue I have is, that frontend uses its own copy of StylesProvider from #material-ui/styles package (I have no need to install the whole #material-ui/core as all components should be imported from design-system instead) and design-system uses its own copy of StylesProvider from #material-ui/core, resulting in a situation, where the Button is being wrapped with another StylesProvider by MUI because it doesn't detect any styles context available (and it doesn't, because MUI creates the context in global scope of StylesProvider.js file - so there are two different contexts that do the same), resulting in Button having access to default JSS instance where the insertionPoint is pointing to document head.
What I'd like to achieve is, have MUI not create another styles context for every single component imported from design-system but use the one I defined in frontend - without passing it as a prop manually to every component imported. I considered adding #material-ui/styles on top of #material-ui/core to design-system and adding it to webpack's "externals" (so, theoretically, only one StylesProvider.js would be used and in turn - one context), but I was hoping there's a better solution.
TLDR:
Just adding #material-ui/styles to externals in design-system's webpack config was enough (even if you don't add it explicitly as dependency, #material-ui/core depends on it and will use it anyway, so it works).
Long answer:
My setup is such that the "main" entrypoint in package.json of design-system points to dist/index.js (so, already bundled/minified version of the library). Without adding #material-ui/styles to "externals" in webpack config, it was bundled along the whole library, so at this point, whatever I did there would always be two copies of StylesProvider.js:
One solution is to mark #material-ui/styles as external - this way, it won't be bundled in dist/index.js and instead, expected to be available during runtime (and it is):
Besides the aforementioned solution, there's also another one that worked - pointing "main" entry in package.json to "src/index.ts" instead. It made the frontend webpack treat it as a part of frontend code, instead of separate library:
As a bonus, it ended up with the final bundle being smaller (as common dependencies weren't duplicated). One minus of this approach was, however, that each frontend build had to also rebuild design-system, which increased the total build time.

Can I tell style-loader to load my global css before my CSS Modules?

Most of my site is using Bulma classes for some of my global UI styling, and I'd like to continue to use those classes within my components, but also be able to define CSS Modules for those components for custom per component tweaks.
Because of this, I added babel-plugin-react-css-modules to my project which has allowed me to use my Bulma classes in className and put my module classes in styleName. Ok, a little hacky feeling, but it's working. I've got a global-styles.scss file in a CSS directory that I'm loading into my main app component. This is where I'm importing Bulma, as well as defining any of my own global styles.
My issue is that my when my global styles and my module styles all get smashed together (via css-modules?) and injected into a style tag in the head (via style-loader?), my module styles get defined first, then my global styles.
I feel like the module styles are locally scoped and should always take precedence (load last), even if I'm loading both global and scoped styles in the same component. For example, in one component I'm using Bulma's .navbar classes, but I'm also defining my own .navbar class in my CSS Module for that component, and I'm applying both to the same element in my component.
Is there anyway I can specify what order to build the style tag? Between all of these plugins I'm just lost, then when you throw Gatsby's plugin abstraction on top of it and it's all very confusing.
I'm not entirely certain of what was causing the issue, but it seems to pertain to Gatsby.
https://www.gatsbyjs.org/tutorial/part-two/#component-css
Tip: This part of the tutorial has focused on the quickest and most straightforward way to get started styling a Gatsby site — importing standard CSS files directly, using gatsby-browser.js. In most cases, the best way to add global styles is with a shared layout component.
Their recommended approach is to import your global files in your layout component. This was loading my globals after my modules. However, creating a gatsby-browser.js file, and importing my globals there is loading my styles in the intended order.

React Styled Components stripped out from production build

I use Styled Components as CSS alternative for my React App. In development everything works fine (first screenshot), but when I run a production build (npm build), styles within style tags are stripped out (second screenshot). As a result, there're no styles in the production build.
Here is the production version: http://projects.loratadin.com.s3-website-us-east-1.amazonaws.com/weather-app/
Here is the source code: https://github.com/Loratadin/weather-app
I had a similar issue with empty style tags in production. I'm using a headless browser for server-side rendering and this issue caused the server-side rendered pages to appear with no styles before JS assets are loaded.
After a lot of searching around, I finally found out the reason. The Styled Components library uses something called the "Speedy mode" to inject styles on production. This makes the styles bypass the DOM` and be injected directly inside the CSSOM, thus, appearing in the inspector, but totally invisible on the DOM.
Fortunately, Styled Components 4.1.0 came with a fix for this issue! Now you can set a global variable called SC_DISABLE_SPEEDY to true in order to disable the Speedy mode and get the styles to appear on Production as well. Keep in mind that you should do it at the very beginning of your application's entry file, before importing any styled component, otherwise it will not work.
The way I did it is by creating a new file called globals.js that contains global.SC_DISABLE_SPEEDY = true
and importing it as the very first thing in my index.js.
Reference: https://www.styled-components.com/releases#v4.1.0
For the Create React App folks out there you can add a .env file in your root and add:
REACT_APP_SC_DISABLE_SPEEDY=true
I was able to replicate your issue and it looks like when the application is in production, it can't select html elements within a styled component (the styles don't apply to the element). Instead, you'll need to create additional stylized components for input and button.
Working example: https://github.com/mattcarlotta/Weather-App
I refactored your application to simplify its structure. Please read the README for instructions on how to run it in development and in production (DO NOT use the above repository for production, as it's highly unnecessary to have an express backend -- I only did this so that you can run a local production build).
What I changed:
Moved any styled components to the components folder for modularity
Any sort of global stylization was put into a styles folder
Moved assets to images and imported them into the styled component that needed them (eliminating the need to use require('../path/to/image'))
Simplified the App.js file. Children are controlled by state and class methods. Most importantly, turned your form into a controlled component, fixed the getWeather method to: Not allow an empty submission, if the AJAX calls fails, it'll catch the error (instead of breaking your app), and reset the form inputs on successful submission.
Added prop-types to ensure props were consistent in declaration (string remains a string, number remains a number, and so on).

Load different css on different pages

I'm trying to find a solution to this problem:
I'm using a template with different css includes based on page, ex:
Login uses login.css
Home uses home.css
If I load both css the login page is broken, because styles are overwritten by home.css
So I need to load or require login.css if the route or the component is Login and the other one when is Home.
If I load both webpack builds a global css with both files, and everything is broken...
I tried to require the css in componentDidMount, but I think that is not the way :)
Thanks in advance
It sounds like both these styles are quite specific to the pages, so why not simply namespace them?
Within your templates, have a .login/.home class, and use this as the namespace within the css. If you're using sass, this is as simple as wrapping all the sass in the class. Otherwise, you can go through and add the class to the beginning of all the elements/clases.
First of all, you shouldn't have any problems if you use different css classes for your views and just style the elements based on those classes.
The best way to load css in react is to do it by components, if you got a component login.jsx, in your styles folder (or whatever folder you're using to hold your styles) create a sass partial _login.scss and add the css selectors and styles for that given component, and do that for every component in your react application.
Then you just include those partials into a main.scss file and that's the file you want to load into your react app.
Here's an example of a main.scss file with some sass partials.
#import 'base/variables';
#import 'base/defaults';
#import 'components/login';
#import 'components/home';
That's a good and clean way to work with styles in react, of course you will need to configure your webpack in order to get sass to work in your application.
Take a look at this and this for more info.
This is a more generic approach to combine CSS files, without depending on technologies like SASS or reactjs.
I assume, if you combine the two CSS files, you are using Grunt or similar tool, to automate that task. So automatically updating the CSS files should be OK for you, even though they are from an external source and you want to use updated versions without making manual changes.
I also assume, you are using classes to style your pages, so there are no tag based styles in your CSS. Because you cannot rename the tags in the CSS file without braking it or make larger changes to your code.
If my assumptions are true, you could use something like grunt-css-prefix. It can add prefixes to your CSS classes for the login page, like in this snippet.
Original CSS file content:
.foo,
.bar,
h1 {
display: none;
}
CSS file content after running the Grunt script:
.login-foo,
.login-bar,
h1 {
display: none;
}
Just use the login-foo like class names in your Login-HTML and you are good to go.
For more details on how to use grunt-css-prefix, please have a look at https://www.npmjs.com/package/grunt-css-prefix.

Resources