DEV Community

Cover image for I efficiently learned "webpack development environment configuration" using this idea
Lee
Lee

Posted on • Originally published at juejin.cn

I efficiently learned "webpack development environment configuration" using this idea

Preface

We often see structures like the following when using webpack:

build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js
Enter fullscreen mode Exit fullscreen mode

Often times, webpack configurations we basically copy and paste without thinking about why we're breaking the config file down into so many. As a result, when we learn to configure webpack on our own, we often have problems such as the following:

  • Slow builds in development environments
  • Blank pages after packaging
  • Resources not found

In fact, these problems, all stem from us:

  • Not understanding webpack to build the development environment, production environment, the two environment configuration of the difference in thinking
  • We don't have a clear understanding of the file directories of the two environments.

So this article is the same as before, will not just copy the configuration over, but hope that summarize the relevant methods, so that we can better learn to configure.

Learning Outline

This article focuses on:

  • The core idea of webpack development environment configuration.
  • Completing a development environment configuration based on the core concepts
  • Explain some confusing points in the devServer configuration.
  • Summarize the core ideas of webpack development environment configuration.

Remarks

The article has been uploaded to github:

  • For the sake of reading convenience, the article only posted the relevant code, it is recommended to fork it to see the complete code; or follow along with the article and write the code yourself
  • It's not easy to create, if you think it's helpful, welcome to star🌟!

Development Environment Core Ideas

We mentioned above that we often see directories like the following when using webpack:

build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js
Enter fullscreen mode Exit fullscreen mode

Why do we need to break the configuration file into so many, so cumbersome?

Let's first review, in our actual development, in order to project can be stable and safe on-line, we will generally be divided into several environments:

  • Development environment: local development, debugging environment
  • Test environment: we complete the local development, the code will be deployed to our test server, for testing
  • Production environment: the test passed, the code will be deployed to the official server, the official on-line

Some of the more rigorous tests will have pre-production environments, etc.

Our configuration should be specific to the environment, so of course our configuration should not be the same for different environments.

Purpose

We need to be clear about what the fundamental purpose of the development environment is.

The fundamental purpose of the development environment is to quickly locate problems during the development process, to see the effect of debugging faster, and to improve development efficiency.

Especially as a front-end, inseparable from the visual dealings. We can't wait to Ctrl+S, immediately after the effect, so that we can quickly debug. Imagine if every time we write an effect, we have to wait for a few seconds before we can see it, will this drive us crazy?

Ideas

Therefore, in order for us to see the effect debugging as soon as possible, reducing the webpack compilation process, development environment, the configuration should be everything from simple:

  • For styles, we don't need to separate them and insert them directly into the <head /> with the style-loader.
  • For js, img, media, font and other front-end resource files, we don't need to separate them.
  • Enable source map to locate the problem.
  • Use the devServer configuration provided by webpack for local development.
  • Don't compress code.
  • Don't use unnecessary loader and plugins.
  • ...

Development environment configuration is also different from person to person, this is what I do. But we should remember that development environment, configuration should be kept simple, in order to let us see the results faster, improve development efficiency!

Development environment configuration

First experience

Through the previous explanation, I believe you are familiar with the basic configuration of webpack:

  • Handling css, less, front-end resources and other files
  • Compiling es6+ syntax and api.
  • Processing html files

have mastered the relevant configuration methods, and we also summarized a basic configuration, not too clear students can look at the first, this basic configuration is still quite important.

ok, then we first use learn-08 this case to experience how to do local development debugging. In order to be as close as possible to our real-life development projects, the case will:

  • refer to the image in html.
  • use less to reference an image
  • use es6+ in js to load images dynamically.
  • Use the devServer configuration item.

For ease of reading, I'm not going to put the source code in the article, you can go to github to see it.

Then perform the following steps:

  1. for semantic purposes, we name the webpack configuration file webpack.dev.js
  2. Start webpack on the command line - npm start.
"scripts": {
    "start": "webpack server --config ./webpack.dev.js"
}
Enter fullscreen mode Exit fullscreen mode

Run the results:

devserve.png

We will find:

  • After the file compilation and processing is complete, no file is outputted
  • At this point, an internal server (http://192.168.0.196:8080/) is turned on. If we are on the same network as our computer, we can access this link from our phone and see the results. This is very efficient for debugging H5 development (this is mainly due to the deveServer configuration item, which will be explained later on)
  • The page is updated in real time after we change the code

The above is pretty much what we want for efficient development.

Analyzing

After the initial experience, let's take a look at how to configure the development environment based on the development environment configuration ideas summarized above:

  • Parsing styles does not require separating out the css file; we insert the parsed styles directly into the <header />:
module: {
    rules: [
        {
            test: /.(css|less)$/, 
            use: [
                'style-loader',
                'css-loader',
                'less-loader'
            ]
        },
    ]
},
Enter fullscreen mode Exit fullscreen mode
  • For js, img, media, font and other front-end resource files, there is no need to subpackage:
output: {
    path: path.resolve(__dirname, './dist'),
    filename: '[name]-[chunkhash:5].js',
},
module: {
    rules: [
        {
            test: /\.(png|svg|jpg|jpeg|gif)$/i,
            type: 'asset',
            parser: {
                dataUrlCondition: {
                    maxSize: 1024 * 3 // When the image size is < 3kb it will be converted to base64
                }
            },
            generator: {
                filename: '[name]-[hash:5][ext]' // Set the name of the output file
            }
        },
        {
            test: /\.m?js$/,
            exclude: /(node_modules|bower_components)/,
            use: {
                loader: 'babel-loader'
            }
        }
    ]
},
Enter fullscreen mode Exit fullscreen mode
  • Enable source map to make it easier to locate the problem; and not compress the code:
{
    mode: 'development',
    devtool: 'inline-cheap-module-source-map'
}
Enter fullscreen mode Exit fullscreen mode
  • Use the devServer provided with webpack for local development:
devServer: {
    static: {
        directory: path.join(__dirname, 'static'),
    },
},
Enter fullscreen mode Exit fullscreen mode
  • No other extra plugins were installed, only the plugin that parses html was installed because it parses html:
plugins: [
    new HtmlWebpackPlugin({
        filename: path.resolve(__dirname, './dist/[name].html'),
        template: path.resolve(__dirname, './src/index.html'),
        title: 'webpack.dev.config',
    })
],
Enter fullscreen mode Exit fullscreen mode

If we compare the base configuration, we will find that the development environment configuration is almost the same as the base configuration, except that the devServer configuration item is used more to enable local server debugging:

// webpack.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
+   mode: 'development',
+   devtool: 'inline-cheap-module-source-map',
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name]-[chunkhash:5].js',
    },
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 1024 * 3 // When the image size is < 3kb it will be converted to base64
                    }
                },
                generator: {
                    filename: '[name]-[contenthash:5][ext][query]' // Set the name of the output file
                }
            },
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: path.resolve(__dirname, './dist/[name].html'),
            template: path.resolve(__dirname, './src/index.html'),
            title: 'webpack.dev.config',
        })
    ],
+   devServer: {
+       static: {
+           directory: path.join(__dirname, 'static'),
+       },
+   }
}
Enter fullscreen mode Exit fullscreen mode

devServer

Remember our previous case, how we ran our code? We ran it with our own editor (vscode) to see the results after we had packaged it. If we were that inefficient, we wouldn't be able to go live with our project.

That's why webpack provides a very user-friendly configuration item called devServer.

To use it, we need to install the webpack-dev-server dependency npm i webpack-dev-server -D.

From such a semantic name, we know that it must be a configuration that provides some kind of service in the development environment.

The service is that this will enable a local service that will compile our configured webpack, in real time, and save it in memory, so that we can easily debug our code, which serves the purpose of our local development needs to be efficient very well.

So this configuration item, only used for our development environment configuration.

devServer.static

Documentation Explanation: tells the server where to serve content from. This is only necessary if you wish to serve static files

Misinterpretation

The devServe configuration item is actually written in quite a bit of detail in the documentation, so here's a potentially confusing one - devServe.static.

A lot of people use webpack and copy and paste, so it's common to see configurations like the following:

output: {
    path: path.resolve(__dirname, '. /dist'), .
}
devServer: {
    static: {
      directory: path.join(__dirname, 'dist'), }
    }
}
Enter fullscreen mode Exit fullscreen mode

Because the folder we set up for output after packaging is generally dist, the devServe.static configuration item specifies that the directory of static files to be served is also dist. So, we would naturally assume that the contents of the local server access opened by webpack at this point would be the contents inside the dist folder.

Therefore, we would incorrectly conclude that devServe.static serves to set the directory that is accessed by the local server when webpack is turned on.

However, we can look at dev.config.js above, where we set the name of the folder we output after packaging to dist, and the directory set by devServe.static is static. If we follow our misinterpretation above, we should have a 404 or a blank page on our server at this point due to the difference in the two folder settings, but we can still run our service.

This means that devServe.static is not setting the directory where the packaged output folder is accessed when webpack is turned on for the local server.

Correctly understood

Analysis

Let's move on to the learn-08 case (the static folder holds the logo.png image inside).

We previously wanted to reference the image in question inside js, which we typically do:

// index.js
const img = new Image();
img.src = require('Your image path');
Enter fullscreen mode Exit fullscreen mode

We normally require the image according to the relative path, which is equivalent to a module, so the image will be compiled by webpack (adding hash or converting it to base64), and then written to the final directory (output.path) that we have set up.

But when we set up:

devServer: {
    static: {
      directory: path.join(__dirname, 'static'),
    }
}
Enter fullscreen mode Exit fullscreen mode

After opening the local server, this line prompts:

Content not from webpack is served from 'your path/static' directory

First of all, this means that the static directory we set up will not be processed and packaged by webpack, so the resources in this folder will not be parsed and compiled by webpack, and therefore it will not be hashed or converted to base64.

Let's take a look at how index.js from learn-08 uses the resources in static:

// index.js
loadImage('./logo.png').then(img => {
    console.log('I am from index.js');
    img.width = 120;
    document.querySelector('#js_content .img_content').append(img);
});
Enter fullscreen mode Exit fullscreen mode

We will see that we are introducing the image directly using the ./ way to bring in the image, indicating that webpack has a local server turned on that will map the contents of the static directory we set up to the root directory.

If you've used vue-cli before, you'll appreciate that this is what the public folder in vue-cli does.

We can access the contents of the set devServer.static.directory folder in the following way:

  • Normally devServer.static.directory is mapped to the root directory, so we access it using http://[devServer.host]:[devServer.port]/[devServer.static.directory]
  • If you want to change the access path, you can add devServer.static.publicPath configuration. In this case, you can use http://[devServer.host]:[devServer.port]/[devServer.static.publicPath]/[devServer.static.directory] for accessing

Summary

After analyzing the explanation above, we can conclude that the correct understanding of devServer.static should be:

  • It is a directory for static resources that are not compiled by webpack (e.g., images, third-party resources, etc.), so it won't be hashed or base64; it is a directory.
  • When opening a webpack local server, it is usually mapped to the root directory of our project (you can change the access directory via devServe.static.publicPath)
  • Since it's not compiled and packaged by webpack, we usually end up copying devServer.static.directory to the root of output.path with copy-webpack-plugin
  • It functions much like the public folder inside vue-cli, which we can use when we develop via ./ or ../ to access that resource (depending on the directory relationship).

Core

Okay, so we know from the above explanation of the development environment configuration and devServer:

  • The development environment configuration is kept simple, so resources such as img, js, etc. are mapped directly to the root directory (css is inserted into <head />).
  • The development environment webpack also maps devServer.static.directory to the root directory when the local server is enabled.

So after running the development environment configuration, our structure directory is roughly as follows:

dist
├── ecj-cli-b6fa8.png
├── index-c466b.js
├── index.html
└── logo.png
Enter fullscreen mode Exit fullscreen mode

Configuration varies from person to person, the most important thing is that after we configure the development environment, production environment, the compilation and packaging of output content, directory, a good understanding of the structure of the mind, which is very important.

It is very important that we have a good understanding of the directory structure of the compiled and packaged output, which is very important.

We can see the structure of the development environment by the following method:

  • devServer.devMiddleware.writeToDisk: true
  • http://[devServer.host]:[devServer.port]/webpack-dev-server
  • Chrome F12 -> Sources

Finally

  • This article learned how to configure the development environment, the next article will explain the configuration of the production environment before some of the preparations, so that we can better learn the production environment configuration
  • The cases covered in the article have been uploaded to github, and you are really welcome to star or fork them.
  • You can support me by following my github!

Regarding the content of the article, if you have similarities and differences, feel free to discuss them in the comments section!

Top comments (1)

Collapse
 
limingcan562 profile image
Lee

I hope this article is helpful for you to learn webpack, if there are differences and similarities, welcome to discuss with me in the comments section!