The author

Peng Daokuan is known as “Eddie Peng of Guangzhou”.

By the way, if you like, check out the SugarTurboS Team

preface

I still remember my first imitation station project: Vue development from entry to actual combat, I just watched the first three sections of the video, I gave up, if you ask me why, I will be proud to tell you that the building environment was not successful, the old configuration of Webpack is wrong, the project can not run.

I have thought, how to learn Webpack, I went to the Internet to search, many tutorials, such as Webpack fool guide, Webpack entry experience, Webpack fancy entry tutorial, I have a rough look, all good, but failed to find their own learning Webpack the right way; I went to look at the documents, but it was boring and boring. I went to B station to study, and a mysterious Eastern power changed the content of my video from Webpack to Lisa. I went to look at the configuration of excellent projects, but it was too complicated. For me this kind of beginner Webpack good comrade will tell, it is a sin.

It’s just a matter of time. How do you learn Webpack? Give you a lot of concepts at the beginning, or chew over documents? Most of the time it doesn’t work. I’ve been down that road. So to really understand Webpack and get started with it, it’s important to get it right.

The following broadband we learn about Webpack, if there is a mistake, 👏 welcome to point out

The content of this article is taken from the booklet: 👉 Electron + React from 0 to 1 to realize the practical application of the resume platform

Webpack concept

This article mainly introduces Webpack related knowledge, talk about the origin of Webpack and why we use Webpack, through two powerful tools: Loader and Plugins to explain, the whole content is relatively long, please bear reading.

The best way to get a quick idea of what Webpack is is to check it out on the website. Webpack is a static Module bundler for modern JavaScript applications.

At the beginning, Webpack was not widely known. When it first came out, the major advantage was Code Splitting, which we can now find its definition on the official website:

Code Splitting refers to Splitting Code into different packages/blocks that can then be loaded on demand, rather than loading a single package with everything in it.

When will Webpack get noticed? In 2014, the front end team of Instagram shared their internal front end page loading performance optimization at a conference. The most important thing they mentioned was the use of Code Splitting for Webpack.

This was a huge boost for Webpack friends, and it became a craze. The tuyere of Webpack came, many companies have used Webpack, and contributed countless Plugin, Loader, you a knife, I a knife, Webpack will come out tomorrow, sure enough, within a short time, Webpack was pushed to the climax.

Everybody uses it. Do I need it? If your application is very small, has no static resources, and only needs a JS file, using Webpack is not a good choice. Whether you use it or not depends on your own assessment

Next, when we talk about other basic properties, we will first look at the two powerful tools of Webpack, and then through a simple Webpack configuration to explain to you.

Two edge tool

Thanks to Webpack’s strong expansibility and perfect plug-in mechanism, many Loader and Plugin are officially provided. Next, through problems and simple and clear demo, we will explain these two powerful tools to you. Before that, we will install Webpack globally.

NPM install [email protected] --save --dev NPM install [email protected] --save --devCopy the code

Loader module packaging scheme

Webpack can use Loader to preprocess files. This allows you to package any static resource except JS.

Loader is a module packaging solution. Webpack, by default, knows how to package JS files, but for other types of files, it doesn’t know what to do with them, so we have to tell it how to package them.

Now, let’s use an example to help you understand why I say it’s a solution.

Let’s create a new demo folder and create an index.js file with this structure

├── ├─ ├─ ├─Copy the code

At this point we write this line of code in index.js

// index.js
const myName = 'My name is Pang Daokuan.';
console.log(myName);
Copy the code

Execute NPX webpack index.js, which means pack our index.js file.

We can see on the terminal that Webpack can also package JS type files without configuring anything, which means Webpack has a package scheme for JS files by default

Next, let’s change our code to something like this to introduce our image

// index.js
import myPdkAvatar from './avatar.jpg';

const myName = 'My name is Pang Daokuan.';
console.log(myName);
Copy the code

NPX webpack index.js () Failed to package the JPG file

Webpack is friendly and tells you that you need a loader to handle this file type.

There is a special solution for this type: file-loader. Let’s install this loader

npm install --save-dev file-loader
Copy the code

Then we add a new file, webpack.config.js, which looks like this

├ ─ ─ demo │ ├ ─ ─ index. The js │ └ ─ ─ webpack. Config. Js └ ─ ─...Copy the code

In the configuration file, we add the processing scheme for JPG files

// webpack.config.js
module.exports = {
  module: {
    rules: [{test: /\.jpg$/,
        use: [
          {
            loader: 'file-loader'.options: {
              name: '[name]_[hash].[ext]'.outputPath: 'images/',},},],},},};Copy the code

When a module is encountered, rules matches. If a file of type /\.jpg$/ is found, file-loader is used and parameters are configured: Name and outputPath, meaning that the packaged file name is named according to the [filename]_[hash].[source type] rule and is output in the images/ directory

Now that we understand what this code means, let’s go back to packing and see what the result is

Packing ok! Let’s take a look at the packaged Dist. Is there really an images/ directory that holds the packaged images?

As we thought, now back to the details, Loader is a module packaging solution does it make sense? I’m going to write a few lines of code, and I’m going to go through them

module.exports = {
  module: {
    rules: [{test: /\.css$/,
        use: ['style-loader'.'css-loader'.'postcss-loader'],}, {test: /\.less$/,
        use: {
          loader: 'less-loader',}}, {test: /\.vue$/,
        use: {
          loader: 'vue-loader',},},],},};Copy the code

Plugins give you wings and make packing easier

Continuing with the Loader demo above, review our current demo file directory structure

├ ─ ─ demo │ ├ ─ ─ index. The js │ └ ─ ─ webpack. Config. Js └ ─ ─Copy the code

Let’s first run NPX webpack index.js to see what files are in the dist directory

If output is not configured, its default value is./dist/main.js, and the other generated files are placed in the./dist folder by default.

Since we are using the default configuration, the generated folder name of the bundle is dist, and the bundle default name is main.js

Next we manually create an HTML and load the packed JS file. How do we load it? Load the packaged main.js via script

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>webpack plugins demo</title>
  </head>
  <body>
    <div id="root"></div>

    <! Load the packed main.js file here -->
    <script src="./dist/main.js"></script>
  </body>
</html>
Copy the code

Then run the page and, through the console, you can see that it prints: My name is Dau-kuan Peng

Suppose you have a scenario where you want to name the output bundle using a hash. Let’s modify webpack.config.js

module.exports = {
  // 1. Webpack performs the first step of the build from entry, where our entry file is index.js
  entry: './index.js'.// 2. Go through a series of processes to get the final code, and then output the result
  output: {
    // Here will output the resulting code file with a custom configuration file name
    filename: '[Peng Dao Kuan]_[hash].bundle.js',},// ...
};
Copy the code

Execute NPX webpack index.js to see if the packed file is named as expected

Okay, what do we do when we load HTML? Manually change the file address to a correct one

<script src=". / dist / / peng channel width _657b45ee79dee39108f7 bundle. Js. ""></script>
Copy the code

If we modify the contents of the index.js file (add a line of code below 👇)

// index.js
import myPdkAvatar from './avatar.jpg';

const myName = 'My name is Pang Daokuan.';
console.log(myName);

// 👇 add a new line of code
console.log('new add code ...... ');
Copy the code

Then delete the dist directory and package again to see if the file hash is consistent?

By comparison, we can see that the bundle filename hash generated by repackaging is different with each change. This is equivalent to manually changing the file reference in THE HTML each time you pack.

Too primitive, too cumbersome, too inefficient! To this end, Webpack provides Plugins capabilities to make Webpack even more flexible.

Many Plugins are provided by the authorities to make packaging more convenient. For the above problems, we can use the HtmlWebpackPlugin to simplify the creation of HTML files. This is especially useful for Webpack bundles that include hashes in their file names that change each time they compile!

Try it. Install the plugin according to the documentation and see what it can achieve

npm install --save-dev html-webpack-plugin
Copy the code

Once installed, we’ll modify the webpack.config.js content to bring the plug-in in

// 👇 import this plug-in
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './index.js'.output: {
    filename: '[Peng Dao Kuan]_[hash].bundle.js',},// 👇 use this plug-in
  plugins: [new HtmlWebpackPlugin()],
};
Copy the code

NPX webpack index.js. What files are packed?

The HtmlWebpackPlugin automatically generates an HTML file for us after the packaging is complete and automatically introduces the packaged bundle. When we modify and repackage the content, the generated HTML is also automatically introduced with each compilation of the bundle that causes a hash change.

Isn’t it perfect? No, let’s take a hard look at the HTML file generated by HtmlWebpackPlugin and see that something seems to be wrong? Do you have some DOM nodes missing from the body? (For example, Vue and React have a DOM element with the ID of APP.) This is generated by default, so is there a way to generate the DOM structure I want?

HtmlWebpackPlugin provides a configuration parameter template that allows you to customize an HTML file, use this file as a template, generate a copy of the same HTML and automatically import the packaged bundle for you.

Let’s start by defining a “unique” HTML template.

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>I am the template for HtmlWebpackPlugin</title>
    <style>
      * {
        margin: 0;
      }
    </style>
  </head>
  <body>
    <div id="root">
      <div id="pdk">PDK Demo</div>
    </div>
  </body>
</html>
Copy the code

This template is then adopted by modifying the webpack.config.js configuration

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './index.js'.output: {
    filename: '[Peng Dao Kuan]_[hash].bundle.js',},plugins: [
    // 👇 is generated using the HTML template we wrote
    new HtmlWebpackPlugin({
      template: './index.html',})]};Copy the code

Finally, is the structure of the packaged, auto-generated HTML file consistent with our template?

Turns out, it’s exactly the same.

There are plenty of clever and useful Plugins out there, almost all of which are designed to make packaging and building easier. Use search engines to find Plugins (official Plugins or third-party Plugins) and solutions to problems.

conclusion

  • Loader is a module packaging solution, in other words, it is a translator with file type conversion
  • Plugins are used to extend the functionality of Webpack, making it extremely flexible.
  • Plugins can do something for you at a certain point in the Webpack run. This is equivalent to Webpack throwing hooks and executing injection hook functions when Webpack is running in a certain lifecycle. For example, Plugins are very much like Vue and React life cycle functions that do things when Webpack runs into a life cycle.

In the example above, the HtmlWebpackPlugin does something at the end of the Webpack lifecycle — automatically generates the HTML file and introduces the packaged bundle.

In a third-party plug-in like clean-Webpack-plugin, it actually does something at a life-cycle point before the WebPack is packed — it deletes the directory we packed

These two Plugins will be used in your projects, so go back and look at the configuration of your projects, combine the documentation, and make sure to use the Plugins in detail.

advice

There are many loaders and Plugins provided by the authorities. If you have problems in packaging certain types of files, you can directly search for information on Baidu and read the documents, and 95% of the problems can be solved.

After second thought, the working principle of Loader is still not explained, and the basic introduction is the focus, so as not to frighten a group of students by talking about the principle at the beginning. If some friends are interested in its principle, Hiro can introduce a small Easter egg chapter.

Easter egg – Simple Webpack configuration

Below, I will take the small volume Electron + React from 0 to 1 to realize the configuration of the resume platform as an example to tell about it

More attribute fields are used when to start to practice, not just bite the document ah

See code comments!!

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  // 👇 resolve configures how Webpack finds files for modules.
  / / document path: https://webpack.js.org/configuration/resolve/#root
  resolve: {
    // We have extensions configured to indicate that Webpack will automatically append the suffix to try to see if the file exists when there is no file suffix in the import statement.
    Here / / configuration extensions: [' js', 'JSX' and 'ts',' benchmark '], means that when met the import from A '/ A'
    // If a.js is not found, then a.js is found.
    extensions: ['.js'.'.jsx'.'.ts'.'.tsx'].// alias stands for alias, because we often write import A from '.. /.. /.. /.. /.. /A' import path, especially disgusting, so configure alias processing.
    / / the document address: https://webpack.js.org/configuration/resolve/#resolvealias
    alias: {
      '@src': path.join(__dirname, '.. / '.'app/renderer'),}},// 👇 define our environment variable. The mode defined here is equivalent to the process.env.node_env we defined in DefinePlugin
  / / the document address: https://webpack.js.org/configuration/mode/#root
  mode: 'development'.// 👇 entry file, here we define multiple entry files
  / / the document address: https://webpack.js.org/concepts/#entry
  / / here in actual combat can see small copies of actual combat section: https://juejin.cn/book/6950646725295996940/section/6962940676258398222
  entry: {
    index: path.resolve(__dirname, '.. /app/renderer/app.tsx'),
    setting: path.resolve(__dirname, '.. /app/renderer/windowPages/setting/app.tsx'),},// 👇 packaged files
  / / the document address: https://webpack.js.org/concepts/#output
  output: {
    filename: '[name].[hash].js'.path: path.resolve(__dirname, '.. /dist'),},// 👇 build target, default is web, in the small book here to be overwritten as electron-renderer
  // In normal development, we do not need to configure this option, because we specify the Web, all the optional values of this property see the documentation
  / / the document address: https://webpack.docschina.org/configuration/target/#target
  target: 'electron-renderer'./ / 👇 document address: https://webpack.docschina.org/configuration/devtool/#devtool
  devtool: 'inline-source-map'.// 👇 We expect to monitor file changes, refresh the web page automatically, and preview in real time
  // Instead of changing a single letter, each word needs to be repackaged. So we started a local service
  // You can visit our target website at http://127.0.0.1:7001
  devServer: {
    contentBase: path.join(__dirname, '.. /dist'),
    compress: true.host: '127.0.0.1'.// Webpack-dev-server must be started with an IP address. It cannot be directly started with localhost
    port: 7001.// Start the service on port 7001
    hot: true,},module: {
    rules: [
      To / / / 👇 when matching \. (js | JSX | | ts TSX) $/ file, use the Babel - loader to deal with it.
      // Exclude files in the node_modules folder
      {
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',}},/ / 👇 when matching to / \. (JPG | PNG | jpeg | GIF) $/ file, using the file - loader to deal with it.
      // Webpack files are stored in dist/images and named in the format of [name]_[hash].[ext]
      {
        test: /\.(jpg|png|jpeg|gif)$/,
        use: [
          {
            loader: 'file-loader'.options: {
              name: '[name]_[hash].[ext]'.outputPath: 'images/',},},],},// 👇 When a match is found in /\.css$/, use the following loader to handle it.
      {
        test: /\.css$/,
        use: ['style-loader'.'css-loader'.'postcss-loader'],},// 👇 If the file /\.less$/ is matched, use the following loader to handle it.
      {
        test: /\.less$/,
        exclude: /node_modules/,
        use: [
          'style-loader',
          {
            loader: 'css-loader'.options: {
              modules: {
                localIdentName: '[name]__[local]__[hash:base64:5]',}}},'postcss-loader'.'less-loader',],},],},plugins: [
    // 👇 each time before packaging, delete the dist directory, and then regenerate it. Here we use clean-webpack-plugin
    new CleanWebpackPlugin(),
    // 👇 Because of each change, the bundle file name hash generated by repackaging is different. This is equivalent to manually changing the file reference in THE HTML each time you pack
    // Inefficiency! To this end, we can use the HtmlWebpackPlugin to simplify the creation of HTML files
    // This is especially useful for Webpack bundles whose file names contain hashes that change each time they are compiled!
    // Since we defined two entries above, we correspond to two HTMLWebPackplugins
    / / the document address: https://webpack.docschina.org/plugins/html-webpack-plugin/
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '.. /app/renderer/index.html'),
      filename: path.resolve(__dirname, '.. /dist/index.html'),
      chunks: ['index'],}).new HtmlWebpackPlugin({
      template: path.resolve(
        __dirname,
        '.. /app/renderer/windowPages/setting/index.html'
      ),
      filename: path.resolve(__dirname, '.. /dist/setting.html'),
      chunks: ['setting'],}),]};Copy the code

The following image is from the booklet: Electron + React implementing a resume platform from 0 to 1

Click here to see the original source of this article

The last

I hope this article can let friends understand Webpack, rather than hard documents, although “the book read a hundred times its meaning from”, but “paper comes zhongjue shallow, paper comes Zhongjue shallow, must know this to practice”, practice is the only standard to test the truth. Friends must be practical, this is the best way!