Visual Studio Code Template: Webpack, Babel, Express Server and Client

I always find setting up the development environment for any new project fairly tedious, so I try to keep it as similar across all my projects as possible. To that end, I have created templates with all the common tools and settings I like so I can get right into work with as little friction as possible.

This is a Visual Studio Code project template for a client-server app running on Node / Express using a shared codebase. Webpack bundles the client-side code, using Babel to support the required browser versions. It supports using the integrated debugger for both the server and client side.


Download

You can download the template files here:


VS Code Extensions

There are two extensions for Visual Studio Code that I find useful during development.

  • Debugger for Chrome

    • Needed to launch the client in Chrome and use the native VS Code debugger.
  • Webpack Progress (Optional)

    • Displays the Webpack progress in the VS Code status bar.


Using the Template

Whenever I need to start a new project, I simply:

  1. Make a copy of the template directory.
  2. Fill in the project-specific information in package.json and webpack.config.js.
  3. Run npm install.
  4. Run npm outdated.
  5. Run npm update depending on which packages are outdated.

Finally, make sure everything is working as intended. The source files included have the most basic functionality to test that everything works.

Start Webpack by choosing Run Task > Webpack Watch. Make sure to say yes when VS Code asks if the Webpack Watch task is allowed to run when the project opens. If successful, Webpack will create a public/ directory with a bundle.web.js and index.html file.

From the Debug pane, choose "Launch Server and Client" then Start Debugging (F5). If everything is working, Chrome will open and display the simple index.html file in the client directory. Try setting some breakpoints in both index.js and app.js to ensure debugging works for both the client and server.


Template Files

Template Files

Let's take a look at the template files and see what they do.

  • launch.json

    • There are configurations for launching the server and client as well as a compound that launches them both. You can select which configuration to use in the Debug panel of VS Code.
  • tasks.json

    • This creates a task in VS Code to run Webpack every time the project is opened. This runs the 'webpack' script defined in the package.json file.

    • I can't tell you how many times I have forgotten to start webpack and wondered why my changes weren't showing up. Having it start automatically makes my job just that much easier.

  • package.json

    • The package.json is preconfigured will all the basic modules necessary to start the project. Of course, you have to manually fill in the project specific name, description, etc.
  • webpack.config.js

    • I like to have Webpack bundle all the assets for a project including images, html and css files. I store all the assets in the src/ directory. Webpack will create a public/ directory and place all the bundled assets into it. This way, if there is ever a problem, I can delete the public/ directory and produce a clean build extremely easily.

    • The HtmlWebpackPlugin creates the index.html file that loads the bundled code. Don't forget to set a proper title for this page in the plugin constructor.

    • The BitBarWebpackProgressPlugin allows the Webpack Progress VS Code Extension to function.

  • babel.config.js

    • You can easily configure Babel to create code that supports any browser version you are targeting. You will likely want to adjust these to your specific project needs.
  • .gitignore

    • I include a .gitignore file so that the node_modules or the Webpack-created public directories aren't accidentally added to the repository.


launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Server",
            "program": "${workspaceFolder}/src/server/app.js",
            "internalConsoleOptions": "openOnSessionStart"
        },
        {
            "name": "Launch Client",
            "type": "chrome",
            "request": "launch",
            "url": "http://localhost:3000/",
            "internalConsoleOptions": "openOnSessionStart",
            "webRoot": "${workspaceFolder}/"
        }
    ],
    "compounds": [
        {
            "name": "Launch Server and Client",
            "configurations": [
                "Launch Server",
                "Launch Client"
            ]
        }
    ]
}


tasks.json

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Webpack Watch",
            "type": "npm",
            "script": "webpack",
            "problemMatcher": [],
            "runOptions": {"runOn": "folderOpen"}
        }
    ]
}


package.json

{
  "name": "template",
  "version": "1.0.0",
  "description": "Template for Webpack, Babel, Express Server and Client",
  "license": "ISC",
  "author": "",
  "main": "src/server/app.js",
  "scripts": {
    "start": "node src/server/app.js",
    "webpack": "npx webpack"
  },
  "dependencies": {
    "@babel/polyfill": "^7.2.5",
    "@babel/runtime": "^7.3.1",
    "babel-core": "^6.26.3",
    "express": "^4.16.3"
  },
  "devDependencies": {
    "@babel/cli": "^7.0.0",
    "@babel/core": "^7.0.0",
    "@babel/plugin-transform-runtime": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "babel-loader": "^8.0.2",
    "bitbar-webpack-progress-plugin": "^1.0.0",
    "css-loader": "^2.1.0",
    "file-loader": "^3.0.1",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "node-sass": "^4.11.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}


webpack.config.js

const path = require('path');

const BitBarWebpackProgressPlugin = require('bitbar-webpack-progress-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const webConfig = {
    target: 'web',
    mode: 'development',
    devtool: 'inline-source-map',
    entry: ['@babel/polyfill', './src/client/index.js'],
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            },
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    'file-loader'
                ]
            },
            {
                test: /\.html$/,
                use: [
                    'html-loader'
                ]
            }
        ]
    },

    externals: [],

    output: {
        path: path.resolve(__dirname, 'public'),
        filename: 'bundle.web.js'
    },
    plugins: [new BitBarWebpackProgressPlugin(),
              new HtmlWebpackPlugin({ title: 'Template' })
             ],
    watch: true
};

module.exports = [webConfig];


babel.config.js

const presets = [
    ["@babel/preset-env", {
        targets: {
        edge: "17",
        firefox: "60",
        chrome: "67",
        safari: "9"
        },
        useBuiltIns: "usage"
    }]
];

module.exports = { presets };


.gitignore

node_modules
public


Source Code Structure

How you organize your source code is largely dependent on the project and personal preference. In this case, I separate unique files for the client and server into two directories and allow shared files in the src directory.

If you do change this, don't forget to adjust the webpack.config.js, package.json and launch.json files to point to your new entry point locations.


Conclusion

This is a fairly complicated setup since it handles both the client and server in one codebase. I find this works well for the smaller projects I typically work on, but if you are working on a larger project, you probably want to split your codebase into completely separate modules.

I highly recommend creating your own templates. They are especially useful for those types of projects that you don't do that often and can easily forget what you need to install and how it should be configured.

I hope this has been helpful. Let me know if you have any questions or comments.

Question or Comment?