'Individual component exports with Rollup instead of one massive index.js file?

I’m working on a proprietary component library built with React and using Rollup to bundle everything. Currently, it’s bundling everything into these files:

dist
 ├ cjs
 │  └ index.js (1.7mb)
 └ esm
    └ index.js (1.7mb)

My hope is that I could instead have every component be bundled individually so the consuming app doesn’t have to download a huge index.js file, but this may be where my inexperience with Rollup kicks in.

I currently have a single entrypoint for Rollup:

input: [
    'src/index.js',
],

My index.js file looks something like this (but with many more components):

import { Badge } from './components/Badge';
import { Button } from './components/Button';
import { CardFooter } from './components/CardFooter';
import { CardHeader } from './components/CardHeader';
import { CardTagList } from './components/CardTagList';
import { CardToolbar } from './components/CardToolbar';
import { CartAnimation } from './components/CartAnimation';

export {
    Badge,
    BasePrice,
    Button,
    CardFooter,
    CardHeader,
    CardTagList,
    CardToolbar,
    CartAnimation,
};

What do I have to do to ensure that components are each bundled separately and can still be imported in the apps that use the library with:

import { Button } from '@company/component-library';

Here is my full config as it stands today:

import { babel } from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';
import commonjs from '@rollup/plugin-commonjs';
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
import eslint from '@rollup/plugin-eslint';
import json from '@rollup/plugin-json';
import resolve from '@rollup/plugin-node-resolve';
import stylelint from 'rollup-plugin-stylelint';
import styles from 'rollup-plugin-styles';

require('dotenv').config();

export default {
    external: [
        'react',
        'react-dom',
        'styled-components',
    ],
    input: [
        'src/index.js',
    ],
    output: [
        {
            // Bundle into ESM for modern consumers.
            // Only ESM build can currently be tree-shaken.
            dir: 'dist/esm',
            format: 'esm',
        },
        {
            // Bundle into CJS for other consumers.
            dir: 'dist/cjs',
            format: 'cjs',
        },
    ],
    plugins: [
        eslint({
            include: '**/*.js',
            throwOnError: true,
        }),
        stylelint(),
        babel({
            babelHelpers: 'bundled',
            exclude: 'node_modules/**',
        }),
        resolve({
            browser: true,
        }),
        styles(),
        commonjs(),
        json(),
        dynamicImportVars({}),
        terser(),
    ],
};

Note: Probably not important, but this project is published to npm as a private repo, but currently the app that uses it installs it using a commit hash.



Solution 1:[1]

You could try adding the preserveModule

export default {
  preserveModules: true,
  ...
}

Solution 2:[2]

I have done some tweek to the rollup config. My problem statement was to export custom elements seperately. Find my custom solution below:

function generateComponentConfig() {
const dir = fs.readdirSync("./src/web-components");
return dir.map(folderName => {
    return {
        input: [`src/web-components/${folderName}/index.js`],
        output: [
            { file: `public/build/wc/${folderName}.mjs`, 'format': 'es' },
            { file: `public/build/wc/${folderName}.js`, 'format': 'umd', name: folderName }
        ],
        plugins: [
            svelte({ compilerOptions:{customElement: true}, emitCss: false, include: /\.wc\.svelte$/ }),
            svelte({ compilerOptions: {customElement: false}, emitCss: false, exclude: /\.wc\.svelte$/ }),
            resolve()
        ]
    };
})};

Use the above function in your export as below

export default [
...generateComponentConfig(), {
input: 'src/main.js',
output: {
  sourcemap: true,
  format: 'iife',
  name: 'app',
  file: 'public/build/bundle.js',
},
plugins: plugins(),
watch: {
 clearScreen: false,
}}];

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dharman
Solution 2 Shivang Gupta