MD Bootstrap Webpack tutorial

Published 02.01.2019 Updated 31.12.2018

Arnt Oddvar Pedersen pro posted 3 weeks ago

This tutorial is created by Arnt Oddvar Pedersen and published thanks to his contribution.

Check out his profile page and Github.


You can find this entire tutorial complete and ready for use, in this GitHub repository.

 

Getting Started 

Welcome to this quick guide where you'll learn how to setup a complete Webpack environment optimized and ready for both Development and Production use. 

First and foremost, you will need NodeJS installed on your Mac/Computer. 

You can download NodeJS from here. 

I also highly recommend using Visual Studio Code as your Code Editor. This is also my preferred code editor personally. 

 

Once NodeJS is done installing on your system, create a folder where you want to start your project, open a command line, navigate to your newly created folder and initialize the project using the following command:

npm init

You'll then be asked a series of questions about your project. How you answer them is up to you.

 

Installing required packages 

Now that you've initialized your project, it's time to start adding the packages that we need for an automated production and development environment. 

To make full use of how powerful JavaScript has become in recent years, for this tutorial we're going to install Babel with a few plugins that transpiles edge JS to plain simple ES5. 

We are also going to install ESLint and the AirBnB JavaScript style guide to automatically find (and automatically fix some) problematic patterns of code while making sure we are adhering to a true-and-tested, mostly reasonable approach to JavaScript. 

Finally, we’re also going to install Webpack to manage our project. In your command line, run the following command to install all the needed "devDependencies" we need to manage our tutorial project.

npm install --save-dev @babel/cli @babel/core @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-proposal-do-expressions @babel/plugin-proposal-export-default-from @babel/plugin-proposal-export-namespace-from @babel/plugin-proposal-function-bind @babel/plugin-proposal-function-sent @babel/plugin-proposal-json-strings @babel/plugin-proposal-logical-assignment-operators @babel/plugin-proposal-nullish-coalescing-operator @babel/plugin-proposal-numeric-separator @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-pipeline-operator @babel/plugin-proposal-throw-expressions @babel/plugin-syntax-dynamic-import @babel/plugin-syntax-import-meta @babel/plugin-transform-arrow-functions @babel/preset-env babel-eslint babel-loader clean-webpack-plugin copy-webpack-plugin css-loader eslint eslint-config-airbnb-base eslint-loader eslint-plugin-import file-loader html-loader html-webpack-plugin mini-css-extract-plugin node-sass optimize-css-assets-webpack-plugin sass-loader style-loader terser terser-webpack-plugin webpack webpack-cli webpack-dev-server

This operation might some time, so sit back and enjoy a cup of coffee or tea while you wait.

 

Finally, to make MDBootstrap for jQuery work properly, we also need to install some required dependencies that MDB require to operate. (Both Free & Pro) 

In your terminal/command line, paste the following command:

npm install --save @fortawesome/fontawesome-free bootstrap datatables.net es6-promise hammerjs jquery node-waves popper.js underscore wow.js

Since Webpack can’t automatically detect the bundled modules of the MDBootstrap main JavaScript file, we need to install the required modules as dependencies. Once we’re done, Webpack will make sure that we’re not including duplicate modules when we are packing and bundling all our modules and JavaScript files for production use.

 

Configure ESLint 

In your root project folder, create a file called .eslintrc and paste the following code into it, then save it. 

{
  "extends": "airbnb-base",
  "parser": "babel-eslint",
  "env": {
    "browser": true,
    "jquery": true
  }
}

 

Configure Babel 

In your root project folder, create a file called .babelrc and paste the following code into it, then save it. 

{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-proposal-class-properties",
["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }],
"@babel/plugin-proposal-do-expressions",
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-function-bind",
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-json-strings",
"@babel/plugin-proposal-logical-assignment-operators",
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-optional-chaining",
["@babel/plugin-proposal-pipeline-operator", { "proposal": "minimal" }],
"@babel/plugin-proposal-throw-expressions",
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-transform-arrow-functions",
],
}

 

Wrapping up, configuring Webpack

Wrapping up, configuring Webpack 

Now that we’ve setup the entire project and installed the packages we need, it’s finally time to wrap-up this tutorial. Create a file in your project root folder called webpack.config.js 

This configuration file instructs Webpack how to handle all the file-types in your project/web-app, how to serve them for both production and development environments and WHERE to find your source files. A little bit of JavaScript knowledge here will go a long way, but I will try and explain everything as well. 

Before we start, you’ll see the following string mentioned a few times in the configuration file: path.resolve(__dirname, ‘folder1’, ‘subfolder’, ‘subfolder’) 

What this does, combined with “__dirname” gives you the absolute path to the directory containing the source file which is being executed (in node). When you add a comma separated list of folders afterwards, it tries to resolve and return the entire path, for example: 

/Users/username/mdb-webpack/subfolder/subfolder/ 

 

Now, paste the following into your webpack.config.js: 

 

const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = (env, argv) => {
return {
entry: [],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
mode: argv.mode,
module: {
rules: [
{
enforce: 'pre',
test: /\.js$/,
exclude: /(node_modules|bower_components|vendors)/,
loader: 'eslint-loader',
options: {
fix: true,
},
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components|vendors)/,
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
{
test: /\.html$/,
loader: 'html-loader',
options: {
minimize: true,
removeComments: true,
collapseWhitespace: true,
},
},
{
test: /\.(sa|sc)ss$/,
use: [argv.mode !== 'production' ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
{
test: /\.(jpe?g|png|gif)$/,
loader: 'file-loader',
options: {
outputPath: 'assets/',
},
},
{
test: /\.(eot|svg|ttf|woff2?|otf)$/,
loader: 'file-loader',
options: {
outputPath: 'assets/',
},
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html',
filename: 'index.html',
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.$': 'jquery',
'window.jQuery': 'jquery',
Waves: 'node-waves',
_: 'underscore',
Promise: 'es6-promise',
}),
new MiniCssExtractPlugin({
filename: argv.mode !== 'production' ? '[name].css' : '[name].[hash].css',
chunkFilename: argv.mode !== 'production' ? '[id].css' : '[id].[hash].css',
cssProcessorOptions: {
safe: true,
discardComments: {
removeAll: true,
},
},
}),
new CopyWebpackPlugin([
{
from: '**/*',
to: 'mdb-addons',
context: path.resolve(__dirname, 'src', 'vendors', 'mdb', 'mdb-addons'),
},
]),
new CleanWebpackPlugin('dist', { verbose: true }),
],
optimization: {
splitChunks: {
chunks: 'all',
},
minimizer: [
new TerserPlugin({
parallel: true,
sourceMap: true,
terserOptions: {
output: {
comments: false,
},
},
}),
new OptimizeCSSAssetsPlugin({}),
],
},
performance: {
hints: false,
},
};
};

(I have no idea why this won't format correctly...)

Before you can sit back and enjoy, thinking this tutorial is over – there are a few things we need to do.   

You’ll notice that the entry object is empty. This takes a string or array of strings with your app's entry-points. Place your main JavaScript and SCSS/SASS file that references all other files here.  

Next is the output object. Here you’ll need to set your desired path, where all the files will be put once you build your project for production. You’ll notice I’ve already set the output path to create a folder called dist in your project root. Next, you’ll see the filename variable. I’ve pre-set this to compile all JavaScript files into a file called bundle.js. Feel free to change the filename as well if you want.  

Note: All files will be served from the output path that is set in this object.  

  

Moving along, you’ll see the module object. This instructs Webpack what to do with the different file-types. Towards the bottom you’ll see the sections for images and web-font files. Here, you can set the output path to whatever you want. Once Webpack comes across these kinds of files, it will put the files Webpack finds into the folder name (or path) you type in here. I’ve already set the path here to put all image and font files into its own assets folder. If you want to separate these files into their own folders or want another destination folder, feel free to change the outputPath for both images and web-fonts.  

Finally, we come to the plugins object. This object further details how handle specific files or ranges of files. The first function you will come across is how we instruct Webpack about our HTML files. I’ve already set the first one for you, instruction Webpack where the template for our index.html file can be found, as well as what to call our first HTML file. The filename string can contain a path+name of the HTML file or simply the name.   

For example, if I wanted my index.html to be in its own folder, I would set the filename string to: my/directory/index.html and Webpack would try to resolve or create the path where you want your index.html file to reside. For simplicity sake, I’ve set Webpack to just dump the index.html file into our output folder. You can read more about the HTML Webpack Plugins’ settings here.  

Special note: There are many neat things you can do with this plugin. Keep an eye out on the Github repository link at the top for an advanced example coming soon.  

  

Next is the CSS extraction plugin. After Webpack is done processing any SCSS/SASS files in your project and converted them to CSS, this plugin tells Webpack what to do with the css files in production mode. Like above, if you want your CSS files to go into a separate directory, include the path in the filename and chunkFilename for both sets.  

The final two plugins are negligible. CopyWebpackPlugin copies the mdb-addons folder from the MDB Pro version if it exists. Since I store all my source files within a src/ folder, change the context path here to point to where you have your mdb-addons folder if you’re using the Pro version. Free users can just ignore this path.  

CleanWebpackPlugin simply deletes the dist folder every time you build your project.  

  

The optimization object is something you can play around with. I’ve sat the settings I personally use for production mode, splitting large css/js files into multiple smaller files (chunks), and minimizes your JavaScript files, using all your CPU cores for maximum speed, while removing all comments.  

Since some libraries needed by MDB and MDB itself, hints have been turned off to ignore warnings about large file sizes possibly having an impact on web load speeds.  

  

Congratulation on setting up Webpack for MDB and getting ready to develop! To see a full working example, check/clone my GitHub repository linked at the top of this tutorial.  

I am constantly updating this guide and the repository, so keep an eye out for changes. Feedback, criticism and comments are also welcome!  

For any problems, feel free to use the issue tracker on my GitHub repository and I’ll help you out as soon as I can.  

Thank you!  

 

Please insert min. 20 characters.
Details of the article
  • Category: jQuery
  • Specification: MDB jQuery Pro + MDB jQuery Free