Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack - How do you require an optional dependency in bundle (saslprep)

I am using webpack to bundle a number of back-end scripts into a single file during my deployment process.

When connecting to the MongoDB database there is an optional dependency, which throws a warning if it is not included.

Warning: no saslprep library specified. Passwords will not be sanitized

In my development environment this error is easily resolved by installing the optional dependency.

npm install saslprep --save

However when bundling with webpack the optional dependency is not included and the warning persists in the production deployment. I can trace the cause of this easily enough, the mongodb library is requiring this as an optional dependency:

let saslprep;
try {
  saslprep = require('saslprep');
} catch (e) {
  // don't do anything;
}

I have tried following the webpack documentation using shimming, externals, plugins and frankly am quite lost as to the correct approach to resolve this issue. Here is my current webpack.config file (attempting to require this as a plugin).

const path = require('path');
const webpack = require('webpack');

module.exports = {
    entry: './src/api/index.ts',
    target: 'node',
    mode: 'production',
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'ts-loader',
                exclude: /node_modules/
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.tsx', '.ts', '.json']
    },
    output: {
    filename: 'api.js',
        path: path.resolve(__dirname, 'dist'),
    },
    plugins: [
        new webpack.IgnorePlugin(/fsevents/),
        new webpack.IgnorePlugin(/blessed/),
        new webpack.ProvidePlugin({
            saslprep: path.resolve(__dirname, "node_modules/saslprep/index.js")
        })
    ],
};

Thanks in advance.

like image 633
Corky3892 Avatar asked Nov 04 '19 16:11

Corky3892


3 Answers

The module saslprep is included into the bundle but it will fail to load because it's trying to read the file code-points.mem that doesn't exist.

You have to copy this file from the saslprep package into the root of your project (the relative path must be ../code-points.mem).

It doesn't matter if you copy it by hand or with the copy-webpack-plugin plugin.

module.exports = {
    plugins: [
        new CopyPlugin({
            patterns: [
                {
                    from: require.resolve("saslprep/code-points.mem"),
                    to: "../code-points.mem"
                }
            ]
        })
    ],
}
like image 111
Vincent Hoch-Drei Avatar answered Dec 17 '22 12:12

Vincent Hoch-Drei


I you use the webpack-node-externals package, you can also do this:

const nodeExternals = require("webpack-node-externals")

...

const webpackConfig = {
  ...
  externals: [nodeExternals({
    allowlist: ['saslprep']
  })],
  ...
}
like image 44
Mirko Avatar answered Dec 17 '22 13:12

Mirko


Thanks to Brendan for steering me in the right direction. Ultimately the answer was found here: http://www.matthiassommer.it/software-architecture/webpack-node-modules/

The key piece of information being:

Webpack’s compiler converts the require() call to its own webpack_require(). At runtime it looks into its internal module registry.

Following the steps outlined therein the resolution becomes:

const path = require('path');
const webpack = require('webpack');

module.exports = {
    entry: './src/api/index.ts',
    target: 'node',
    mode: 'production',
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'ts-loader',
                exclude: /node_modules/
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.tsx', '.ts', '.json'],
    },
    output: {
        filename: 'api.js',
        path: path.resolve(__dirname, 'dist'),
    },
    plugins: [
        new webpack.IgnorePlugin(/fsevents/),
        new webpack.IgnorePlugin(/blessed/),
    ],
    externals: {
        "saslprep": "require('saslprep')"
    }
};

Please note that in my testing the quotes around "saslprep" do appear to berequired when importing externals.

like image 33
Corky3892 Avatar answered Dec 17 '22 13:12

Corky3892