postcss-single-spa-scoped
v1.5.0
Published
PostCSS plugin for manipulating the CSS in a single-spa application to best achieve scoped CSS
Downloads
318
Maintainers
Readme
postcss-single-spa-scoped
PostCSS plugin for manipulating the CSS in a single-spa application to best achieve scoped CSS.
.foo {
/* Input example */
}
#single-spa-application\\:\\@org\\/app-name .foo {
/* Output example */
}
Why...
Typically in single page application frameworks (Vue, React, etc.), there is a stylesheet imported at the global level.
// main.ts file
import './style.css';
These styles are not scoped to any component! This is typically a good thing as it allows you to share styles; but global stylesheets are a problem when your application is nested inside a microfrontend architecture. Why is it a problem? Because typically "import './style.css'" is compiled by bundlers into javascript code which mounts that style sheet in the head element as a style tag.
That style you defined in your style.css file? "h1 { font-size: 100px }".. It's now affecting the whole page!
This plugin attemps to counteract that by following the single-spa recomendation and prefixing all of your compiled css selectors with an id "#single-spa-application//:...". This works (for the most part) because your application is nested inside a div that single-spa creates that has the aforementioned fancy id.
There's a catch
Sometimes your application has portals (html outside the body) like modals or popups. These will typically leave the boundary of the single-spa div. That global style you defined will now not effect that portal because your now prefixed selectors wont select it.
To address this we added a field, additionalSelectors, to our plugin options. We expect an array of strings that are valid css selectors. We will then scope each original selector to each of the additional selectors you've provided along with the single-spa-id scope.
For example, if your pass ["#my-dialog"], the output will be:
#single-spa-application\:\@app1 .pointer-events-none,
#my-dialog .pointer-events-none {
pointer-events: none
}
This will help you address the portals issue! Give your portal an id and then add that id as an additional selector... now your portal will be selected.
Usage
Step 1: Install plugin:
npm install --save-dev postcss-single-spa-scoped
Step 2: Add the plugin to your config:
Vite
// postcss.config.cjs
export default {
plugins: {
"postcss-single-spa-scoped": {
// appName: "app1",
// additionalSelectors: ["#my-dialog"]
}
},
}
Plugin Options Type Definitions
type PluginOpts = {
appName?: string;
additionalSelectors?: string[];
}