webpack creates a graph of all of your application's dependencies. The starting point of this graph is known as an entry point. The entry point tells webpack where to start and follows the graph of dependencies to know what to bundle. You can think of your application's entry point as the contextual root or the first file to kick off your app. Simple rule: one entry point per HTML page. SPA: one entry point, MPA: multiple entry points. Entry Points are also called chunks
entry: {
home: "./home.js",
about: "./about.js",
contact: "./contact.js"
}
This will bundle all the files into three different files home.bundle.js, about.bundle.js, contact.bundle.js
If the entry file property is an array it will bundle all the array elements into one file name
entry: {
home: ['./app.js','./vendor.js','./ext.js']
}
This will bundle all the files into one home.bundle.js
By default the current directory is used, but it's recommended to pass a value in your configuration.
context: path.resolve(__dirname, "app")
Starting from the context folder It looks for entry filenames and reads the content. Every import (ES6) or require() (Node) dependency it finds as it parses the code, it bundles for the final build. It then searches those dependencies, and those dependencies’ dependencies, until it reaches the very end of the “tree”—only bundling what it needed to, and nothing else.
Once you've bundled all of your assets together, we still need to tell webpack where to bundle our application. The webpack output property describes to webpack how to treat bundled code.
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
Using entry name
filename: "[name].bundle.js"
Using internal chunk id
filename: "[id].bundle.js"
Using the unique hash generated for every build
filename: "[name].[hash].bundle.js"
Using hashes based on each chunks' content
filename: "[chunkhash].bundle.js"
Don’t use [chunkhash] in development since this will increase compilation time. Separate development and production configs and use [name].js for development and [name].[chunkhash].js in production.
Loaders have two purposes in your webpack config.
1.Identify what files should be transformed by a certain loader. (test property) 2.Transform that file so that it can be added to your dependency graph (and eventually your bundle). (use property) 3.Webpack's loaders are always evaluated from right to left and from bottom to top 4.enforce can be set to either pre or post to push processing either before or after other loaders.
module: {
rules: [
{
// Match files against RegExp. This accepts
// a function too.
test: /\.(js|jsx)$/,
// Restrict matching to a directory. This
// also accepts an array of paths.
//
// Although optional, I prefer to set this for
// JavaScript source as it helps with
// performance and keeps the configuration cleaner.
//
// This accepts an array or a function too. The
// same applies to `exclude` as well.
include: path.join(__dirname, 'app'),
/*
exclude(path) {
// You can perform more complicated checks
// through functions if you want.
return path.match(/node_modules/);
},
*/
// Apply loaders the matched files. These need to
// be installed separately. In this case our
// project would need *babel-loader*. This
// accepts an array of loaders as well and
// more forms are possible as discussed below.
use: 'babel-loader',
}
]
}
To use more than one loader and to pass query params
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: ['react', 'es2015'],
},
},
// Add more loaders here
]
In the configuration above we have defined a rules property for a single module with two required properties: test, and use. This tells webpack's compiler the following:
Hey webpack compiler, when you come across a path that resolves to a '.js' or '.jsx' file inside of a require()/import statement, use the babel-loader to transform it before you add it to the bundle".
Given webpack 2 forbids arbitrary root level configuration, you have to use LoaderOptionsPlugin to manage it. The plugin exists for legacy compatibility and may disappear in a future release.
plugins: [
new webpack.LoaderOptionsPlugin({
sassLoader: {
includePaths: [
path.join(__dirname, 'style'),
],
},
}),
]
This is important as you want to cache the non-updating humongous node_module libraries only once on the client's browser. Commons Chunk is smart. It will detect a piece of code which is used twice (minChunks) in your app dependencies and put it to a separate file which will not get updated unless it is changed. name is the name of entry chunk that you have provided and you can pass an array to it too
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: 'commons.bundle.js',
minChunks: 2,
}),
]
This is cool if you don't want much headache but this is configurable which means you can get the most out of it. You can specify in your entry files which files do you want to bundle as common bundle. Things are in your control now.
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor', 'manifest'],
minChunks: function (module) {
// this assumes your vendor imports exist in the node_modules directory
return module.context && module.context.indexOf('node_modules') !== -1;
}
})
]
You can do is write all the node_modules in a vendor chunk as array but that takes up a lot of time so the following code helps extracting that automatically. We can even extract out very frequently updating modules into another bundle to make sure not everything is downloaded when even a single module updates. Will add more...
// Extract all 3rd party modules into a separate 'vendor' chunk
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: ({ resource }) => /node_modules/.test(resource),
}),
// Generate a 'manifest' chunk to be inlined in the HTML template
new webpack.optimize.CommonsChunkPlugin('manifest'),
// Need this plugin for deterministic hashing
// until this issue is resolved: https://github.com/webpack/webpack/issues/1315
// for more info: https://webpack.js.org/how-to/cache/
new WebpackMd5Hash(),
// Creates a 'webpack-assets.json' file with all of the
// generated chunk names so you can reference them
new AssetsPlugin()
]
Skip build Dir .eslintignore
build/*
Define .eslintrc.js file We'll ensure that ESLint gets executed before anything else using the enforce field
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
loader: 'eslint-loader',
options: {
emitWarning: true,
},
},
],
}
Webpack does not allow arbitrary fields at configuration root level anymore. to access all functionality of the eslint-loader, you'll need to use LoaderOptionsPlugin as below.
plugins: [
new webpack.LoaderOptionsPlugin({
options: {
eslint: {
// Fail only on errors
failOnWarning: false,
failOnError: true,
// Disable/enable autofix
fix: false,
// Output to Jenkins compatible XML
outputReport: {
filePath: 'checkstyle.xml',
formatter: require('eslint/lib/formatters/checkstyle'),
},
},
},
}),
]
use clean-webpack-plugin to clean the build dir on each new build