Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Storybook menu option with icon

But when imported into the Next JS app and the same component used

enter image description here

The files seem to be available in the node_modules folder of the Next JS app enter image description here enter image description here

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!

like image 379
Jamadan Avatar asked Jul 03 '26 15:07

Jamadan


1 Answers

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!

like image 126
Jamadan Avatar answered Jul 05 '26 14:07

Jamadan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!