How To Load Custom CSS or SASS Styles Into Single SPA Framework
As you may already know, Single SPA is a Javascript framework that allows we developers to implement our single page front-end application using multiple single-page applications build in react or any other single page application framework, hence the name Single Single Page Application. Single SPA framework will load Javascript bundles of each application from their hosts and inject them into the DOM of our landing page at runtime.
You can find more about this awesome front end framework in their official documentation.
But if you used create-react-app (cra)tool to generate a micro-frontend react application, you may have faced a problem (that’s why you are here, isn’t it?) where CSS styles will not be loaded into the Single SPA in production environment although they are loaded fine in the development environment. You can fix this issue by overriding webpack configurations in the react application.
TL;DR
Before looking at why this error occurs in the first place, let’s look at something you can use now, how to configure webpack to get your styles working.
Note: There are several libraries you can use to override react-scripts webpack configurations without ejecting, such as “customize-cra”, “react-app-rewired”, “react-scripts-rewired” and “rescripts”. I will be using “rescripts” in this article.
1. Install @rescripts/cli and @rescripts/utilities
npm i -D @rescripts/cli @rescripts/utilities
2. Replace react-scripts scripts in package.json with rescripts
3. Create .rescriptsrc file
Create a .rescriptsrc file (with .js or .json extension or no extensions) in root of the source code folder which rescripts will read configurations from.
4. Add required configurations
edit utility in rescripts utilities follows a “matcher-transformer” pattern where matcher is a predicate which is used to find the part of configurations that should be edited and transformer is a function which states how matching part of the configurations should be edited.
Note: We are using the “lazyStyleTag” inject type in style-loader which will configure style-loader to add and remove style tags from DOM as we need. We can use styles.use() and styles.unuse() functions in our react application to load styles into DOM when our application is mounted and remove once unmounted.
The following gist shows how to do it in our root React component “app” which is a functional component written in the app.js file.
What about sass?
All the steps mentioned below are the same for SASS styles except for a few changes in webpack configurations.
sass-loader which is inserted at the end of the loaders array will convert SASS files into CSS at build time and then processed as same as the CSS files.
As now we know how to fix styles in our Single SPA, let’s look at why this problem occurs in the first place.
WHY?
When you generate a react application using the create-react-app tool (cra), it installs and uses another set of tools called react-scripts to build and run the react application. react-scripts uses webpack tool underneath to build a react application like you would do if you did not use cra. The difference is that you do not have to manually configure webpack yourself as react-scripts comes with a set of default webapck configurations.
In these configurations, react-scripts has specified how to load styles into react application in webpack module rules configurations in loaders arrays. Webpack loaders are how webpack processes each type of file in the react application such as .js or .css. I do not plan to go deep into loaders as it is out of the scope of this article.
If you peek into default configurations provided with react-scripts (located at <path_to_your_react_project>/node_modules/react-scripts/config/webpack.config.js) you can see that react-scripts uses the loader of “mini-css-extract-plugin” to load the CSS or SASS files in production environment whereas “style-loader” is used for development environment on top of css-loader and postcss-loader in the both environments.
As webpack loaders are executed as a stack, the last loader in the loaders array will be executed first and the one before that next and so on. Therefore, firstly “postcss-loader” will pre-process CSS styles using tools like auto-prefixer and provide processed CSS strings to “css-loader” to resolve assets mentioned in “@import” or “url()” statements. After that, depending on the runtime environment, styles will be processed by either “mini-css-extract-plugin loader” or “style-loader”.
mini-css-extract-plugin loader — Production Environment
the mini-css-extract-plugin loader will create static CSS files from commonJS modules provided by css-loader and inject links of those files into index.html file of the single page application in build time. When single page application is hosted and served in a production environment these styles will be loaded in parallel with JavaScript bundles.
style-loader — Development Environment
Compared to the mini-css-extract-plugin loader, the style-loader will not create separate CSS files. style-loader will inject CSS styles into the js bundle and load them into DOM using Javascript in runtime.
Important part
In the Single SPA framework, only js bundles of micro-frontend applications are loaded, without index.html files. Therefore, there will be no reference to styles in frontend application in the production environment. That’s why styles won’t be loaded in the production environment although they work fine on localhost in the development environment.