Rollup - how to prevent CSS import from d.ts file? - css

I have a React & Typescript / tailwind / postcss / Rollup setup to build a component library, at this repo.
Everything is working as intended apart from one issue; a corresponding import for ../styles/index.css is being included in the outputted dist/index.d.ts file. I wish to have declarations for my components, but not this CSS import.
The problem is that this index.css file is outside the dist directory, and is not included in the final library. Instead, the minified and purged tailwind css file is being generated and used instead.
Current solution
I am currently relying on a post-build command to remove the import from the file using sed:
scripts: {
...
"build": "rollup -c && cp dist.package.json dist/package.json",
"fix": "sed '1d' ./dist/index.d.ts > ./tmp.d.ts; mv ./tmp.d.ts ./dist/index.d.ts",
}
I do not feel this is an optimal approach. If I can prevent the import in the build process instead, this would be preferred.
Similar issues
I found this issue but the pseudo code provided does not work / is not complete. Furthermore, this feels like a workaround rather than an actual fix.
rollup.config.js
For what it is worth, my current rollup config is as follows:
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import resolve from "#rollup/plugin-node-resolve";
import typescript from "rollup-plugin-typescript2";
import postcss from "rollup-plugin-postcss";
import del from "rollup-plugin-delete";
import simplevars from "postcss-simple-vars";
import nested from "postcss-nested";
import cssnext from "postcss-cssnext";
import cssnano from "cssnano";
/**
* #type {import('rollup').RollupOptions}
*/
export default {
input: "lib/index.tsx",
output: [
{
file: "dist/index.tsx",
format: "es",
sourcemap: false,
},
],
plugins: [
del({ targets: "dist/*" }),
peerDepsExternal(),
postcss({
config: {
path: "./postcss.config.js",
},
plugins: [
simplevars(),
nested(),
cssnext({ warnForDuplicates: false }),
cssnano(),
],
extensions: [".css"],
minimize: true,
modules: false,
extract: "index.css",
}),
resolve(),
typescript({
useTsconfigDeclarationDir: true,
}),
],
};

Related

Configuring Vanilla TS Vite project to keep CSS files separated

I am trying to set up a basic (css) library with vanilla TS and Vite 4.
I want to have a main js and css file at the top level so you can import the whole thing in one go. I also want to have component level imports where you can chose to just import the components js + css. The combined css and JS files are working fine; and the individual component JS file is working fine too.
Currently I'm running into the problem where I can't seem to keep an isolated version of the CSS files next to the JS files after bundling. My build is currently creating :
I've gone over the docs of both Vite and Rollup but I can't seem to figure out how to do the same to my CSS as I'm doing to my JS.
dist
--components
----button
------button.js
--main.css
--main.js
My preferred output would be:
dist
--components
----button
------button.js
------button.css
--main.css
--main.js
In my `main.ts` I'm importing:
import './style.scss'
import './tokens.scss'
import './components/button/button.scss'
vite.config.js
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
build: {
cssCodeSplit: false,
manifest: true,
rollupOptions: {
output: {
assetFileNames: () => 'main[extname]',
}
},
lib: {
formats: ['es'],
entry: {
main: resolve(__dirname, 'src/main.ts'),
button: resolve(__dirname, 'src/components/button/button.ts')
},
name: 'CSSFramework',
fileName: (_, fileName) => fileName === 'main' ? '[name].js' : 'components/[name]/[name].js',
},
},
});
Thanks in advance !

React component library, how to correctly bundle fonts with rollup

I'm working on a project which has a React component library, and a Next JS app which imports said library. I've read a lot of questions on SO and attempted most of the solutions to no avail.
We have the component library working, fonts and all, and in storybook looks great
There's two fonts we import in our package.json (in devDependencies)
"#fontsource/inter": "4.5.12",
"#fontsource/material-icons": "4.5.4",
The material-icons font is imported in our <Icon /> component
import "#fontsource/material-icons";
And referenced in the tailwind config
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx,mdx}"],
theme: {
fontFamily: {
sans: ["Inter", "ui-sans-serif", "sans-serif"],
heading: ["Inter", "ui-sans-serif", "sans-serif"],
},
This works in storybook with no problems
But when imported into the Next JS app and the same component used
The files seem to be available in the node_modules folder of the Next JS app
Here is the roll up config:
import resolve from "#rollup/plugin-node-resolve";
import commonjs from "#rollup/plugin-commonjs";
import typescript from "rollup-plugin-typescript2";
import postcss from "rollup-plugin-postcss";
import dts from "rollup-plugin-dts";
import json from "#rollup/plugin-json";
import pkg from "./package.json";
export default [
{
input: "src/index.ts",
output: [
{
file: pkg.main,
format: "cjs",
sourcemap: true,
},
{
file: pkg.module,
format: "esm",
sourcemap: true,
},
],
plugins: [
resolve(),
commonjs(),
typescript({ tsconfig: "./tsconfig.json" }),
postcss(),
json(),
],
external: [
"react",
"react-dom",
"#fontsource/inter/400.css",
"#fontsource/inter/600.css",
"#fontsource/inter/700.css",
"#fontsource/material-icons",
"react-loading-skeleton/dist/skeleton.css",
],
},
{
input: "dist/types/index.d.ts",
output: [{ file: "dist/index.d.ts", format: "esm" }],
plugins: [dts()],
external: [
"react",
"react-dom",
"#fontsource/inter/400.css",
"#fontsource/inter/600.css",
"#fontsource/inter/700.css",
"#fontsource/material-icons",
"react-loading-skeleton/dist/skeleton.css",
],
},
];
QUESTION: what I'd ideally like to do is export all the referenced css from the component library, such that in the next app's _app.tsx I can use
import "#us/component-library/styles.css";
How do I configure rollup to bundle the referenced css and expose it in the build folder?
Also: if there is an alternative or better way of doing this, we aren't precious over the plugins used and would be open to being shown a better (or correct) way of doing this.
Appreciate any help!
If anyone is still in the same boat - here's how I solved it in the end...
New rollup.config.js
import resolve from "#rollup/plugin-node-resolve";
import commonjs from "#rollup/plugin-commonjs";
import typescript from "rollup-plugin-typescript2";
import postcss from "rollup-plugin-postcss";
import dts from "rollup-plugin-dts";
import json from "#rollup/plugin-json";
import pkg from "./package.json";
import copy from "rollup-plugin-copy";
export default [
{
input: "src/index.ts",
output: [
{
file: pkg.main,
format: "cjs",
sourcemap: true,
},
{
file: pkg.module,
format: "esm",
sourcemap: true,
},
],
plugins: [
postcss(),
resolve(),
commonjs(),
typescript({ tsconfig: "./tsconfig.json" }),
json(),
copy({
targets: [
{
src: "node_modules/#fontsource/inter/files/*",
dest: "./dist/files",
},
{
src: "node_modules/#fontsource/material-icons/files/*",
dest: "./dist/files",
},
],
}),
],
external: ["react", "react-dom"],
},
{
input: "dist/types/index.d.ts",
output: [{ file: "dist/index.d.ts", format: "esm" }],
plugins: [dts()],
external: ["react", "react-dom"],
},
];
Then in src/theme/input.css
#import url("../../node_modules/#fontsource/inter/400.css");
#import url("../../node_modules/#fontsource/inter/600.css");
#import url("../../node_modules/#fontsource/inter/700.css");
#import url("../../node_modules/#fontsource/material-icons/index.css");
#import url("../../node_modules/react-loading-skeleton/dist/skeleton.css");
#tailwind base;
#tailwind components;
#tailwind utilities;
...
foo {
bar...
Then in our consuming Next app, I no longer have to have the #fontsource/font import in the package.json.
In my head, this works because the rollup build, using rollup-plugin-postcss, leverages the css imports and bundles everything together as part of the css, rather than trying to re-package imports or manage external dependencies from the consuming app.
Pretty sure my rollup config can still be trimmed down, in particular where I'm using rollup-plugin-copy to copy the #fontsource/font files. But for now this is working and means our consuming apps don't need to care about importing fonts.
However, this has is drawbacks as I'm not sure how this would work if we wanted to override the font.
Perhaps re-defining the inter font in the calling app? And then assigning something else to it?
Or maybe overriding the fontFamily in our tailwind config? Not sure yet. Will update when I have a better answer.
Hope this helps someone else - when I get more time to spend on trimming the rollup config I'll post the latest.
Kia Ora!

Rollup and building everything in my styles folder to a stylesheet and insert it into html

So, I am creating a react component library and the individual scss files within those components are fine... but I also have "global" scss that are "site wide". Because I am using storybook, I am not seeing these "global styles" being applied. My source code shows no "inline css files". Of course, when I grep for "styles" FROM the component, they are built within the js.....
....but I need to also have these "site wide" files... these describe like h1,h2,h3.. spacing etc.. that I just using on the component propers.. ie... className="spacing-lg border-dark" etc..
My goal is to have rollup "build" these scss global files and include them in the html/storybook main site... BUT also export them out for consumption.
rollup config: (I am new to rollup)
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import resolve from "rollup-plugin-node-resolve";
import typescript from "rollup-plugin-typescript2";
import sass from "rollup-plugin-sass";
import commonjs from "rollup-plugin-commonjs";
import copy from "rollup-plugin-copy";
import postcss from 'rollup-plugin-postcss';
import autoprefixer from 'autoprefixer'
import scss from 'rollup-plugin-scss'
import url from "rollup-plugin-url"
// update input to use #rollup/plugin-multi-entry
export default {
input: ["src/index.ts", "src/Button/Button.tsx"],
output: [
{
dir: 'build',
format: "cjs",
sourcemap: true
},
{
dir: 'build',
format: "esm",
sourcemap: true
}
],
preserveModules: true,
plugins: [
peerDepsExternal(),
resolve(),
commonjs(),
typescript({ useTsconfigDeclarationDir: true }),
copy({
targets: [
{
src: "src/styles/_variables.scss",
dest: "build",
rename: "variables.scss"
},
{
src: "src/styles/_typography.scss",
dest: "build",
rename: "typography.scss"
}
]
})
postcss({
extract: 'bundle.css',
plugins: [
sass({
insert: true
})
]
})
]
};
so, my goal is to be able to "bring in the components I want from the npm (where this will be built) and also the various css files, variables, colors etc... BUT, the components themselves within storybook needs to reference these "globals" and they are not atm.

Gzipping css files in Rollup

I am trying to bundle my js and scss files in rollup ready for production.
Rollup takes all of my files and outputs them to a build dir, the result looks like this:
build
css
bundle.css
js
bundle.js
bundle.js.gz
As you can see, I am using the gzipPlugin for my js files.
I also want to use gzipPlugin to handle my css, but I cannot figure out how to do this.
My current setup looks like this:
import babel from "rollup-plugin-babel";
import { terser } from "rollup-plugin-terser";
import multi from "#rollup/plugin-multi-entry";
import gzipPlugin from "rollup-plugin-gzip"
import scss from "rollup-plugin-scss"
import del from "rollup-plugin-delete"
export default [{
input: "src/**/*.logic.js",
output: {
file: "build/assets/js/main.min.js",
format: "umd",
name: "Logic"
},
plugins: [
del({ targets: "build" }),
gzipPlugin(),
terser({
output: {
wrap_iife: false
}
}),
multi({
exports: true
}),
babel({
exclude: "node_modules/**"
})
]
}, {
input: "src/all.scss",
plugins: [
scss({
output: "build/assets/css/styles.min.css",
outputStyle: "compressed"
}),
]
}
];
My question is:
How can I get my outputted css file to be gzipped?.
I think I am missing something fairly simply, I just can't see how to get gzipPlugin working on the css file.... thanks in advance for any tips.
I think that you just need to add the gzipPlugin in the plugins session of your CSS generation.
Like this:
input: "src/all.scss",
plugins: [
scss({
output: "build/assets/css/styles.min.css",
outputStyle: "compressed"
}),
gzipPlugin()
]
I was able to accomplish this by specifying the additionalFiles option:
// rollup.config.js
...
import gzipPlugin from "rollup-plugin-gzip";
import css from "rollup-plugin-css-only";
export default {
input: "src/main.js",
output: {
...
file: "public/build/bundle.js",
},
plugins: [
gzipPlugin({
additionalFiles: ["./public/build/bundle.css"],
}),
css({ output: "bundle.css" }),
...
]
}
One little quirk I ran into was that the build has to be run twice. The first time without gzip to generate the bundle.css and the second time to gzip the bundle.css from the previous run.

How to use css #import in rollup?

I try to create a simple rollup app's config and have some troubles with css.
This is my css file:
#import "normalize.css";
#import "typeface-roboto";
html, body, #root {
height: 100%;
font-family: Roboto, serif;
}
body {
background: url('./images/background.jpg');
}
And all what i have is 3 errors about not found resources.
This is my config file:
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import babel from 'rollup-plugin-babel'
import replace from 'rollup-plugin-replace'
import postcss from 'rollup-plugin-postcss'
import html from 'rollup-plugin-fill-html'
import url from "rollup-plugin-url"
process.env.NODE_ENV = 'development'
const CWD = process.cwd()
const Paths = {
SRC: `${CWD}/src`,
DIST: `${CWD}/dist-rollup`,
NODE_MODULES: `${CWD}/node_modules`
}
Object.assign(Paths, {
INPUT: Paths.SRC + '/index.js',
OUTPUT: Paths.DIST + '/index.js'
})
export default {
input: Paths.INPUT,
output: {
file: Paths.OUTPUT,
format: 'iife', // immediately-invoked function expression — suitable for <script> tags
// sourcemap: true
},
plugins: [
html({
template: `${Paths.SRC}/template.html`,
filename: 'index.html'
}),
postcss({
modules: true,
plugins: [
]
}),
url({
limit: 10 * 1024, // inline files < 10k, copy files > 10k
}),
resolve(), // tells Rollup how to find date-fns in node_modules
babel({
exclude: 'node_modules/**'
}),
commonjs(), // converts date-fns to ES modules
replace({ 'process.env.NODE_ENV': JSON.stringify('development') })
]
}
I was tried to use some plugins like rollup-plugin-rebase and postcss-assets, but unfortunately, it did not help me.
Maybe i chose not common way, but single working solution for me is use postcss with 2 plugins: postcss-imports for #import syntax and postcss-url for url.
But there were difficulties too.
Postcss-url don't want just work, like i expect.
I had to use 3 instance of this plugin:
[
postcssUrl(), // Find files' real paths.
postcssUrl({
url: 'copy',
basePath: 'src',
useHash: true,
assetsPath: 'dist'
}), // Copy to required destination.
postcssUrl({
url (asset) {
const rebasedUrl = `dist/${path.basename(asset.absolutePath)}`
return `${rebasedUrl}${asset.search}${asset.hash}`
}
}) // Fix final paths.
]
You may see it in complex on https://github.com/pashaigood/bundlers-comparison
And of course, i will be glad to see more simple solution if you know that, please, share with me.
I've found css-import to work well, the NPM package provides a cssimport command line interface that accepts a main CSS file which includes #import statements and an optional list of directory in which to search for the CSS; it outputs to stdout the merged CSS which can be written to a single file.
I use the following to output a single main.css file in my build directory, searching for imported files under node_modules:
cssimport main.css ./node_modules/ > ./build/main.css
When using rollup you can use the rollup-plugin-execute plugin to execute a shell command as part of rollup's build process. For example:
plugins: [
...
execute('npx cssimport main.css ./node_modules/ > build/main.css')
]

Resources