Creating node library in Webpack 4

I'm trying to create node library using webpack and babel so that I can use ES2017. Everything works properly but the problem is a size of the output file which is huge comparing to the original file size. My test library is really simple and as the only dependency has mongodb package. Here is entire code of the library:

import crypto from "crypto";
import { MongoClient } from "mongodb";

let client = null;
let db = null;

/**
 * Connects to database using info defined in environment variables (MONGO_URL,
 * MONGO_DATABASE, MONGO_SSL, MONGO_SSL_VALIDATE).
 *
 * @async
 * @function connect
 */
const connect = async () => {
  if (!client) {
    // Connect to MongoDB server.
    client = await MongoClient.connect(process.env.MONGO_URL, {
      ssl: process.env.MONGO_SSL || false,
      sslValidate: process.env.MONGO_SSL_VALIDATE || false
    });
    // Get database.
    db = client.db(process.env.MONGO_DATABASE);
  }
};

/**
 * Disconnects from database.
 *
 * @async
 * @function disconnect
 */
const disconnect = async () => {
  if (client) {
    await client.close();
    client = null;
    db = null;
  }
};

/**
 * Disconnects from database.
 *
 * @function getDatabase
 * @return {Db} MongoDB instance of the Db class.
 */
const getDatabase = () => {
  if (!client) {
    throw new Error("Not connected to database");
  }
  return db;
};

/**
 * Gets collection.
 *
 * @function getCollection
 * @return {Collection<TSchema>} MongoDB instance of the Collection class.
 */
const getCollection = collectionName => {
  if (!client) {
    throw new Error("Not connected to database");
  }
  // Get collection.
  return db.collection(collectionName);
};

/**
 * Generates Mongo ID string compatible with Meteor Mongo IDs.
 *
 * @function generateId
 * @param {number} charsCount - Length of the Mongo ID string.
 * @return {string} Mongo ID string compatible with Meteor Mongo ID.
 */
const generateId = (charsCount = 17) => {
  const CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz";
  const digits = [];
  for (let i = 0; i < charsCount; i++) {
    let bytes;
    try {
      bytes = crypto.randomBytes(4);
    } catch (e) {
      bytes = crypto.pseudoRandomBytes(4);
    }
    const hexString = bytes.toString("hex").substring(0, 8);
    const fraction = parseInt(hexString, 16) * 2.3283064365386963e-10;
    const index = Math.floor(fraction * CHARS.length);
    digits[i] = CHARS.substr(index, 1);
  }
  return digits.join("");
};

export { connect, disconnect, getDatabase, getCollection, generateId };

And here is my webpack.config.js:

const path = require("path");
const paths = require("../lib/paths");

const externals = Object.keys(
  require(path.resolve(paths.pkg, "package.json")).dependencies || {}
);

module.exports = {
  mode: "production",
  entry: path.resolve(paths.src, "index.js"),
  output: {
    libraryTarget: "commonjs",
    path: paths.dist,
    filename: "index.js"
  },
  node: {
    __filename: true,
    __dirname: true
  },
  devtool: "source-map",
  target: "node",
  externals: externals,
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: paths.loaders.babel,
          options: {
            plugins: [
              paths.plugins.proposalClassProperties,
              paths.plugins.proposalObjectRestSpread,
              paths.plugins.transformRuntime
            ],
            presets: [[paths.presets.env, { targets: { node: "6.10" } }]]
          }
        },
        exclude: /node_modules/
      }
    ]
  }
};

The output file is 19 KB in size... It contains a lot of I guess polyfills which are not necessary. Why the hell webpack is including them in the output file even when I told it that I'm creating library.

In the .map file I can see that there are things like: "webpack:///./node_modules/core-js/library/modules/_has.js" or "webpack:///./node_modules/@babel/runtime/core-js/promise.js"

2 answers

  • answered 2018-03-13 20:21 Jeffrey Westerkamp

    You probably do not want to use webpack if your library is consumed in a Node environment. Simply running all files through babel is probably sufficient.

    Webpack is intended to transform a dependency tree in any module syntax into a single bundle for use in a web browser.

    In your case the only objective is to transpile one language level to another, which is exactly what babel does. The babel docs provide enough information on how to use the babel-cli to transpile your code.

  • answered 2018-03-13 20:21 Jagi

    I've found a problem. The big file size is caused by babel-plugin-transpile-runtime. Actually, instead of requiring features from the plugin it just puts all the code inside the file. I don't know why it's doing it. So as I know what's causing it, I still don't know how to fix it.