TailwindCSS Duplicate CSS classes when using library in app - reactjs

I have a component library using storybook & TailwindCSS and a host app that's also using TaildwindCSS itself that imports the component library. When the classes are generated, I'm seeing that they're duplicated:
Both projects import TailwindCSS standardly in their index.css files which is then imported into index.tsx using import "./index.css";:
The host app does generate all the classes from the component library when imported but due to there being duplicate classes, some are being overridden due to the order (pay attention to the source and line numbers in the above image)
The component looks correct on storybook:
Host app:
Looking for advice on how to correctly import the component library within the host app?
UPDATE:
I've figured that the component library generates it's own TailwindCSS classes as expected and that's where the "duplicate" classes (inline) come from and it's being included in a single output in index.js in the dist folder. Still need a way to avoid these duplicates when imported in the host app. May need to look at changing the component library to build a separate .css file with the styles and tell the host app to generate the component library's styles to prevent these duplicates.

After reading more on the TailwindCSS documentation, I've found a resolution. Using the following information from https://tailwindcss.com/docs/content-configuration#working-with-third-party-libraries, I was able to fix my issues.
Essentially what I've now done is, on my component library, I ensured that the.css styles are extracted into it's own file and not built into a single index.js. After that, on the host app, I set the content of tailwind config to reference my component library so that it scans the src and generates those classes itself.

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.

Building separate css for components in CRA app with SASS

Working on a new project setup, and trying to get figure out the configuration to get .scss files to build per component. Ideally, only the necessary css files would load per component added to a page, rather than an entire combined .css file for all components. I know this can be done with JSS, but I believe should work with webpack in a CRA app.
My current project setup is:
/src/App.js
/src/components/
index.js => exports all components for easy import to the page (i.e., import {ComponentName} from './components')
/src/components/{component-name}
{component-name.js}
{component-name.scss}
Currently trying sass#v1.56.1 and sass-loader#13.2.0, but not sure about the proper setup.
Might need to do a modular setup to accomplish this or just stick with JSS?

Nx workspace - Shared lib with tailwindcss and react

I struggled in setting this up, so I thought I would share my Knowledge.
Basically, I wanted to have a UI Kit / Component library with NX that could be shared with for example a webapp with react and a website built with Next.js.
I ran into this error:
Failed to compile
../../libs/shared-ui/src/lib/shared-ui.module.css
CssSyntaxError
([object Object]:[object Object]) Selector "*,
::before,
::after" is not pure (pure selectors must contain at least one local class or id)
[...]This is because you are trying to put Tailwind’s base styles in a CSS module, and CSS modules can’t contain those types of rules. This is just how CSS modules work, you shouldn’t put Tailwind’s base styles in a module, the two concepts are just not compatible. [...]
https://github.com/tailwindlabs/tailwindcss/issues/6717#issuecomment-1000805774
This branch contains the basic setup:
https://github.com/DanielSoCra/test-nx/tree/tailwind-shared-lib
Basically, I had NOT to import the css inside the lib, but in the apps/website and apps/webapp respecitvely.
For the rest of the configs with postcss and tailwind refer to the repository.

Typescript cannot load SVG as react components

I'm trying to import in Typescript some SVG icons, but I'm facing some problems.
At the first time I tried to import them, Typescript wasn't able to recognize the file extension.
I solved this issue by creating, as suggested in other Stack Overflow and Github topics, a custom.d.ts file with this rule inside:
declare module "*.svg" {
const content: React.StatelessComponent<React.SVGAttributes<SVGElement>>;
export default content;
}
But the problems seem to not finish here, even if the compilation seems going fine.
The current project I'm working on, is structured this way:
Typescript + React package (with SVG icons files) (SDK)
React Internal Sample page (package) to use the SDK
other internal packages...
For our development phase, we build through Webpack all the packages through different loaders and see the result through the Sample page.
But the final product flow to production is quite different: I export the SDK as CommonJS to an internal NPM Registry so another company can use it in a React project (the equivalent of the Sample page but for production) and push to production the final Webpack bundles with both projects inside.
So, to load in the Sample application the SVG icons, I'm using #svgr/webpack loader, which converts the files.
But when I have to export the SDK through npx tsc, I see that the exported folder, does not contain the folders with svg files.
I've tried to include them in tsconfig.json/files, but got this error:
TS6054: File '<path>/*.svg' has an unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts'.
So, to attempt exporting them I converted my exporting script to use #svgr/cli to export the files to React files from SVGs before compiling to typescript:
// package.json
scripts: {
"build-ts": "rm -rf ./lib; yarn convert-svg-to-react; npx tsc",
"convert-svg-to-react": "npx #svgr/cli -d src src --typescript",
}
In this way, I get the new Typescript files mixed with the SVGs inside the package (so I'll have to remove them later) and I can see them in the exported folder lib.
But watching inside the Typescript exported code, I can see this line (for each svg import):
var close_svg_1 = __importDefault(require("./icons/close.svg"));
Leaving out the Typescript function for Babel __importDefault, you can see that it still requires the file svg, but what I have at this point, are the React components that replaces those files.
During development it works fine because #svgr/webpack loader, resolves the svg files.
But requiring svg files that do not exist, should make the application above it crash.
So, I'm stuck and I need some clues to get out of this situation.
Some clues that I got (but wasn't able to find how to do that), were:
[Best] Find how I can export raw svg files as they are during Typescript compilation without doing that manually, as they are not all in one folder but divided per components areas in the package tree. Doing this, I would tell the other company to add #svgr/webpack to its own building process.
Find how can I tell Typescript to import svg files without specify the extension (currently, removing .svg probably makes it fallback to .ts/tsx and therefore it cannot find the file with that name). In this way, the require would keep requiring the same file name but I could convert SVG to React Components without occurring in problems. But this would also require Typescript to export the file
Otherwise, I should convert all the SVGs in React components and directly use them instead of making them being compiled by #svgr/webpack, but I'm not sure this would have some other side-effects.
Any other clues or any way to achieve the ideas I got? Thank you everybody.

React tree-shakable component library with Rollup and Sass

I have a requirement which I'm not sure if can be achieved with Rollup (or with Webpack?)
I've written a React component library. Each component imports it's stylesheet. Something like
import "./button.scss"
export default function Button() {
...
}
Now, these scss files use sass variables of all sorts that I would like to define in a global file.
I want the consumer of my library to be able to import Button as so:
import { Button } from "mylib" or even better:
import Button from "mylib/button"
and have only the code required by Button be added to my library.
I can't for the life of me figure/google out how to achieve this.
Is there a good reference to a tree-shakable React component library that uses sass and sass variables?
Bonus question:
I have some third party css that only some of the component require.
So, if each of the component's scss files imports:
#import "~some-third-party-css-lib.css"
Will Rollup duplicate that css? Or is there some kind of deduping mechanism?
Thanks!
From what I know now (Feb 2020) the only options to achieve good tree-shaking results for a component library are:
When using css modules
You need to rely on the consumer of your library to handle the (s)css imports (Create React App for example is doing this pretty well)
Make sure to not transpile/bundle the css in your package and that the import paths are correct
Make the consumers import each component separately (import Button from "mylib/button"). This is because css imports are considered side-effects by most bundlers and it's petty hard (maybe even impossible) to tell which classes are actually used. So if you have an index in your library that re-exports all components, this causes ALL css to be imported and probably bundled.
When using a css-in-js system with a runtime
also make sure that you do not pre-bundle/export the css in the library build-step but rather have that leave that to the consuming app.
This has some implications that should be considered.
The consumer of your components must ship a css-in-js runtime alongside their app
If the consumer is trying to do server-side pre-rendering in some sort that might require custom additional steps depending of the css-in-js library you're using
Conclusion
As of now I don't know a solution that supports full tree-shaking (including css) while also not imposing additional complexity to the consuming app. But I'm currently still investigating this topic and will post updates here if I find something interesting.
Look at the library tailwindcss. It automatically purges the unused css variables.

Resources