I have a series of small atomic packages that I want to be able to publishing and versioning independently, all within a monorepo using TurboRepo.
When these components were used as "internal" components, there was no issue.
However, when I tried to perform builds, I discovered that I couldn't get any CSS styles applied to these components when they were imported and used in my Next.js application (/apps/web).
For example, the Button package contains a single file named Button.tsx
and a file named Button.module.scss
.
import styles from './Button.module.scss';
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
{
className,
...restProps
},
ref
) => {
return (
<button className={styles.base} ref={ref} {...restProps}>
...
</button>
);
}
);
My vite.config.js
looks like :
import path from 'path';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
export default defineConfig({
build: {
minify: 'terser',
lib: {
formats: ['es', 'cjs'],
entry: path.resolve(__dirname, 'src/index.ts'),
name: 'Button',
fileName: format => `button.${format}.js`,
},
rollupOptions: {
// externalize deps that shouldn't be bundled
// into your library
external: ['react', 'react-dom'],
output: {
exports: 'named',
sourcemap: true,
format: 'es',
preserveModules: true,
},
treeshake: true,
},
},
plugins: [
react(),
dts({
copyDtsFiles: true,
exclude: ['**/node_modules'],
insertTypesEntry: true,
}),
],
});
The package.json :
"name": "@company/components__button",
"version": "0.0.1",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/button.es.js",
"require": "./dist/button.cjs.js"
}
},
"files": ["dist/**"],
Here is a partial view of the output dist files.
Then, I import the package in my Next app (apps/web) like this :
"@company/components__button": "workspace:*",
Now, I can import it, but** no style is applied** at runtime !
However, If I inspect the DOM, I can see the class on the button DOM node:
<button class="_base_3rp5a_4" type="submit">create an account</button>
Upon inspecting the network tab, there is a GET request fetching the page's CSS. However, the payload only contains the CSS defined at the Next.js application level and used on this same page but none of the styles included in the imported package...
Shouldn't it also include the CSS of the button imported from my package?
Does Next.js is struggling to reconcile dynamic classes with their associated styles at runtime. Am I approaching this incorrectly? Have I missed something in the configuration?
I would like the style associated with the imported package to be applied correctly.
I followed this guide : https://turbo.build/repo/docs/handbook/publishing-packages/bundling
Edit finale solution :
I have created an additional package called @company/components__css
, which includes a script enabling the retrieval of the style.css
derived from the build
folder of each component package (@company/component__button
).
In the package.json
of the new css package, I add the list of components as dependencies. This is done so that TurboRepo adheres to the build order as follows :
dist
folder.index.css
file and removes styles.css
from the components packages. Each component package operates autonomously. The removal of style files occurs only in context of monorepo (They are useless in the final build).globals.scss
file, like so:
@import url('@company/components__css');
.Finally, the reconciliation process proceeds seamlessly, the style is successfully fetched on the browser side, and consequently, becomes active.
You can find an example of the finale solution here.
Since you are bundling your UI library through esbuild
, there shall be couple of files generated by esbuild
in dist
directory.
index.js
index.js.map
(only if you enable sourcemap)style.css
(this is very important)The issue here is that, you need to import that style.css
in the Next.js app which uses the above UI library by,
import '<path to the style.css>';
Which is why even though you have the CSS classes in your HTML elements (from the index.js
part of your UI library), no styles are applied (because those CSS classes don't exist in your DOM)