There are a few obscure variable names in Webpack, mainly to make a summary.

What is the difference between module, chunk, and bundle in Webpack?

Look at this graph and it makes sense:

For a piece of code with the same logic, when we write one file after another, whether they are ESM, commonJS or AMD, they are all modules; When the module source file we wrote is sent to Webpack for packaging, Webpack will generate a chunk file according to the file reference relationship, and Webpack will perform some operations on this chunk file. After processing the chunk files, WebPack finally outputs the bundle file, which contains the loaded and compiled final source file, so it can be run directly in the browser. In general, a chunk corresponds to a bundle, such as in the figure above, utils.js -> chunks -> utils.bundle.js; There are exceptions, such as in the example above, where I use the MiniCssExtractPlugin to pull out the index.bundle. CSS file from chunks 0.

In a word:

Module, chunk, and bundle are the same logical code with three names in different transformation scenarios: module is written directly, chunk is processed by Webpack, and bundle can be run directly by the browser.

2. Difference between filename and chunkFilename

filename

Filename is a common configuration. It is the name of the output file corresponding to the input file in Entry that is packaged by Webpack. For example, after the following configuration, the generated file is named index.min.js.

{
 entry: {
 index: ".. /src/index.js"
 },
 output: {
 filename: "[name].min.js".// index.min.js}}Copy the code

chunkFilename

HunkFilename indicates the name of the chunk file that is not included in the entry but needs to be packed out. In general, this chunk file refers to code that is lazy to load. For example, we wrote a lazy loDash code in our business code:

// File: index.js
// Create a button
let btn = document.createElement("button");
btn.innerHTML = "click me";
document.body.appendChild(btn);
// Load code asynchronously
async function getAsyncComponent() {
 var element = document.createElement('div');
 const { default: _} =await import('lodash');
 element.innerHTML = _.join(['Hello! '.'dynamic'.'imports'.'async'].' ');
 return element;
}
// When button is clicked, loDash lazily loads and displays Hello! dynamic imports async
btn.addEventListener('click'.() = > {
 getAsyncComponent().then(component= > {
 document.body.appendChild(component); })})Copy the code

Our Webpack does not do any configuration, the original configuration code:

{
 entry: {
 index: ".. /src/index.js"
 },
 output: {
 filename: "[name].min.js".// index.min.js}}Copy the code

The packing result at this time is as follows:

The 1.min.js file is the chunk file loaded asynchronously. The document explains:

Output.chunkfilename defaults to use [id].js or a value inferred from output.filename ([name] is pre-replaced with [id] or [id].)

The document is too abstract, so let’s use the example above:

The output filename of output.filename is [name].min.js. [name] is inferred to be index according to the entry configuration, so the output file is index.min.js.

Since output.chunkfilename is not specified, [name] is replaced with the chunk file ID, where the file ID is 1, so the file name is 1.min.js.

If we explicitly configure chunkFilename, the file is generated with the configured name:

{
 entry: {
 index: ".. /src/index.js"
 },
 output: {
 filename: "[name].min.js".// index.min.js
 chunkFilename: 'bundle.js'.// bundle.js}}Copy the code

In a word:

Filename indicates the name of the file listed in entry and output after packaging.

ChunkFilename refers to the name of the file that is not listed in the entry but needs to be packed out

3. What are webpackPrefetch, webpackPreload, and webpackChunkName?

webpackChunkName

As an example of loading lodash asynchronously, we ended up writing output.chunkfilename to bundle.js. In our business code, it is not possible to load only one file asynchronously, so writing to death is definitely not possible. However, when writing [name].bundle.js, the file is packaged with an obscure chunk ID that is not well recognized.

{
 entry: {
 index: ".. /src/index.js"
 },
 output: {
 filename: "[name].min.js".// index.min.js
 chunkFilename: '[name].bundle.js'.// 1.bundle.js, where the chunk ID is 1, is not recognizable}}Copy the code

This is where webpackChunkName comes in handy. We can alias chunk files with comments in import when importing files:

async function getAsyncComponent() {
 var element = document.createElement('div');
 
 /* webpackChunkName: "lodash" */ alias the imported file
 const { default: _} =await import(/* webpackChunkName: "lodash" */ 'lodash');
 element.innerHTML = _.join(['Hello! '.'dynamic'.'imports'.'async'].' ');
 return element;
}
Copy the code

The generated file looks like this:

Now the question is, lodash is the name we’re using, and it should make LoDash.bundle. js, so what are the vendors~?

SplitChunksPlugin is a built-in SplitChunksPlugin plugin. The default SplitChunksPlugin plugin for automaticNameDelimiter is ~. I’m not going to go into this, but if you’re interested, you can do your own research.

WebpackPrefetch and webpackPreload

The two configurations are called Prefetch and Preload, and they are slightly different. Let’s talk about WebPackage Prefetch first.

In the lazy loading code above, the asynchronous loading of loDash is triggered when the button is clicked, which dynamically generates a script tag and loads it into the head:

If we add webpackPrefetch when we import:

const { default: _} =await import(/* webpackChunkName: "lodash" */ /* webpackPrefetch: true */ 'lodash');
Copy the code

The lodash code will be prepulled in the form of:

This asynchronous loading code does not need to be triggered manually by clicking button. Webpack loads loDash files at idle time after the parent chunk has finished loading.

WebpackPreload preloads resources that may be required under the current navigation. The main differences between webpackPrefetch and webpackPrefetch are:

Preload Chunk starts loading in parallel when the parent chunk loads. Prefetch Chunk starts loading after the parent chunk finishes loading. Preload Chunk has medium priority and is downloaded immediately. Prefetch Chunk downloads while the browser is idle. Preload chunk is immediately requested in the parent chunk for the present moment. Prefetch Chunk will be used at some point in the future

In a word:

WebpackChunkName is an alias for a preloaded file. WebpackPrefetch will download the file when the browser is idle, and webpackPreload will download the file concurrently when the parent chunk is loaded.

4. What’s the difference between hash, Chunkhash, and Contenthash?

First, to give some background, hashing is usually used in conjunction with CDN caching. If the file content changes, the corresponding file hash value will also change, and the URL address referenced by the corresponding HTML will also change, triggering the CDN server to pull the corresponding data from the source server, and then update the local cache.

hash

Hash calculation is related to the construction of the whole project, so let’s do a simple demo. Use the demo code of case 1, and the file directory is as follows:

├─ SRC / ├─ index.css ├─ index.html ├─ index.js ├── utils.jsCopy the code

The core configuration of WebPack is as follows (some Module configuration information is omitted) :

{
 entry: {
 index: ".. /src/index.js".utils: '.. /src/utils.js',},output: {
 filename: "[name].[hash].js"./ / to hash},...plugins: [
 new MiniCssExtractPlugin({
 filename: 'index.[hash].css' / / to hash]}}),Copy the code

The generated file name is as follows:We can see that the generated file hash is exactly the same as the project build hash.

chunkhash

Since the hash is the hash value that the project builds, if something changes in the project, the hash will definitely change. For example, if I change the utils. Js code, the index.js code does not change, but everyone uses the same hash. There is no way to implement CDN and browser caching in this way.

Chunkhash solves this problem by parsing dependent files according to different Entry files, constructing corresponding chunks, and generating corresponding hash values.

For another example, we make a change to a file in utils.js:

export function square(x) { return x * x; } // export function cube(x) {return x * x * x; }

Then change all hashes in webpack to chunkhash:

{ entry: { index: “.. /src/index.js”, utils: ‘.. / SRC /utils. Js ‘,}, output: {filename: “[name].[chunkhash].js”, // change to chunkhash},

.

Plugins: [new MiniCssExtractPlugin({filename: ‘index.[chunkhash].css’ // // change to chunkhash}),]}

The construction results are as follows:We can see that the hash for chunk 0 is the same, and the hash for Chunk 1 is different.

Suppose I removed the cube() function from utils.js and packaged it again:

The comparison shows that only the hash of Chunk 1 changes, while the hash of Chunk 0 remains the same

contenthash

Js and index.css are the same chunk. If the contents of index.js change but the index.css does not, their hash changes after packaging, which is a waste of CSS files. How to solve this problem?

Contenthash creates a unique hash based on the content of the resource, that is, the hash remains the same as the content of the file remains the same.

Let’s modify the webPack configuration:

{
 entry: {
 index: ".. /src/index.js".utils: '.. /src/utils.js',},output: {
 filename: "[name].[chunkhash].js",},...plugins: [
 new MiniCssExtractPlugin({
 filename: 'index.[contenthash].css' Contenthash = contenthash]}}),Copy the code

We made three changes to the index.js file (that is, we changed the output of the log function), and then built the file separately. The screenshot of the result is as follows:

We can see that the HASH of the CSS file has not changed.

In a word:

Hash computations are associated with building the entire project;

Chunkhash computations are associated with the same chunk of content;

The Contenthash calculation is related to the content of the file itself.

5. What do eval, cheap, inline, and module mean in sourse-map?

Developing common configurations:

1.source-map

Big and complete, everything, just because everything can make webPack take longer to build, depending on the situation.

2.cheap-module-eval-source-map

This is generally recommended by development environments (Dev) and provides a good balance between build speed error alerts.

3.cheap-module-source-map

Source-map is generally not available in production environments, so if you want to catch code errors on the line, you can use this