93

I was just wondering, I started using Webpack for a new project and so far it's working fine. I almost would say I like it better than Grunt, which I used before. But now I'm quite confused how and or I should use it with my Express back-end?

See, I'm creating one app with a front-end (ReactJS) and a back-end (ExpressJS). The app will be published on Heroku. Now it seems like I should use Webpack with ExpressJS as well to get the app up and running with one single command (front-end and back-end).

But the guy who wrote this blogpost http://jlongster.com/Backend-Apps-with-Webpack--Part-I seems to use Webpack for bundling all back-end js files together, which is in my opinion really not necessary. Why should I bundle my back-end files? I think I just want to run the back-end, watch my back-end files for changes and use the rest of Webpack's power just for the front-end.

How do you guys bundle the front-end but at the same time run the back-end nodejs part? Or is there any good reason to bundle back-end files with Webpack?

Erik van de Ven
  • 4,747
  • 6
  • 38
  • 80

3 Answers3

75

Why to use webpack on node backend

If we are talking about react and node app you can build isomorphic react app. And if you are using import ES6 Modules in react app on client side it's ok - they are bundled by webpack on the client side.

But the problem is on server when you are using the same react modules since node doesn't support ES6 Modules. You can use require('babel/register'); in node server side but it transipile code in runtime - it's not effective. The most common way to solve this problem is pack backend by webpack (you don't need all code to be transpile by webpack - only problematic, like react stuff in this example).

The same goes with JSX.

Bundling frontend and backend at the same time

Your webpack config can have to configs in array: one for frontend and second for backend:

webpack.config.js

const common = {
    module: {
        loaders: [ /* common loaders */ ]
    },
    plugins: [ /* common plugins */ ],
    resolve: {
        extensions: ['', '.js', '.jsx'] // common extensions
    }
    // other plugins, postcss config etc. common for frontend and backend
};

const frontend = {
     entry: [
         'frontend.js'
     ],
     output: {
        filename: 'frontend-output.js'
     }
     // other loaders, plugins etc. specific for frontend
};

const backend = {
     entry: [
         'backend.js'
     ],
     output: {
        filename: 'backend-output.js'
     },
     target: 'node',
     externals: // specify for example node_modules to be not bundled
     // other loaders, plugins etc. specific for backend
};

module.exports = [
    Object.assign({} , common, frontend),
    Object.assign({} , common, backend)
];

If you start this config with webpack --watch it will in parallel build your two files. When you edit frontend specific code only frontend-output.js will be generated, the same is for backend-output.js. The best part is when you edit isomorphic react part - webpack will build both files at once.

You can find in this tutorial explanation when to use webpack for node (in chapter 4).

Everettss
  • 15,475
  • 9
  • 72
  • 98
  • Well I'm trying to build an isomophic app ;) The thing is that before I used webpack, I used Grunt, which was quite easy to use a combination of `browserify`, `grunt-nodemon` and `grunt-contrib-watch` to run the front-end and back-end code with a single command. And at the same time, having a watcher on front- AND back-end code. I'm experiencing this is harder using webpack, while having a single application folder (with subfolders) with express and react files. I need webpack to only watch the back-end code, and watch and bundle the front-end. I'm experiencing this isn't that easy. – Erik van de Ven Jun 20 '16 at 11:13
  • Also because If I'm looking for different articles online, I came across some blogs like http://jlongster.com/Backend-Apps-with-Webpack--Part-I, who bundles the back-end code as well, which is not what I want :) – Erik van de Ven Jun 20 '16 at 11:15
  • @ErikvandeVen you ask for a webpack solution. Every one of us has got the most comfortable build tools stack. I found that only webpack is great for isomorphic react apps. – Everettss Jun 20 '16 at 12:07
  • `// specify for example node_modules to be not bundled` Does this mean this should be an array of every module in `node_modules` that isn't a dependency of backend code..or a dependency of one of their dependencies, etc etc.. That can't be right.. Can you explain further? Thanks – 1252748 Aug 18 '17 at 17:47
  • 2
    @1252748 in `externals` you should specify modules which are specific for node environment like for example `fs` (webpack will fail to compile this modules). You can read about this here https://webpack.js.org/configuration/externals/ For most of the time this plugin https://www.npmjs.com/package/webpack-node-externals will cover all problematic node modules. Use it like this: `externals: [require('webpack-node-externals')()]`. – Everettss Aug 19 '17 at 17:57
  • I see. I have tried using the node-externals plugin, but am presently experiencing [this problem](https://stackoverflow.com/questions/45763620/how-to-whitelist-all-subdependencies-with-webpack-node-externals). Do you mind taking a look? – 1252748 Aug 19 '17 at 18:05
  • Hi @Everettss, thanks for this clear explanation. I'm new to webpack and I don't understand how an output js file can be useful when working with express (back). For the front, we will use it in a script tag of the html. But what do we do with the backend-output.js ?? Thank you! – unadivadantan Nov 22 '17 at 11:09
  • @unadivadantan before webpack config you run `node backend.js`. After webpack config for backed you run `node backend-output.js` - that's all differences! – Everettss Nov 30 '17 at 13:18
10
This is my second update to this answer, which is beyond outdated by now.

If you need full a stack web framework in 2023, I'd recommend nextjs (which is built on top of react). No need to go around setting up anything, it just works out of the box, and is full stack.

On the other hand, if you need to compile your nodejs project written in typescript (which you should use as much as you can for js projects), I would use tsup-node.

You don't need to be a genius to imagine that in 3-5 years I'll come back to this and say this is really outdated, welcome to javascript.


This answer is outdated by now since node now has better support for ES modules

There's only a couple of aspects I can redeem the need to use webpack for backend code.

ES modules (import)

import has only experimental support in node (at least since node 8 up to 15). But you don't need to use webpack for them work in node. Just use esm which is very lightweight and has no build step.

Linting

Just use eslint, no need to use webpack.

Hot reloading/restart

You can use nodemon for this. It's not hot reloading but I think it's way easier to deal with. I wished I could refer to a more lightweight project than nodemon, but it does do the trick.


The blog post you shared (which is dated by now) uses webpack for having hot reloading. I think that's an overkill, opens a can of worms because now you have to deal with webpack config issues and hot reloading can also lead to unexpected behaviour.

The benefits we get from using tools like webpack on the frontend don't really translate to backend.

The other reasons why we bundle files in frontend is so browsers can download them in an optimal way, in optimal chunks, with cache busting, minified. There's no need for any of these in the backend.

Old (and terrible, but maybe useful) answer

You can use webpack-node-externals, from the readme:

npm install webpack-node-externals --save-dev

In your webpack.config.js:

var nodeExternals = require('webpack-node-externals');

module.exports = {
    ...
    target: 'node', // in order to ignore built-in modules like path, fs, etc.
    externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
    ...
};
Guido Tarsia
  • 1,962
  • 4
  • 27
  • 45
9

to use Webpack for bundling all back-end js files together, which is in my opinion really not necessary.

I think you are absolutely right. It's not necessary at all. I've been researching on this topic for a while. I've asked lots of questions on this topic, and up to this day, I haven't found yet a single "real" reason for one to use webpack on a Node.js back-end.

I'm not saying you can't or shouldn't set up a webpack-dev-server to develop your back-end code locally. But you definitely don't need to bundle your backend code on your build process.

webpack bundles are meant for the browser. Take a look at its official docs: Why webpack?. Historically, browsers never had a built-in module system, that's the reason why you need webpack. It basically implements a module system on the browser. On the other hand, Node.js has a built-it module system out of the box.

And I do re-use all of my front-end code for SSR on my server. The very same front-end files are run on my server as-is without any bundling (they are just transpiled, but the folder structured and number of files is the same). Of course I bundle it to run on the browser, but that's all.

To run on your Node.js server, simply transpile it with babel, without webpack.

Just use ["@babel/preset-env", { targets: { node: "12" }}], on your babel config. Choose the Node version of your backend environment.

backend
  dist_app     // BABEL TRANSPILED CODE FROM frontend/src
  dist_service // BABEL TRANSPILED CODE FROM backend/src
  src
    index.tsx
frontend
  src
    App.tsx
  public   // WEBPACK BUNDLED CODE FROM frontend/src

You can perfectly render your frontend code on the server, by doing:

backend/src/index.tsx

import { renderToString } from "react-dom/server";
import App from "../dist_app/App";

const html = renderToString(<App/>);

This would be considered isomorphic, I guess.

If you use path aliases on your code, you should use babel-plugin-module-resolver.

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336