Search code examples
node.jswebpackmysqljs

Webpacking a NodeJS Express API with MySQL throws connection error in mode '-p', not in '-d'


I have a simple Express API where I use MySQL to retrieve my data. I use Webpack 4 to bundle it with a very simple configuration:

'use strict';

const path = require('path');

module.exports = {
    entry: './src/main.js',
    target: 'node',
    output: {
        filename: 'gept_api.js',
        path: path.resolve(__dirname, 'dist'),
    },
    node: {
        __dirname: true,
    },
};

When I use webpack --config webpack.config.js -d for development everything works just fine.

However, when I run webpack --config webpack.config.js -p for production it suddenly doesn't work anymore, and throws an error when it's getting a connection from the pool.

TypeError: Cannot read property 'query' of undefined
at Object.getItem (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:154359)
at t.db_pool.getConnection (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:154841)
at c._callback (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:68269)
at c.end (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:8397)
at C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:322509
at Array.forEach (<anonymous>)
at C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:322487
at process._tickCallback (internal/process/next_tick.js:112:11)

So somehow this is broken by using the production mode in webpack 4. The connection object undefined somehow, while it isn't in development mode.

I have no idea how to fix this, since I'm a noob in using Webpack. I tried searching on google, but couldn't find anything relevant.


How I create my pool:

'use strict';

var mysql = require('mysql');
var secret = require('./db-secret');

module.exports = {
    name: 'gept_api',
    hostname: 'https://api.toxsickproductions.com/gept',
    version: '1.3.0',
    port: process.env.PORT || 1910,
    db_pool: mysql.createPool({
        host: secret.host,
        port: secret.port,
        user: secret.user,
        password: secret.password,
        database: secret.database,
        ca: secret.ca,
    }),
};

How I consume the connection:

pool.getConnection((err, connection) => {
    PlayerRepository.getPlayer(req.params.username, connection, (statusCode, player) => {
        connection.release();
        res.status(statusCode);
        res.send(player);
        return next();
    });
});  

and

/** Get the player, and logs to HiscoreSearch if exists.
 *
 * Has callback with statusCode and player. Status code can be 200, 404 or 500.
 * @param {string} username The player's username.
 * @param {connection} connection The mysql connection object.
 * @param {(statusCode: number, player: { username: string, playerType: string }) => void} callback Callback with statusCode and the player if found.
*/
function getPlayer(username, connection, callback) {
const query = 'SELECT p.*, pt.type FROM Player p JOIN PlayerType pt ON p.playerType = pt.id WHERE username = ?';

connection.query(query, [username.toLowerCase()], (outerError, results, fields) => {
        if (outerError) callback(500);
        else if (results && results.length > 0) {
            logHiscoreSearch(results[0].id, connection, innerError => {
                if (innerError) callback(500);
                else callback(200, {
                    username: results[0].username,
                    playerType: results[0].type,
                    deIroned: results[0].deIroned,
                    dead: results[0].dead,
                    lastChecked: results[0].lastChecked,
                });
            });
        } else callback(404);
    });
}

Solution

  • I found what was causing the issue. Apparantly the mysql package relies on Function.prototype.name because setting keep_fnames: true fixed the production build. (https://github.com/mishoo/UglifyJS2/tree/harmony#mangle-options)

    I disabled the Webpack 4 standard minification and used custom UglifyJSPlugin settings:

    'use strict';
    
    const path = require('path');
    const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
    
    module.exports = {
        entry: './src/main.js',
        target: 'node',
        output: {
            filename: 'gept_api.js',
            path: path.resolve(__dirname, 'dist'),
        },
        node: {
            __dirname: true,
        },
        optimization: {
            minimize: false,
        },
        plugins: [
            new UglifyJsPlugin({
                parallel: true,
                uglifyOptions: {
                    ecma: 6,
                    mangle: {
                        keep_fnames: true,
                    },
                },
            }),
        ],
    };