Developing an easily optimized library using rollup to remove unnecessary code branches

I'm currently in the process of developing a component library using rollup and Vue with the goal of making it tree shakable for others who import it. The configuration setup is outlined below:

Here's a snippet from package.json

{
  "name": "red-components-with-rollup",
  "version": "1.0.0",
  "sideEffects": false,
  "main": "dist/lib.cjs.js",
  "module": "dist/lib.esm.js",
  "browser": "dist/lib.umd.js",
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w"
  },
  "devDependencies": {
    /* ... */
}

And this is my complete rollup.config.js

import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import vue from "rollup-plugin-vue";
import pkg from "./package.json";

export default {
  input: "lib/index.js",
  output: [
    {
      file: pkg.browser,
      format: "umd",
      name: "red-components"
    },
    { file: pkg.main, format: "cjs" },
    { file: pkg.module, format: "es" }
  ],
  plugins: [resolve(), commonjs(), vue()]
};

I have a straightforward project structure with an index.js file and two Vue components:

root
 ∟ lib
    ∟ index.js
    ∟ components
       ∟ Anchor.vue
       ∟ Button.vue
 ∟ package.json
 ∟ rollup.config.js

My index.js imports the Vue files and exports them:

export { default as Anchor } from "./components/Anchor.vue";
export { default as Button } from "./components/Button.vue";

export default undefined;

If I don't include export default undefined; somehow, any application importing my library won't be able to find any exports. Strange.


Now, when I integrate my library into another app by importing red-components-with-rollup like this:

import { Anchor } from "red-components-with-rollup";

and inspect the bundle in my app, I notice that the source code of Button.vue is also included in the bundle; it hasn't been stripped out as dead code.

What could be the issue here?

Answer №1

What happens to the ES format build outcome? Does it result in a single file or multiple files similar to your source files?

It seems like with your Rollup options, everything is bundled into one file which may be why tree-shaking isn't working.

If you want your ES build to output multiple files, make the following changes:

{ file: pkg.module, format: "es" }

Change it to:

{
  format: "es",
  // Specify a directory instead of a file for multiple outputs
  dir: 'dist/esm'
  // Keep each module in a separate file
  preserveModules: true,
  // Optionally remove unnecessary path from the source
  preserveModulesRoot: 'lib',
}

Update your package.json to point module to the new build file, something like

"module": "dist/esm/index.js"
.

Answer №2

There's an insightful discussion on tree shaking pitfalls in this article that you may find intriguing.

In addition, it's essential to ensure that your build tooling for the consumer app supports pure ES modules and has tree shaking capabilities. It's important to avoid any 'side-effecty' actions in your exported files that could confuse Rollup.

As a precaution, consider offering direct imports for each component along with a main index.js file that exports them all. This way, you provide the option for those who are concerned about including unused code ie -

import { Anchor } from "red-components-with-rollup/Anchor";

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Delve into the art of utilizing negative space between elements with

Looking to implement hover detection between rows in a grid container, rather than on individual items. The number of items in the container and per row may vary. It's important to note that the item count in the container and rows is dynamic. The c ...

Is there a way to postpone the execution of a scheduled interval function?

Below is the setup of my function: setInterval(function () { get_fb(); }, 10000); If a user interacts with an element, such as hovering over it or clicking on it, I want to reset the timer back to 10 seconds. How can I instruct the program to achieve th ...

Avoiding the repetition of CSS animations during Gatsby page hydration

I am facing an issue in Gatsby where I have an element with an initial CSS animation. It works perfectly when the static site loads, but after hydration, it keeps repeating. Is there a way to prevent this from happening? Below is my styled components code ...

Can lazy loading be implemented for the video tag using JavaScript?

Currently, I am in the process of working on a project that entails incorporating three videos onto the homepage. However, loading them simultaneously is causing a significant decrease in load time. In addition, I prefer to utilize the <video/> tag ...

What is the best way to allocate a unique color to every item within an array?

I've been working on some JavaScript code that pulls a random color from a selection: const colors = [blue[800], green[500], orange[500], purple[800], red[800]]; const color = colors[Math.floor(Math.random() * colors.length)]; Within my JSX code, I ...

Exploring ways to extract HREF using Selenium in combination with Node JS

I am having trouble extracting the hrefs from my web element using .getAttribute("href"). It works fine when applied to a single variable, but not when looping through my array. const {Builder, By, Key, until} = require('selenium-webdriver'); (a ...

Upon mounting, Vue.js 3 composable data is not available

Currently, I am utilizing Vue.js 3 along with a basic test composable: TEST COMPOSABLES Load post id: {{ i }} <div v-if="error"> <p>Uh oh! An error has occurred: {{ error.message }}</p> <button @click="r ...

Loop through the JSON data to obtain distinct values for certain indices

My PHP script retrieves data with the following query: SELECT objective,signal_type,signal_name FROM signals WHERE channel="Email" This is how the data is returned: [ { "objective": "Awareness", "signal_type": "Efficiency", " ...

Swap out the svg element with an icon alternative

Transforming Circle Elements into Shopping Cart Icons I am attempting to change the appearance of my SVG circle elements to resemble shopping carts. Is there a method to completely alter the definition of a circle element in svg so that it displays a spec ...

Sharing State with a Secure Route in Vue Router (using the script setup method)

Hello everyone, I'm encountering an issue while trying to send a state to the protected routes in vue-router. The error that I faced mentioned "Discarded invalid param(s) "_id", "dish_name", "description", "img" ...

Leveraging @click within dropdown selections - Vue.js 2

Is there a way to implement the @click event in select options? Currently, I have the following: <button @click="sortBy('name')">sort by name</button> <button @click="sortBy('price')">sort by price</button> Th ...

Utilizing Javascript / jQuery to eliminate specific CSS styles

I am facing an issue with the CSS code for a table positioned at the bottom of the screen. The current code includes a filter specifically for IE 8, but I need to make it compatible with IE 10 as well by removing the filter and adding a background color. ...

Discovering discrepancies between an empty array and undefined in Mongoose

How can I distinguish between an empty array and a null/undefined value when retrieving data from MongoDB using Mongoose? Mongoose treats both as empty arrays, but the actual meanings in the database are different. For example: var Mongoose = require(&apo ...

Concealing applicationId and clientToken in Datadog

I'm currently using an Angular application and I've integrated it with the Datadog application to utilize Session and Replay (RUM). However, I am concerned about the security of my sensitive information such as applicationId and clientToken. Is t ...

Modifying the CSS design of specific columns within a table created using JavaScript

A unique way to showcase JSON data in a table is by utilizing a for loop within a function. This method, however, does not assign an ID or Class to the table. To hide the final three columns of this table using CSS, the following code can be employed (whe ...

Controlling an AJAX request to fetch individuals

I am currently using an ajax request to display people data on the page, which is retrieved from a backend database. The search form on the page includes options for location, sector, service, and job title. Below is the javascript code being used: //var ...

Tips for Transferring Values Between Multiple Dropdown Menus with jQuery

Hello there, can anyone guide me on how to transfer selected items from one multiple combo box to another multi-combo box? I would really appreciate it if someone could provide an example for this scenario. <HTML> <HEAD> <TITLE></T ...

The mongoose library requires JSON input, yet it is unable to generate a dynamic JSON object from a Node

This question delves more into javascript and JSON concepts rather than focusing on the mongoose library. When working with Mongoose, conditions are expected to be in JSON format, like so: { $or: [ { "doc_no" : /first/i }, { "doc_type" : /second/i } ] ...

`I'm getting an unexpected result when using the click function`

I have been facing an issue with retrieving the updated value from a data controlled by v-model within a component. Despite observing changes in the app and Vue dev tools, whenever I try to console log the data, it consistently displays the previous value ...

Error: The term "Worker" is undefined in a new Nextjs project

I'm currently looking into an issue where I am attempting to import a webpacked javascript file into a NextJS project that utilizes Worker, but I keep encountering the error message ReferenceError: Worker is not defined. I've simplified it down t ...