What is the best way to divide a library and its plugins into separate npm packages?

I am currently developing a JavaScript library that allows users to select specific plugins to add to their project along with the main library. However, I am facing some challenges with modules and webpack. To illustrate how the code is structured, I am writing pseudo code.

Here is an excerpt from my index.js file for the main library:

import ClassA from "./classA";
import ClassB from "./classB";

export default class MyLib { 
    .....
}
export { ClassA, ClassB } 

Successfully outputting the library with webpack:

output: {
     path: ...
     filename: 'mylib.min.js',
     library: "MyLib", 
     libraryTarget: "umd"
}

To allow users to choose which plugins to incorporate, I am creating individual npm packages for each plugin, making MyLib an external dependency, and then implementing:

import {ClassA, ClassB} from "MyLib";


class PluginA extends ClassB {
   constructor() {
      this.test = new ClassA();
   }
}

Although this approach works well, compiling PluginA with webpack ends up including MyLib in the final js file for PluginA. If multiple plugins are added, the main lib will be duplicated in the code.

My ultimate objective is to structure the code in a way that makes it easy to install using the following npm commands without redundant code:

npm install MyLib
npm install MyLib-PluginA
npm install MyLib-PluginB

While one solution could be to avoid using webpack for the plugins altogether, I prefer to keep this option as a last resort if all else fails.

Thank you!

Answer №1

It's not ideal to rely on webpack for building your plugins or libraries. Instead, it's better to let the user who is consuming the library choose their own bundler. The main focus for the library should be transpilation of any code that may need it, such as JavaScript with babel features or TypeScript, into something that can be easily required by node.

Furthermore, each plugin should list MyLib as a peerDependency rather than a regular dependency. This ensures that MyLib won't get duplicated within the plugin's node_modules directory, preventing unnecessary bundling of duplicates. While it's okay to have MyLib listed as a devDependency for unit testing purposes, it's crucial that it remains a peer dependency and not a regular dependency.

Answer №2

After delving deep into the webpack documentation, I stumbled upon a solution that utilizes webpack's externals feature.

According to webpack documentation:

The externals configuration option allows certain dependencies to be excluded from the output bundles.

To implement this solution, I simply inserted the following code snippet into the webpack configuration for the plugin:

module.exports = {
    ...,
    externals: {
        mylib: { 
            commonjs: 'MyLib',
            commonjs2: 'MyLib',
            amd: 'MyLib',
            root: 'MyLib'
        }
    }
};

For more information, refer to the webpack documentation at: https://webpack.js.org/configuration/externals/

I trust that this insight will be beneficial to others facing similar challenges.

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

Tips for including vue-autonumeric in your webpack 2 setup

Encountering a problem while bundling the vue-autonumeric package with Webpack 2, where the dependency AutoNumeric is not being found properly. Although there is an alias set up in the configuration that works fine with webpack 3, it seems to fail when wo ...

The behavior of Ajax is resembling that of a GET method, even though its intended method

Greetings, I am currently facing an issue while coding in Javascript and PHP without using jQuery for Ajax. My aim is to upload a file over Ajax and process it in PHP. Here is the code snippet: index.html <html> <head> <title>PHP AJAX ...

Tips on how to customize/ng-class within a directive containing a template using replace: true functionality

To keep replace: true, how can ng-class be implemented on the directive below without causing conflicts with the template's ng-class? This currently results in an Angular error: Error: Syntax Error: Token '{' is an unexpected token at co ...

Having trouble locating the module node_modules@ionicapp-scripts within IONIC 3

I have npm version 3.10.10 installed followed by the installation of Ionic 3.9.2 and Cordova 7.0.1. Here are the steps I have taken: ionic start newProject (chose a tabs project) https://i.sstatic.net/D9tFI.png https://i.sstatic.net/KP4OV.png https: ...

Guide for implementing async/await in conjunction with the eval() function within JavaScript

I'm currently using the eval function to evaluate strings and adding await to it to ensure all values are obtained, but unfortunately the await is not functioning correctly. Here is a snippet of my code: if (matchCard.card.status != "notstarted& ...

I am utilizing the useEffect hook along with Axios to fetch data from the backend. My goal is to retrieve two arrays of objects in order to render them on the

I am attempting to retrieve 2 arrays of objects from my MySQL database using Axios, but the console.log output '3' is showing an empty array. I'm not sure what's causing this issue. export default function Editar() { let {clienteId} = ...

Can a javascript file be included through a symbolic link?

I am working on a PHP web application and I have a question: Is it advisable to store my JavaScript files in the private directory? If yes, can I include them from a symbolic link located in the public directory? ...

Executing onClick event in RiotJS upon page load

As I develop a table application using RiotJS, I consistently encounter an issue with the onclick event. Whenever I attempt to utilize the <tag onclick={somefunction}> I face unpredictable behavior. Sometimes, it will excessively call the function ...

Ways to conceal all components except for specific ones within a container using JQuery

My HTML structure is as follows: <div class="fieldset-wrapper"> <div data-index="one">...</div> <div data-index="two">...</div> <div data-index="three">...</div> < ...

Ways to retrieve information from a URL using the .get() method in a secure HTTPS connection

As I work on handling user input from a form using node.js, express, and bodyParser, I encounter an issue. Even after using console.log(req.body), the output is {}. This is puzzling as there is data in the URL when the form is submitted successfully at htt ...

techniques for tracking instance variables in a Ruby controller and transferring them to an HTML view utilizing AJAX

Hello, I am looking to create a page that dynamically monitors or renders the value of a variable within the controller as it iterates through different values. view.html.erb <a id='get_value' class="btn">Run</a> <ul id="value_va ...

"Utilize Ember Data to extract data using a specific serializer

I'm working with an object called "Residence" that consists of various details. I am trying to use the serializer "extractSingle" to establish its relationships when receiving data from the server, but I keep encountering the error message "Unable to ...

After repeated attempts to initialize and destroy, Froala encounters issues when loading a textarea via Ajax

Whenever an EDIT button is clicked to update some Blog Data, it triggers an Ajax call that brings up a textarea for Froala and initiates the initialization process. This sequence works smoothly initially, but after a few cycles of edit/submit (1, 2, or 3 o ...

Methods for identifying when a Vue component has been updated based on property change

I have a requirement to show a spinner in every Vue component. My initial thought is to use v-if="loading" within the component's HTML. How do I know when a component has finished loading? In other words, how can I tell when the DOM has be ...

Troubleshooting the height problem in react-window when using react-select

There seems to be an issue with the height of the dropdown in react-select when used with react-window. Even though there are only two values, the height is larger than the items displayed. How can this be fixed, especially considering that the dropdown va ...

What is the most effective way to extract Geolocation API co-ordinates from my nested function and store them in React state?

My goal is to retrieve a user's location once they click a button using the Geolocation API. <button onClick={this.setNewLatLong()}>"Use my location"</button>; I have successfully obtained the latitude and longitude coordinates with the ...

What is the best way to view npm modules in a web browser?

After fetching an npm module via ajax, I attempt to evaluate the response using eval, but unfortunately I can't locate it afterwards. I have searched within window, this, and even module - all returning as undefined. How can I properly evaluate an npm ...

Check each field in a loop and if validation for any field fails, then return false using jQuery

Having trouble resetting the flag variables when it comes to form validations. I seem to be missing something crucial. I'm dealing with a form that has multiple text fields. I want to validate each field on blur and prevent form submission if any val ...

Tips for resolving the issue of infinite re-render with react-hook-form?

Struggling to build a basic form in React with react-hook-form library. Implemented various validations and features in the form. However, encountering the following console error. Error message on console: Warning: Maximum update depth exceeded. This can ...

Solving the puzzle of complex polymorphic object model deserialization in Java Jackson: Facing the JsonMappingException error – Unexpected token (START_OBJECT) instead

I am working with a hierarchy of objects described as follows: A B extends A C extends B D extends B E extends C F extends A and contains a reference to A The annotation for class A is defined as: @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS,include=Jso ...