This is the third day of my participation in the More text Challenge. For details, see more text Challenge

Multiple environment configurations

Sometimes in a project, we do not have only one environment, may be divided into several environments, such as: development environment, production environment. At this point, it would be unreasonable to combine the configuration of the development environment with the configuration of the production environment.

Webpack-merge: separate configuration files

At this point, we can use the Webpack-merge plug-in

npm i -D webpack-merge
Copy the code

We create two more configuration files in the Build directory, webpack.dev.js (development environment configuration) and webpack.prod.js (production environment configuration).

The production environment does not need to use Webpack-dev-server, but the development environment does.

Let’s comment out or delete the devServer from webpack.config.js.

Then write the following code in webpack.dev.js

const { merge } = require('webpack-merge');
const common = require('./webpack.config.js');

module.exports = merge(common, {
  devServer: {
    port: 3000.hot: true.contentBase: path.resolve(__dirname, '.. /dist')}})Copy the code

Webpack.prod.js writes these lines

const { merge } = require('webpack-merge');
const common = require('./webpack.config.js');

module.exports = merge(common, {
  
})
Copy the code

The purpose of the merge is to add additional configuration to a common configuration file, in this case webpack.config.js.

Let’s change the package.json dev command to point to webpack.dev.js; Also point the configuration of the build command to webpack.prod.js by the way.

"scripts": {
    "dev": "webpack server --config build/webpack.dev.js"."build": "webpack --config ./build/webpack.prod.js". }Copy the code

In this way, our environment configuration is separated, running dev is the development environment, and running Build is the production environment. But is the environment really that simple to distinguish? We also need to note that WebPack has a concept of environment mode, and we need to set the mode.

Environment mode Mode

Webpack’s mode provides three values: None, development, and Production.

Since we haven’t defined a mode for WebPack, the above commands run in production mode.

If mode is not defined, a warning will be thrown when the project is compiled.

Different modes have different functions, which are as follows (official document extract) :

options describe
development The value of process.env.node_env in DefinePlugin is set to development. Enable valid names for modules and chunks.
production The value of process.env.node_env in DefinePlugin is set to production. For the module and the chunk enable deterministic confusing name, FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin and TerserPlugin.
none Do not use any default tuning options

As you can see, production mode has more plugins enabled than development mode. In this case, you can simply assume that production mode automatically compresses and obviates code for you.

The method for setting mode is as follows.

Setting mode Method 1: Webpack configuration

Write directly in the WebPack configuration file.

webpack.dev.js

module.exports = merge(common, {
    mode: 'development'. })Copy the code

For webpack.prod.js, write production.

Setting mode Method 2: Using script commands

Add –mode XXXX to the package.json script command as follows:

"dev": "webpack server --config build/webpack.dev.js --mode development"."build": "webpack --config ./build/webpack.prod.js --mode production"
Copy the code

Environment variable NODE_ENV

Process.env. NODE_ENV is an environment variable of node. In a program, we should use NODE_ENV as a basis to determine what kind of environment we are in. Notice the difference between environment mode, which is for WebPack, and environment variables, which are for programs.

Change NODE_ENV indirectly using mode

As mentioned in the previous section, setting mode will change process.env.node_env. Let’s test whether this changes.

After adding –mode development to the dev command, add the following code to webpack.config.js and SRC /js/index.js respectively.

Console. log(' environment variables: ', process.env.node_env)Copy the code

NPM run dev webpack.config.js output undefined.

In the index.html console, the output is Development.

In index.js, the environment variable is indeed assigned a development value, but not in the WebPack configuration file.

If we look at the document more closely, it says:

The value of process.env.node_env in DefinePlugin is set to developmentCopy the code

Here said the process. The env. NODE_ENV is DefinePlugin inside, no indication is the process of the node. The env. NODE_ENV, don’t the two equal?

Let’s look at another way to change NODE_ENV with a problem in mind.

Change NODE_ENV directly from the command line

On the Windows command line, we can set environment variables by using set, for example:

"dev": "set NODE_ENV=development && webpack server --config build/webpack.dev.js"
Copy the code

On the Linux command line, we can set environment variables using export, for example:

"dev": "export NODE_ENV=development && webpack server --config build/webpack.dev.js"
Copy the code

Cross-env is a recommended tool, which is compatible with multiple systems and can be used with the cross-env command.

npm i -D cross-env
Copy the code

The command reads.

"scripts": {
    "dev": "cross-env NODE_ENV=development webpack server --config build/webpack.dev.js"."build": "cross-env NODE_ENV=production webpack --config ./build/webpack.prod.js". }Copy the code

Note: There is no && connection between cross-env and Webpack.

After running the NPM run dev command, you can see that the Webpack configuration file and index.js output environment variable: development.

Let’s change the NODE_ENV of the dev command to production, so that the output source of “environment variable: production” is main.xxx.js, not index.js.

This means that changing NODE_ENV directly from the command line will also cause webPack mode changes, as mentioned in the official documentation.

thinking

So let’s analyze that.

  1. The environment mode mode can change the environment variable NODE_ENV. NODE_ENV can be obtained in the runtime environment, but cannot be obtained in the Webpack configuration.
  2. Setting the environment variable NODE_ENV on the command line can also change the environment mode. NODE_ENV can be obtained from both the runtime environment and webpack configuration.
  3. DefinePlugin is a plugin that defines global constants at webPack compile time.
  4. Mode defines the global constant NODE_ENV using DefinePlugin.

So, this is how I understand it.

Mode changes to NODE_ENV occur at webpack compile time, so DefinePlugin doesn’t start working until the Webpack configuration is loaded. Until then NODE_ENV has been undefined. After loading the Webpack configuration, DefinePlugin does its work and NODE_ENV is assigned. DefinePlugin’s NODE_ENV and node’s NODE_ENV should be the same concept.

By using the command line, NODE_ENV is assigned before webpack is compiled, so NODE_ENV can be read by the Webpack configuration file.

Another configuration mode method

In addition to using webpack-merge to separate configuration files and write different mode in different configuration files, we seem to have found another way to configure mode. We can use NODE_ENV to determine which mode to use. For example:

Webpack configuration file

const isProMode = process.env.NODE_ENV === "production"
module.exports = {
    mode: isProMode ? 'production' : 'development'.// Change mode according to NODE_ENV. }Copy the code

supplement

Priority for mode. Mode > Mode > NODE_ENV in the webpack configuration command line change mode

NODE_ENV priority for the runtime environment. Change mode on the cli NODE_ENV > Change mode on the webpack configuration NODE_ENV > change mode on the cli NODE_ENV

For NODE_ENV in the Webpack configuration file, only the command line NODE_ENV can be assigned.

It is not recommended to use the –mode and cross-env commands together to avoid confusion.

The complete code

directory

webpack.config.js

const path = require('path')

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

console.log('Environment variables:', process.env.NODE_ENV)

module.exports = {
  // entry: path.resolve(__dirname, '.. /src/js/index.js'),
  entry: {
    main: path.resolve(__dirname, '.. /src/js/index.js'),
    header: path.resolve(__dirname, '.. /src/js/header.js'),
    footer: path.resolve(__dirname, '.. /src/js/footer.js'),},output: {
    // filename: 'main.js',
    filename: '[name].[fullhash].js'.path: path.resolve(__dirname, '.. /dist')},// devServer: {
  // port: 3000,
  // hot: true,
  // contentBase: '.. /dist'
  // },
  plugins: [
    // new HtmlWebpackPlugin({
    //   title: '首页'
    // }),
    // Configure multiple htmlWebPackPlugins for as many pages as possible
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '.. /src/html/index.html'),
      filename: 'index.html'.chunks: ['main'] // The module name corresponding to the entry file (entry configuration), which can be understood here as importing main.js
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '.. /src/html/header.html'),
      filename: 'header.html'.chunks: ['header']}),new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '.. /src/html/footer.html'),
      filename: 'footer.html'.chunks: ['footer']}),new CleanWebpackPlugin(),
  ]
}
Copy the code

webpack.dev.js

const path = require('path')

const { merge } = require('webpack-merge');
const common = require('./webpack.config.js');

module.exports = merge(common, {
  mode: 'development'.devServer: {
    port: 3000.hot: true.contentBase: path.resolve(__dirname, '.. /dist')}})Copy the code

webpack.prod.js

const { merge } = require('webpack-merge');
const common = require('./webpack.config.js');

module.exports = merge(common, {
  mode: 'production',})Copy the code

package.json

{
  "name": "test"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "dev": "webpack server --config build/webpack.dev.js"."build": "webpack --config ./build/webpack.prod.js"."test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": ""."license": "ISC"."devDependencies": {
    "clean-webpack-plugin": "^ 4.0.0 - alpha."."cross-env": "^ 7.0.3." "."html-webpack-plugin": "^ 5.3.1"."webpack": "^ 5.38.1"."webpack-cli": "^ 4.7.0"."webpack-dev-server": "^ 3.11.2"."webpack-merge": "^ 5.7.3." "}}Copy the code

series

Using WebPack5 (0) : Concepts Using WebPack5 (1) : Starting Using WebPack5 (2) : Configuring Multiple environments Using WebPack5 (3) : Loading the CSS Using WebPack5 (4) : Load resource file Webpack5 use (5) : Babel translation JS code use (6) : optimization