#StackBounty: #javascript #webpack #babeljs #es6-modules How to export multiple ES6 modules from one NPM package

Bounty: 50

I’ve built a relatively small NPM package consisting of roughly 5 different ES6 classes contained in one file each, they all look pretty much like this:

export default class MyClass {
    // ...
}

I’ve then setup an entry point for my package that looks like this:

export { default as MyClass } from './my-class.js';
export { default as MyOtherClass } from './my-other-class.js';

I’ve then run the entry point through webpack and babel ending up with a transpiled and minified index.js

Installing and importing the package works fine, but when I do the following from my client code:

import { MyClass } from 'my-package';

It doesn’t just import “MyClass” it imports the entire file including all dependencies of every class (some of my classes have huge dependencies).

I figured this is how webpack works when you try to import parts of an already bundled package? So I set up my local webpack config to run node_modules/my-package through babel too and then tried:

import { MyClass } from 'my-package/src/index.js';

But even this imports every single class exported by index.js. The only thing that seems to work the way I want is if I do:

import MyClass from 'my-package/src/my-class.js';

But I’d much rather:

  1. Be able to import the transpiled and minified file so that I don’t have to tell webpack to run babel inside node_modules and
  2. Be able to import each individual class directly from my entry point instead of having to enter the path to each file

What’s the best practice here? How do others achieve similar setups? I’ve noticed GlideJS has an ESM version of its package which allows you to import only the things you need without having to run babel through it for example.

The package in question: https://github.com/powerbuoy/sleek-ui

webpack.config.js

const path = require('path');

module.exports = {
    entry: {
        'sleek-ui': './src/js/sleek-ui.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist'),
        library: 'sleek-ui', // NOTE: Before adding this and libraryTarget I got errors saying "MyClass() is not a constructor" for some reason...
        libraryTarget: 'umd'
    },
    module: {
        rules: [
            {
                test: /.js$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env']
                        }
                    }
                ]
            }
        ]
    }
};

package.json

  "name": "sleek-ui",
  "version": "1.0.0",
  "description": "Lightweight SASS and JS library for common UI elements",
  "main": "dist/sleek-ui.js",
  "sideEffects": false, // NOTE: Added this from Abhishek's article but it changed nothing for me :/
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "build": "webpack --mode production"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/powerbuoy/sleek-ui.git"
  },
  "author": "Andreas Lagerkvist",
  "license": "GPL-2.0-or-later",
  "bugs": {
    "url": "https://github.com/powerbuoy/sleek-ui/issues"
  },
  "homepage": "https://github.com/powerbuoy/sleek-ui#readme",
  "devDependencies": {
    "@babel/core": "^7.8.6",
    "@babel/preset-env": "^7.8.6",
    "babel-loader": "^8.0.6",
    "webpack": "^4.42.0",
    "webpack-cli": "^3.3.11"
  },
  "dependencies": {
    "@glidejs/glide": "^3.4.1",
    "normalize.css": "^8.0.1"
  }
}


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.