DEV Community

Cover image for A simple webpack setup with Bootstrap and VueJS
David Johnson
David Johnson Subscriber

Posted on

A simple webpack setup with Bootstrap and VueJS

I'm sure there a hundreds of variants of these out there in the wild, but I thought I'd throw my aging hat into the ring. Or keys into the hat. What's the saying?

This is something I've boiled down to be as light as I could possibly make it, and as straightforward to work with as I could get. Although critique is always welcome. Constructive critique. Don't just wade in here, call me a muppet, and then ride off into the sunset.

I've put a link to the Github repository at the end, so you can skip past everything if you just want the raw goods.

Node version management

First thing to talk about - Node.js. I expect many of you out there working on front-end development need to switch node versions between different projects. It's a given. Of course, we need a way to manage that, and I used to use NVM.

However, the past few months I've been trying out something called FNM, or Fast Node Manager, and I really like it. It's built in Rust, and if you want to give it a go, there's a very descriptive Github repo here https://github.com/Schniz/fnm that explains how to configure it.

What's in the box?

Firstly, the packaging

This is my package.json. I'm running it in Node.js 22.14.0, and there is a .node-version file in the project that should automatically install the correct node variant if you're running FNM with --use-on-cd. (I won't explain that here, it's in the repo referenced above).

{
    "name": "frontend-build",
    "version": "1.0.0",
    "description": "Webpack build for the Bootstrap and VueJS",
    "author": "davidisnotnull",
    "license": "MIT",
    "keywords": [
      "webpack",
      "boilerplate",
      "template",
      "setup"
    ],
    "dependencies": {
      "@fortawesome/fontawesome-free": "^6.2.1",
      "@fortawesome/fontawesome-svg-core": "^6.2.1",
      "@fortawesome/free-solid-svg-icons": "^6.2.1",
      "@fortawesome/vue-fontawesome": "^3.0.2",
      "@popperjs/core": "^2.11.6",
      "axios": "^1.1.3",
      "bootstrap": "^5.2.2",
      "jquery": "^3.6.1",
      "jquery-validation": "^1.19.5",
      "jquery-validation-unobtrusive": "^4.0.0",
      "mitt": "^3.0.0",
      "vue": "^3.2.41",
      "vue-axios": "^3.5.2"
    },
    "devDependencies": {
      "@babel/core": "^7.21.0",
      "@babel/preset-env": "^7.19.4",
      "assets-webpack-plugin": "^7.1.1",
      "autoprefixer": "^10.4.12",
      "babel-loader": "^8.2.5",
      "clean-webpack-plugin": "^4.0.0",
      "css-loader": "^6.7.1",
      "file-loader": "^6.2.0",
      "mini-css-extract-plugin": "^2.7.5",
      "postcss-loader": "^7.0.1",
      "sass": "^1.55.0",
      "sass-loader": "^13.1.0",
      "style-loader": "^3.3.1",
      "url-loader": "^4.1.1",
      "vue-loader": "^17.0.0",
      "webpack": "^5.78.0",
      "webpack-bundle-analyzer": "^4.6.1",
      "webpack-cli": "^4.10.0",
      "webpack-merge": "^5.8.0"
    },
    "engines": {
      "node": ">=22"
    },
    "scripts": {
      "build": "webpack --config ./configuration/webpack.dev.config.js --mode=development",
      "watch": "webpack --config ./configuration/webpack.dev.config.js --mode=development --watch",
      "bundle": "npm install && npm run watch",
      "production": "webpack --config ./configuration/webpack.production.config.js --mode=production",
      "stats": "webpack --config ./configuration/webpack.production.config.js --mode=production --json > dist/stats.json && webpack-bundle-analyzer dist/stats.json"
    }
  }
Enter fullscreen mode Exit fullscreen mode

There's a dev and production version of the build. That's kind of self-explanatory, but use dev when you're dev'ing so you can debug things easier.

Enter webpack

I've used webpack-merge so that I can create config variants for development and production. You'll see these in the configuration folder in the repo.

The main bare-bones webpack config looks like this:

const path = require('path');
const environment = require('./configuration/environment');
const webpack = require('webpack')
const AssetsPlugin = require('assets-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    entry: [
        path.resolve(__dirname, 'js/app.js'),
        path.resolve(__dirname, 'scss/app.scss')
    ],    
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: [
                    'babel-loader'
                ]
            },
            {
                test: /\.css$/,
                use: [
                  {
                    loader: 'style-loader',
                  },
                  {
                    loader: 'css-loader',
                  },
                ],
              },
            {
                test: /\.(scss)$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: "css-loader",
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: function () {
                                    return [
                                        require('autoprefixer')
                                    ];
                                }
                            }
                        }
                    },
                    {
                        loader: 'sass-loader'
                    },
                ]
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
                use: [
                  {
                    loader: 'file-loader',
                    options: {
                      name: '[name].[ext]',
                      outputPath: 'fonts/'
                    }
                  }
                ]
              }
        ]
    },
    output: {
        filename: 'js/[name].[contenthash].js',
        path: environment.paths.output,
        publicPath: '/dist/'
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
        }),
        new CleanWebpackPlugin({
            verbose: true,
            cleanOnceBeforeBuildPatterns: ['**/*', '!stats.json'],
        }),
        new MiniCssExtractPlugin({
            filename: "css/[name].[contenthash].css",
        }),
        new VueLoaderPlugin(),
        new AssetsPlugin({
            filename: 'webpack.assets.json',
            path: environment.paths.output,
            prettyPrint: true,
        }),
    ],
    optimization: {
        minimize: false,
    },
    resolve: {
        fallback: {
            "fs": false
        },
        extensions: ['.js', '.jsx', '.json', '.css', '.scss'],
        modules: [
            path.resolve(__dirname, 'node_modules'),
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

This includes a compiler for Vuejs as well, as I've been using that for some simple interactive functionality. I like React, but I find it a bit too heavy for a lot of the simpler stuff that clients tend to ask for. Unless someone wants an SPA, I find myself leaning into Vue a lot more.

The great babel fish

I've got babel configured to only target modern browsers. No IE11 fixes required these days. I am so glad that old Trident engine is dead.

module.exports = {
    presets: [
      [
        "@babel/preset-env",
        {
          // Target modern browsers (>0.25% market share and not obsolete)
          targets: ">0.25%, not dead",
          // Enables polyfill injection based on your code usage (and your browser targets)
          useBuiltIns: "usage",
          corejs: "3.28",
          // Apply bug fixes from Babel's plugin layer
          bugfixes: true
        }
      ]
    ]
  };
Enter fullscreen mode Exit fullscreen mode

Scripting and styling

There's an app.js and an app.scss file in their respective folders in the repo. These, again, are barebones and just import the components that you need to get going.

Extend these as you need to.

That's pretty much it. PostCSS and Sass Linting are both light-touch configured, so you've got scope to modify those as you like as well.

Now go grab the repo

I've structured all of this into a public repo on Github. Please use it to your heart's content. Fork it. Recommend changes.

https://github.com/davidisnotnull/webpack-build-framework

David

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more