So from now we manage a lot of things, but we need to divide our config into two parts:
Dev part (for developer)
Prod part (when we deploy our application on the web)
Until now we just focus on the Prod part!
So in this article, we will split our config into 3 files!
Common config webpack
Prod config
Dev config
Common config webpack
Some properties are common to dev & prod config files, so we can create a file that will contain these fields to avoid repeating code!
Before starting we need to install a package named webpack-merge
, which will merge two configs files into one! So we can merge-common file with another file !
After this, we create a common config file π
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const cdn = require("./cdn")
const config = {
// Webpack start from this entry point
entry: {
myApp: [
"./src/style.css",
"./src/main.js",
],
},
// External lib that will not be put in bundle but use from CDN
externals: {
lodash: '_',
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Webpack academy title',
template: './src/index.html',
inject: 'body',
cdn,
minify: {
removeComments: true,
collapseWhitespace: false
}
}),
new BundleAnalyzerPlugin({
openAnalyzer: true,
analyzerMode: 'server',
})
],
}
module.exports = config
In common config we need to use bundle analyser for prod & dev mode, we need also HTML plugin & clean webpack !
We also need to use cdn !
And we create a prod config file !
Prod config file
const commonConfig = require("./webpack.config.common")
const merge = require('webpack-merge')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const config = {
mode: "production",
module: {
rules: [
{
// Match file extension
test: /\.css$/,
// Order of loader from bottom to up
use: [
MiniCssExtractPlugin.loader,
'css-loader'
],
}
]
},
// This is the output of Webpack
output: {
// From current folder + dist folder that will contains all bundle
path: path.resolve(__dirname, "dist/"),
filename: "[contenthash:8].js"
},
optimization: {
minimize: true,
},
plugins: [
new MiniCssExtractPlugin({
// Name output by extract
filename: "style.css",
}),
],
}
// Merge commonConfig with prod config, priority to prod config
module.exports = merge(commonConfig, {
...config,
})
In prod mode we need to use hash, extract css & minimize bundle code !
It's almost finished for the prod part, we need to rename cdn
file to cdn.prod.js
since we will use two separate files for cdn in prod & dev mode !
And we need to edit script file
π
"build": "cross-env --env.NODE_ENV=prod webpack --config webpack.config.prod.js"
And it's finished from now for the prod part !
All things are working since before ! It's a good start to continue and go on the prod part!
Dev config file
Let's start by creating cdn.dev
!
Unlike prod cdn
, we will NOT use the minify
version of library ! We will just use the classic !
module.exports = {
js: [
"https://unpkg.com/lodash@4.17.15/lodash.js",
],
}
After this we need to install webpack-dev-server
, which serves to handle dev service like a dev server for developer !
And create the dev config π
const path = require("path")
const commonConfig = require("./webpack.config.common")
const merge = require('webpack-merge')
const config = {
mode: "development",
devServer: {
// Show info about dev server
noInfo: false,
// Port of dev server
port: 8080,
// Asking the server to fallback to index.html in the event that a requested resource cannot be found, need to vue router
historyApiFallback: true,
// Allows https in dev server
// Use this https://stackoverflow.com/questions/35531347/localhost-blocked-on-chrome-with-privacy-error for allow https in localhost directly on chrome
https: true,
},
// This is the output of Webpack
output: {
// From current folder + dist folder that will contains all bundle
path: path.resolve(__dirname, "dist/"),
filename: "bundle.dev.js"
},
module: {
rules: [
{
// Match file extension
test: /\.css$/,
// Use multiple loader
// Order => from bottom to top
use: [
'style-loader',
'css-loader'
],
}
]
}
}
// Merge commonConfig with prod config, priority to prod config
module.exports = merge(commonConfig, {
...config,
})
For css part
we need to use style-loader
since we need to inject style in the DOM !
We use some properties like port
, https
etc... (check comment above)
But on thing is very interesting and I should explain you π₯
historyApiFallback:
When you use a framework like Vuejs or React, you will choose between two things -> Use Router in front part or back part.
If you use vuejs for example and you need to use VueRouter (handling routing of your app in the Front part).
You will need to inform the current server that hosts your app (in my case webpack server) that you handle route by the front and not by the server (back).
But why ?
For example if you use router front and you will try this URL π
https://toto.com/test
The server will try to access to /test
file from the server files, and it will get nothing since it's not an existing file (because you handle routing by front). And you will get a 404
!
To avoid this behavior in our case, we need to tell the server -> If you have a 404, access to the root file (main file) and not looking for /test file
And after this you can enter any URL and your project will works !
So this options historyApiFallback
is just an option to prevent this if you use Router in the front part, you should put true
! Else put false
!
We almost finish πͺ
Create the command to run our app in dev mode
"dev": "cross-env --env.NODE_ENV=dev webpack serve --hot --config webpack.config.dev.js",
webpack serve --hot
: Command to run webpack server in hot reload mode (when a file is changed, we reload our project automatically)
Source map
We will not get in details about this, if you want to check this URL -> https://blog.teamtreehouse.com/introduction-source-maps
To be short, in dev mode we will need to debug some files, if we don't use source map, we will have some files that are a little weird, for example, our main.js
π
lodash__WEBPACK_IMPORTED_MODULE_1___default().cloneDeep({})
console.log(_three__WEBPACK_IMPORTED_MODULE_0__.three)
document.getElementById("button").addEventListener("click", function() {
jsonObjectImport().then(jsonObject => console.log(jsonObject.default))
})
Here it's not a problem, but with big files we can have some trouble to debug this !
So source map
is our hero ! π¦ΈββοΈ
devtool: 'eval-cheap-source-map',
(You have a lot of choices about source map, for me the best to use in dev is 'eval-cheap-source-map'), check at this URL to have more information: https://webpack.js.org/configuration/devtool/
When you want to debug the main.js
, you will see another file like main.js?56d7
and this is this file that we will need to debug ! Open it and π
import { three } from './three'
import _ from 'lodash'
const jsonObjectImport = async () => import(/* webpackChunkName: "myChunkName" */ "./big-object.json")
_.cloneDeep({})
console.log(three)
document.getElementById("button").addEventListener("click", function() {
jsonObjectImport().then(jsonObject => console.log(jsonObject.default))
})
It's like our original main.js
file !
To summarise source map :
When we bundle our code with Webpack, it will compile our original file into another special file (can be weird), so if we want to debug our code, we will have this special file that is different from the original file code.
To fix this we can use source map that will keep track of our original file (each original file has a special hash). So if we need to debug code we can find the file like the original file !
Well done ! πͺπ₯
We made it ! We manage to split the original config into two parts !
We almost finish the webpack academy!
I hope you like this, You can check the source code at this commit
π Note: We create two more commands for bundle analyzer, in prod and dev mode if we need to check bundle size in both cases
I hope you like this reading!
π You can get my new book Underrated skills in javascript, make the difference
for FREE if you follow me on Twitter and MP me π
Or get it HERE
π MY NEWSLETTER
βοΈ You can SUPPORT MY WORKS π
πββοΈ You can follow me on π
π Twitter : https://twitter.com/code__oz
π¨βπ» Github: https://github.com/Code-Oz
And you can mark π this article!
Top comments (0)