How can I use webpack with express?

87,742

Solution 1

What I ended up doing was I used 2 different configurations, 1 for packing the server stuff together using webpack, and 1 for packing all the browser stuff together and also run webpack dev server for hot reloading.

Server webpack config aka webpack.node.config.js now looks like this:

var webpack = require('webpack');
var path = require('path');
var fs = require('fs');
var nodeModules = {};

// note the path.resolve(__dirname, ...) part
// without it, eslint-import-resolver-webpack fails
// since eslint might be invoked with different cwd
fs.readdirSync(path.resolve(__dirname, 'node_modules'))
    .filter(x => ['.bin'].indexOf(x) === -1)
    .forEach(mod => { nodeModules[mod] = `commonjs ${mod}`; });

// es5 style alternative
// fs.readdirSync(path.resolve(__dirname, 'node_modules'))
//     .filter(function(x) {
//         return ['.bin'].indexOf(x) === -1;
//     })
//     .forEach(function(mod) {
//         nodeModules[mod] = 'commonjs ' + mod;    
//     });

module.exports =

{
    // The configuration for the server-side rendering
    name: 'server',
    target: 'node',
    entry: './app/server/serverEntryPrototype.js',
    output: {
        path: './bin/',
        publicPath: 'bin/',
        filename: 'serverEntryPoint.js'
    },
    externals: nodeModules,
    module: {
        loaders: [
            { test: /\.js$/,

                loaders: [
                    // 'imports?document=this',

                    // 'react-hot',
                    'babel-loader'
                    //,'jsx-loader'
                ]
            },
            { test:  /\.json$/, loader: 'json-loader' },
        ]
    },
    plugins: [
    // new webpack.NormalModuleReplacementPlugin("^(react-bootstrap-modal)$", "^(react)$")
    // new webpack.IgnorePlugin(new RegExp("^(react-bootstrap-modal)$"))
    // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ]
};

Browser webpack config aka webpack.browser.config.js now looks like this:

var webpack = require('webpack');
var path = require('path');
var buildPath = path.resolve(__dirname, 'assets');
var fs = require('fs');


var commonLoaders = [
    { test: /\.js$/,

        loaders: [
            'react-hot',
            'babel-loader'
            //,'jsx-loader'
        ]
    }
];


module.exports =
{
    // Makes sure errors in console map to the correct file
    // and line number
    name: 'browser',
    devtool: 'eval',
    entry: [
        //'./bin/www.js',
        './app/index.js',
        'webpack/hot/dev-server',
        'webpack-dev-server/client?http://localhost:8081'  // WebpackDevServer host and port
    ],
    output: {
        path: buildPath,
        filename: '[name].js',
        // Everything related to Webpack should go through a build path,
        // localhost:3000/build. That makes proxying easier to handle
        publicPath: 'http://localhost:8081/assets/'
    },

    extensions: [
        '',
        '.jsx', '.js',
        '.json',
        '.html',
        '.css', '.styl', '.scss', '.sass'
    ],

    module: {

        loaders: [
            // Compile es6 to js.
            {
                test: /app\/.*\.jsx?$/,
                loaders: [
                    'react-hot',
                    'babel-loader'
                ]
            },

            ///app\/.*\.json$/
            { test:  /\.json$/, loader: 'json-loader' },

            // Styles
            { test: /\.css$/, loader: 'style-loader!css-loader' },
            { test: /\.s(a|c)ss$/, loader: 'style!css?localIdentName=[path][name]---[local]---[hash:base64:5]!postcss!sass' },

            // Fonts
            { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&minetype=application/font-woff' },
            { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader' }

            //{ test: /\.png$/, loader: 'url-loader?limit=100000' },
            //{ test: /\.jpg$/, loader: 'file-loader' }
        ],

        plugins: [
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NoErrorsPlugin()
        ]
    },

    postcss: [
        require('autoprefixer-core')
    ],

    devtool: 'source-map'
}
;

Solution 2

It can be realized by specifying "node" to "target" option, since v1.10.2.

For reference: http://jlongster.com/Backend-Apps-with-Webpack--Part-I

If you want to bundle the server and the client's code at the same time, it is possible to use multiple configuration in the following manner.

// webpack.config.js

module.exports = [
    {
        name: 'server',
        entry: './src/server/index.js',
        target: 'node',
        output: {
            path: __dirname + '/dist/server',
            filename: 'bundle.js',
        },
    },
    {
        name: 'client',
        entry: './src/client/index.js',
        // target: 'web', // by default
        output: {
            path: __dirname + '/dist/client',
            filename: 'bundle.js',
        },
    }
];

Solution 3

I am just clarifying @meta2's answer because I believe it can be written in a more understandable way - although full points to him!

tl;dr - set target: 'node' in your webpack.config.js to fix the errors that get generated when using Webpack with Express.

You still get warnings like:

WARNING in ./node_modules/express/lib/view.js 
81:13-25 Critical dependency: the request of a dependency is an expression

To fix those, use https://github.com/liady/webpack-node-externals. FYI - this reduces you bundle size significantly (check size before and after) and speeds up the bundling time incredibly.

Full example:

const path = require('path')
const nodeExternals = require('webpack-node-externals')

module.exports = {
  entry: './src/app.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  target: 'node',   // THIS IS THE IMPORTANT PART
  externals: [nodeExternals()],
  mode: 'development'
}

Solution 4

Additionally, if you are working with Typescript, make sure to also include the ".js" extension in your config:

module.exports = {
   entry: './src/server/index.ts',
   target: 'node',
   output: {
      path: __dirname + '/dist/server',
      filename: 'bundle.js',
   },        
   resolve: {
      modules: [
         "node_modules"
      ],
      extensions: [".ts", ".js"]
   }
};

Solution 5

I took an easy approach that could be useful in a small or medium project. I make it so webpack would serve as the bundler for ecma script and scss, though in this aproach i dont use hot reloading.

The server configuration is the default given by express generator.

webpack.config.js

const path = require("path");

module.exports = {
  entry: "./resources/index.js",
  output: {
    path: path.join(__dirname, "/public/dist"),
    publicPath: "/public/dist",
    filename: "main.js"
  },
  mode: "development",
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.scss$/,
        use: ["style-loader", "css-loader", "sass-loader"]
      }
    ]
  }
};

package.json is devDependencies

"devDependencies": {
    "@babel/core": "^7.6.4",
    "@babel/preset-env": "^7.6.3",
    "babel-loader": "^8.0.6",
    "css-loader": "^3.2.0",
    "mini-css-extract-plugin": "^0.8.0",
    "node-sass": "^4.13.0",
    "sass-loader": "^8.0.0",
    "style-loader": "^1.0.0",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.9"
  }

package.json is scripts

"scripts": {
    "start": "node ./bin/www",
    "dev": "nodemon",
    "build": "webpack",
    "watch": "webpack --watch"
  },
Share:
87,742
SudoPlz
Author by

SudoPlz

Lets make the world, a better place..!

Updated on November 13, 2021

Comments

  • SudoPlz
    SudoPlz over 2 years

    When I try to use webpack with a simple express server I always get TONS of errors: express.js

    'use strict';
    var express = require('express');
    var path = require('path');
    var url = require('url');
    
    
    // -------- my proxy----------------------
    var app = express();
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    app.set('port', process.env.PORT || 8080);
    app.use(function logErrors(err, req, res, next) {
            console.error(err.stack);
            next(err);
        }
    );
    
    app.listen(app.get('port'), function() {
        console.info('Express server started at http://localhost:' + app.get('port'));
    });
    

    I get all those errors:

    Version: webpack 1.10.0
    Time: 1200ms
      Asset    Size  Chunks             Chunk Names
    outfile  559 kB       0  [emitted]  main
    chunk    {0} outfile (main) 498 kB [rendered]
        [0] ../app/server/express2.js 553 bytes {0} [built]
         + 125 hidden modules
    
    WARNING in ../~/express/lib/view.js
    Critical dependencies:
    78:29-56 the request of a dependency is an expression
     @ ../~/express/lib/view.js 78:29-56
    
    ERROR in ../~/express/lib/request.js
    Module not found: Error: Cannot resolve module 'net' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/lib
     @ ../~/express/lib/request.js 18:11-25
    
    ERROR in ../~/express/lib/view.js
    Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/lib
     @ ../~/express/lib/view.js 18:9-22
    
    ERROR in ../~/express/~/send/index.js
    Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send
     @ ../~/express/~/send/index.js 25:9-22
    
    ERROR in ../~/express/~/etag/index.js
    Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/etag
     @ ../~/express/~/etag/index.js 22:12-25
    
    ERROR in ../~/express/~/send/~/destroy/index.js
    Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send/node_modules/destroy
     @ ../~/express/~/send/~/destroy/index.js 1:17-30
    
    ERROR in ../~/express/~/send/~/mime/mime.js
    Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send/node_modules/mime
     @ ../~/express/~/send/~/mime/mime.js 2:9-22
    
    ERROR in ../~/express/~/send/~/statuses/codes.json
    Module parse failed: /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send/node_modules/statuses/codes.json Line 2: Unexpected token :
    You may need an appropriate loader to handle this file type.
    | {
    |   "100": "Continue",
    |   "101": "Switching Protocols",
    |   "102": "Processing",
     @ ../~/express/~/send/~/statuses/index.js 2:12-35
    
    ERROR in ../~/express/~/send/~/mime/types.json
    Module parse failed: /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send/node_modules/mime/types.json Line 1: Unexpected token :
    You may need an appropriate loader to handle this file type.
    
    |
     @ ../~/express/~/send/~/mime/mime.js 87:12-35
    
    ERROR in ../~/express/~/accepts/~/mime-types/~/mime-db/db.json
    Module parse failed: /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/accepts/node_modules/mime-types/node_modules/mime-db/db.json Line 2: Unexpected token :
    You may need an appropriate loader to handle this file type.
    | {
    |   "application/1d-interleaved-parityfec": {
    |     "source": "iana"
    |   },
     @ ../~/express/~/accepts/~/mime-types/~/mime-db/index.js 11:17-37
    
    ERROR in ../~/express/~/type-is/~/mime-types/~/mime-db/db.json
    Module parse failed: /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/type-is/node_modules/mime-types/node_modules/mime-db/db.json Line 2: Unexpected token :
    You may need an appropriate loader to handle this file type.
    | {
    |   "application/1d-interleaved-parityfec": {
    |     "source": "iana"
    |   },
     @ ../~/express/~/type-is/~/mime-types/~/mime-db/index.js 11:17-37
    

    and this is my config file:

    var webpack = require('webpack');
    
    
    module.exports = {
        // Makes sure errors in console map to the correct file
        // and line number
        devtool: 'eval',
        entry: [
            './bin/www.js'
        ],
        output: {
            path: './bin/out',
            filename: 'server.js'
        },
    
        extensions: [
            '',
            '.jsx', '.js'
        ],
    
        module: {
    
            loaders: [
                // Compile es6 to js.
                {
                    test: /app\/.*\.js?$/,
                    loaders: [
                        'react-hot',
                        'babel-loader'
                    ]
                }
            ]
        },
    
        devtool: 'source-map'
    };
    

    What can I do, I need to use webpack on my server side as well.

    I run the express.js file like so: ./node_modules/webpack/bin/webpack.js ../app/server/express.js outfile --display-chunks -c --progress -d

  • jdahlgren
    jdahlgren almost 9 years
    Do you have a source for using multiple configurations in a single file? I couldn't find it in Webpack docs and it's not working for me.
  • Admin
    Admin over 8 years
    Although I couldn't find docs, an example exists in the repository: github.com/webpack/webpack/tree/master/examples/multi-compil‌​er
  • Ateev Chopra
    Ateev Chopra over 8 years
    Can you please share where you add webpack into node file ? That would be helpful.
  • SudoPlz
    SudoPlz over 8 years
    Not sure if I understood your question correctly, but if I did, you don't add webpack into your main node file. Webpack converts your node file, but you don't have to put webpack code IN it. You just convert the file using webpack command line before running your main file with node. In my case I ran the whole thing by typing npm start debugMode. deugMode was a script I created to do everything for me, here is a part of my package.json code: tinyurl.com/tldrsudo
  • Eldelshell
    Eldelshell over 8 years
    Man this is the sort of magic I love. That little nodeModules thing made my day.
  • Marco Lazzeri
    Marco Lazzeri over 8 years
    Still failing for me when trying to load the express/lib/view.js dependency (the request of a dependency is an expression @ ../~/express/lib/view.js 78:29-56)
  • tet
    tet about 8 years
    HI, I'm trying to figure out your webpack set-up. Could you tell me the file name of your server webpack config? I would like to know how you built your ./app/server/serverEntryPrototype.js into ./bin/serverEntryPrototype.js.
  • SudoPlz
    SudoPlz about 8 years
    I updated my answer to include the filenames of each file, I hope that helps.
  • tet
    tet about 8 years
    @SudoPlz thank you so much for adding the filenames, now I'm having webpack and express working together. You rock, sir!!
  • Joseph Rex
    Joseph Rex about 8 years
    So when you change an asset (scss, css, js) you have to stop your express server to separately run webpack for browser assets? or how do you go about it?
  • alfonsodev
    alfonsodev over 7 years
    bare in mind with private orgs, the packages are installed under node_modules/@organisation/packageName so you must add them "manually" right after readdirSync. With `nodeModules['@myorg/mypackage'] = 'commonjs mypackage'
  • Alexander
    Alexander over 7 years
    everything is working for me but when I introduced require express, webpack now gives me a ton of error.. this solves it.. now upvoted
  • Abdulhakim
    Abdulhakim over 2 years
    After you finish the code, on the command line, just type: "npm run dev"