webpack的学习(基础部分)

151 阅读9分钟

一、webpack 简介

1、webpack 是什么

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。

在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。

它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

2、webpack 的五个核心概念

  • Entry入口(Entry)指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。
  • Output输出(Output)指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。
  • LoaderLoader让webpack能够去处理那些非JavaScript文件(webpack自身只理解JavaScript)。
  • Plugins插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等
  • Mode模式(Mode)指示 webpack 使用相应模式的配置
选项描述特点
development会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development。启用 NamedChunksPlugin 和NamedModulesPlugin。能让代码本地调试运行的环境
production会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。启用 FlagDependencyUsagePlugin,FlagIncludedChunksPlugin, ModuleConcatenationPlugin,NoEmitOnErrorsPlugin, OccurrenceOrderPlugin,SideEffectsFlagPlugin 和 TerserPlugin。能让代码优化上线运行的环境

二、webpack 的初体验

1、初始化配置

  1. 初始化 package.json
npm init
  1. 下载并安装 webpack
npm install webpack webpack-cli -g
npm install webpack webpack-cli -D

2、编译打包应用

  1. 创建文件
  2. 运行指令
  • 开发环境指令:webpack src/js/index.js -o build/js/built.js --mode=development
  • 功能:webpack 能够编译打包 js 和 json 文件,并且能将 es6 的模块化语法转换成浏览器能识别的语法。
  • 生产环境指令:webpack src/js/index.js -o build/js/built.js --mode=production
  • 功能:在开发配置功能上多一个功能,压缩代码。
  1. 结论
  • webpack 能够编译打包 js 和 json 文件。
  • 能将 es6 的模块化语法转换成浏览器能识别的语法。
  • 能压缩代码。
  1. 问题
  • 不能编译打包 css、img 等文件。
  • 不能将 js 的 es6 基本语法转化为 es5 以下语法。

三、webpack 开发环境的基本配置

1、创建配置文件

  1. 创建文件 webpack.config.js
  2. 配置内容如下
const { resolve } = require('path'); // node 内置核心模块,用来处理路径问题。
module.exports = {
    entry: './src/js/index.js', // 入口文件
    output: { // 输出配置
        filename: './built.js', // 输出文件名
        path: resolve(__dirname, 'build/js') // 输出文件路径配置
    },
    mode: 'development'  //开发环境
};
  1. 运行指令: webpack
  2. 结论: 此时功能与上节一致

2、打包样式资源

下载安装 loader 包

npm i css-loader style-loader less-loader less -D

修改配置文件

/*
  webpack.config.js  webpack的配置文件
    作用: 指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置)
    所有构建工具都是基于nodejs平台运行的~模块化默认采用commonjs。
*/

// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
module.exports = {
    // webpack配置
    // 入口起点
    entry: './src/index.js',
    // 输出
    output: {
        filename: 'static/js/built.js', // 输出文件名
        // __dirname nodejs的变量,代表当前文件的目录绝对路径
        path: resolve(__dirname, 'build'), // 输出路径
    },
    // loader的配置
    module: {
        rules: [
          // 详细loader配置
          // 不同文件必须配置不同loader处理
          {
            // 匹配哪些文件
            test: /\.css$/,
            // 使用哪些loader进行处理
            use: [
              // use数组中loader执行顺序:从右到左,从下到上 依次执行
              // 创建style标签,将js中的样式资源插入进行,添加到head中生效
              'style-loader',
              // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
              'css-loader',
            ],
          },
          {
            test: /\.less$/,
            use: [
              'style-loader',
              'css-loader',
              // 将less文件编译成css文件
              // 需要下载 less-loader和less
              'less-loader',
            ],
          },
        ],
    },
    // plugins 的配置
    plugins: [
        // 详细 plugins 的配置
    ],
    mode: 'development'  //开发环境
};

运行指令: webpack

3、打包HTML资源

下载安装 plugin 包

npm install --save-dev html-webpack-plugin

修改配置文件

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'static/js/built.js',
    path: resolve(__dirname, 'build'),
  },
  module: {
    rules: [
      // loader的配置
    ]
  },
  plugins: [
    // plugins的配置
    // html-webpack-plugin
    // 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
    // 需求:需要有结构的HTML文件
    new HtmlWebpackPlugin({
      // 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

运行指令: webpack

4、打包图片资源

下载安装 loader 包

npm install --save-dev html-loader url-loader file-loader

修改配置文件

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'static/js/built.js',
    path: resolve(__dirname, 'build'),
  },
  module: {
    rules: [
      {
        test: /\.less$/,
        // 要使用多个loader处理用use
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        // 问题:默认处理不了html中img图片
        // 处理图片资源
        test: /\.(jpg|png|gif)$/,
        // 使用一个loader
        // 下载 url-loader file-loader
        loader: 'url-loader',
        options: {
          // 图片大小小于8kb,就会被base64处理
          // 优点: 减少请求数量(减轻服务器压力)
          // 缺点:图片体积会更大(文件请求速度更慢)
          limit: 8 * 1024,
          // 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
          // 解析时会出问题:[object Module]
          // 解决:关闭url-loader的es6模块化,使用commonjs解析
          esModule: false,
          // 给图片进行重命名
          // [hash:10]取图片的hash的前10位
          // [ext]取文件原来扩展名
          name: 'static/images/[hash:10].[ext][query]'
        }
      },
      {
        test: /\.html$/,
        // 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
        loader: 'html-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

运行指令: webpack

5、打包其他资源

修改配置文件

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'static/js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      // 打包其他资源(除了html/js/css资源以外的资源)
      {
        // 排除css/js/html资源
        exclude: /\.(css|js|html|less)$/,
        loader: 'file-loader',
        options: {
          name: 'static/images/[hash:10].[ext][query]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

运行指令: webpack

6、处理JS资源

  • 针对兼容性处理,我们使用Babel来完成。
  • 针对代码格式,我们使用ESlint来完成。 我们先完成ESlint,检测代码格式无误后,再由Babel做代码兼容性处理。

Eslint

可组装的JS和JSX检查工具。我们使用ESlint,关键是ESlint的配置文件,里面写上各种rules规则,将来运行ESlint时就会以写的规则来检查代码。

1、配置文件

配置文件由很多种写法:

  • .eslintrc.* :新建文件,位于项目根目录; .eslintrc; .eslintrc.js; .eslintrc.json 区别在于配置格式不一样
  • package.json中eslintConfig:不需要创建文件,在原有文件基础上写
  • ESLint会查找和自动读取它们,所以以上配置文件只需要存在一个即可
2、具体配置
module.exports ={ 
    // 解析选项
    parserOptions: {}, 
    // 具体检查规则 rules: {},
    // 继承其他规则
    extends:[], 
    // .….
    // 其他规则详见:https://eslint.bootcss.com/docs/user-guide/configuring
}; 
  • parserOptions解析选项
parserOptions: {
    ecmavVersion: 6, // ES版本
    sourceType: "module", // ES模块化
    ecmaFeatures: { // ES其他特性
        jsx: true // 如果是REACT项目,就需要开启JSX语法
    }
}
  • rules具体规则
    • "off"或e-关闭规则
    • "warn"或1-开启规则,使用警告级别的错误:warn(不会导致程序退出)
    • "error”或 2-开启规则,使用错误级别的错误: error(当被触发的时候,程序会退出)
rules:{ 
    semi: "error",
    //止使用分号 
    'array-callback-return': 'warn',
    //强制数组方法的回调函数中有 return 语句,否则警告 
    'default-case': [
        'warn',
        // 要求 switch 语句中有 default 分支,否则警告 
        {commentPattern: '^no default$'} // 允许在最后注释 no default,就不会有警告了 
    ],
    eqeqeq:[ 
        'warn',
        // 强制使用 === 和 !==,否则警告 
        'smart'
        // https://eslint.bootcss.com/docs/rules/egegeq#smart 除了少数情况下不会有警告
     ], 
}
  • extends继承 1658733882158.png
3、在webpack中的使用
  • 下载包
npm i eslint-webpack-plugin eslint -D
  • 定义ESlint配置文件
// .eslintrc.js
module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: [
    'plugin:vue/essential',
    '@vue/airbnb',
  ],
  parserOptions: {
    parser: 'babel-eslint',
    ecmaVersion: 2020
  },
  globals: {
    THING: false,
    CMAP: false,
    uino: false,
    spray: false,
    horizion: false,
  },
  rules: {
    "vue/order-in-components": [
      "error",
      {
        "order": [
          "el",
          "name",
          ["components", "directives", "filters"],
          "extends",
          "mixins",
          "props",
          "data",
          "computed",
          "watch",
          "beforeCreate",
          "created",
          "beforeMount",
          "mounted",
          "beforeUpdate",
          "updated",
          "activated",
          "deactivated",
          "beforeDestroy",
          "destroyed",
          "methods",
        ]
      }
    ],
    // 强制 error
    indent: ['error', 4],
    'vue/html-indent': ['error', 4],
    // 'no-console': process.env.NODE_ENV === 'production' ? ["error", { allow: ["warn", "error"] }] : 'off',
    'no-console': 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    // 推荐 warn
    'max-len': ['error', { 'code': 180 }],
    'vue/html-quotes': 'warn',
    'no-param-reassign': ['error', { 'props': false }],
    'camelcase': 0,
    'no-mixed-operators': 'off',
    'no-bitwise': 'off',
    'no-unused-expressions': ['error', { 'allowShortCircuit': true }],
    'no-restricted-globals': 'off',
    'class-methods-use-this': 'off',
  },
  overrides: [
    {
      files: [
        '**/__tests__/*.{j,t}s?(x)',
        '**/tests/unit/**/*.spec.{j,t}s?(x)',
      ],
      env: {
        mocha: true,
      },
    },
  ],
};
  • 修改配置文件
const { resolve } = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');

module.exports = {
  // 入口起点
  entry: './src/js/index.js',
  // 输出
  output: {
    filename: 'static/js/built.js', // 输出文件名
    path: resolve(__dirname, 'build') // 输出路径,__dirname nodejs的变量,代表当前文件的目录绝对路径
    clean: true, // 自动清空上次打包的内容
    // 原理:在打包前,将path整个目录清空,再进行打包。
  },
  // loader的配置
  module: {
    rules: []
  },
  // plugins的配置
  plugins: [
    new ESLintPlugin({
        // 检测那些文件
        context: path.resolve(_dirname, "src"),
    }}
  ],
  // 开发模式
  mode: 'development',
};

Babel

JavaScript编译器。 主要用于将ES6语法编写的代码转换为向后兼容的JavaScript语法,以便能够运行在当前和旧版本的浏览 器或其他环境中

1、配置文件

配置文件由很多种写法:

  • bel.config.*:新建文件,位于项目根目录
    • bel.config.js
    • babel.config.json
  • abelrc.* :新建文件,位于项目根目录
    • .belrc
    • .babelrc.js
    • abelrc.json
  • ckage.json中babel:不需要创建文件,在原有文件基础上写

Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可

2、具体配置
// 以babelconfigjs 配置文件为例:
module.exports ={
    // 预设 
    presets: [], 
}; 
  • presets 预设
  • 简单理解:就是一组 Babel 插件 展Babel 功能
    • @babel/preset-env:一个智能预设,允许您使用最新的JavaScript。
    • @babel/preset-react:一个用来编译Reactjsx语法的预设
    • @babel/preset-typescript:一个用来编译TypeScript语法的预设
3、在webpack中使用
  • 下载包
npm i babel-loader @babel/core @babel/preset-env-D
  • 定义 Babel 配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'static/js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.js, // 匹配哪些文件
        exclude: /node_modules/, // 排除node_modules的JS文件不处理
        loader: 'babel-loader",
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

7、devserver

修改配置文件

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'static/js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      // 打包其他资源(除了html/js/css资源以外的资源)
      {
        // 排除css/js/html资源
        exclude: /\.(css|js|html|less)$/,
        loader: 'file-loader',
        options: {
          name: 'static/images/[hash:10].[ext][query]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',

  // 开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
  // 特点:只会在内存中编译打包,不会有任何输出
  // 启动devServer指令为:npx webpack-dev-server
  devServer: {
    // 项目构建后路径
    contentBase: resolve(__dirname, 'build'),
    // 启动gzip压缩
    compress: true,
    // 端口号
    port: 3000,
    // 自动打开浏览器
    open: true
  }
};

运行指令: npx webpack-dev-server

8、开发环境配置

修改配置文件

/*
  开发环境配置:能让代码运行
    运行项目指令:
      webpack 会将打包结果输出出去
      npx webpack-dev-server 只会在内存中编译打包,没有输出
*/

// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');

module.exports = {
  // webpack配置
  // 入口起点
  entry: './src/js/index.js',
  // 输出
  output: {
    filename: 'static/js/built.js', // 输出文件名
    path: resolve(__dirname, 'build') // 输出路径,__dirname nodejs的变量,代表当前文件的目录绝对路径
    clean: true, // 自动清空上次打包的内容
    // 原理:在打包前,将path整个目录清空,再进行打包。
  },
  
  // loader的配置
  module: {
    rules: [
      // 详细loader配置
      // 不同文件必须配置不同loader处理
      {
        // 处理less资源
        test: /\.less$/, // 匹配哪些文件
        // 将less文件编译成css文件
        // 需要下载 less-loader和less
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        // 处理css资源
        test: /\.css$/, // 匹配哪些文件
        // use数组中loader执行顺序:从右到左,从下到上 依次执行
        // 创建style标签,将js中的样式资源插入进行,添加到head中生效
        // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
        use: ['style-loader', 'css-loader']
      },
      {
        // 处理图片资源
        test: /\.(jpg|png|gif)$/, // 匹配哪些文件
        // 使用一个loader
        // 下载 url-loader file-loader
        loader: 'url-loader',
        options: {
          // 图片大小小于8kb,就会被base64处理
          // 优点: 减少请求数量(减轻服务器压力)
          // 缺点:图片体积会更大(文件请求速度更慢)
          limit: 8 * 1024,
          // 给图片进行重命名
          // [hash:10]取图片的hash的前10位
          // [ext]取文件原来扩展名
          name: 'static/images/[hash:10].[ext][query]',
          // 关闭es6模块化
          // 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
          // 解析时会出问题:[object Module]
          // 解决:关闭url-loader的es6模块化,使用commonjs解析
          esModule: false,
          outputPath: 'imgs'
        }
      },
      {
        // 处理html中img资源
        test: /\.html$/, // 匹配哪些文件
        loader: 'html-loader'
      },
      {
       // 排除css/js/html资源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: 'static/images/[hash:10].[ext][query]',
          outputPath: 'media'
        }
      }
    ]
  },
  
  // plugins的配置
  plugins: [
    // html-webpack-plugin
    // 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
    // 需求:需要有结构的HTML文件
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new ESLintPlugin({ // 检测那些文件 context: path.resolve(_dirname, "src"), }}
  ],
  
  // 开发模式
  mode: 'development',
  
  // 开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
  // 特点:只会在内存中编译打包,不会有任何输出
  // 启动devServer指令为:npx webpack-dev-server
  devServer: {
    // 项目构建后路径
    contentBase: resolve(__dirname, 'build'),
    // 启动gzip压缩
    compress: true,
    // 端口号
    port: 3000,
    // 自动打开浏览器
    open: true
  }
};

运行指令: npx webpack-dev-server

四、webpack 生产环境的基本配置

1、提取 css 成单独文件

CSS文件目前被打包到JS文件中,当JS文件加载时,会创建一个style标签来生成样式,这样对于网站来说,会出现闪屏现象,用户体验不好。我们应该是单独的CSS文件通过link标签加载性能才会好一些。

a、安装插件

npm install --save-dev mini-css-extract-plugin

b、修改配置文件

// webpack.prod.js

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            {
            test: /\.css$/,
            use: [
                // 创建 style 标签,将样式放入
                // 'style-loader',
                // 这个 loader 取代 style-loader。作用:提取 js 中的 css 成单独文件
                MiniCssExtractPlugin.loader,
                // 将 css 文件整合到 js 文件中
                'css-loader'
            ]
        }
       ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new MiniCssExtractPlugin({
            // 对输出的 css 文件进行重命名
            filename: 'css/built.css'
        })
    ],
    mode: 'development'
};

2、css 兼容性处理

a、安装插件

npm install --save-dev postcss-loader postcss-preset-env

b、修改配置文件

// webpack.prod.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 设置 nodejs 环境变量
// process.env.NODE_ENV = 'development';

// 用来获取处理样式得loader
function getStyleLoader(pre){
    return [
            MiniCssExtractPlugin.loader,
            'css-loader',
            {
                loader: 'postcss-loader',
                options: {
                    ident: 'postcss',
                    plugins: () => [
                        // postcss 的插件
                        require('postcss-preset-env')()
                    ]
                }
            },
            pre,
        ].filter(Boolean);
}

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            // 注意顺序
            {
                test: /\.css$/,
                use: getStyleLoader()
            },
            {
                test: /\.less$/,
                use: getStyleLoader("less-loader")
            },
            {
                test: /\.s[ac]ss$/,
                use: getStyleLoader("sass-loader")
            },
            {
                test: /\.styl$/,
                use: getStyleLoader("stylus-loader")
            },
    ]
},
plugins: [
    new HtmlWebpackPlugin({
        template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
        filename: 'css/built.css'
    })
],
mode: 'development'
};
// package.json

"browserslist": {
    "development": [
        "last 2 chrome version",  // 所有的chrome版本
        "last 1 firefox version",
        "last 1 safari version"
    ],
    "production": [
        ">0.2%",
        "not dead", // 去除死掉的版本
        "not op_mini all"
    ]
}

3、压缩 css

a、安装插件

npm install --save-dev optimize-css-assets-webpack-plugin

b、修改配置文件

// webpack.prod.js   
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

// 设置 nodejs 环境变量
// process.env.NODE_ENV = 'development';

// 用来获取处理样式得loader
function getStyleLoader(pre){
    return [
            MiniCssExtractPlugin.loader,
            'css-loader',
            {
                loader: 'postcss-loader',
                options: {
                    ident: 'postcss',
                    plugins: () => [
                        // postcss 的插件
                        require('postcss-preset-env')()
                    ]
                }
            },
            pre,
        ].filter(Boolean);
}

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            // 注意顺序
            {
                test: /\.css$/,
                use: getStyleLoader()
            },
            {
                test: /\.less$/,
                use: getStyleLoader("less-loader")
            },
            {
                test: /\.s[ac]ss$/,
                use: getStyleLoader("sass-loader")
            },
            {
                test: /\.styl$/,
                use: getStyleLoader("stylus-loader")
            },
    ]
},
plugins: [
    new HtmlWebpackPlugin({
        template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
        filename: 'css/built.css'
    }),
    new CssMinimizerPlugin(),
],
mode: 'development'
};

4、js 压缩

生产环境下会自动压缩 js 代码

mode: 'production'

5、HTML 压缩

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

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            // 压缩 html 代码
            minify: {
                // 移除空格
                collapseWhitespace: true,
                // 移除注释
                removeComments: true
            }
        })
    ],
    mode: 'production'
};

6、生产环境配置

const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

// 定义 nodejs 环境变量:决定使用 browserslist 的哪个环境
process.env.NODE_ENV = 'production';

// 复用 loader
const commonCssLoader = [
    MiniCssExtractPlugin.loader,
    'css-loader',
    {
        // 还需要在 package.json 中定义 browserslist
        loader: 'postcss-loader',
        options: {
            ident: 'postcss',
            plugins: () => [require('postcss-preset-env')()]
        }
    }
];

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [...commonCssLoader]
            },
            {
                test: /\.less$/,
                use: [...commonCssLoader, 'less-loader']
            },
            /*
                正常来讲,一个文件只能被一个 loader 处理。
                当一个文件要被多个 loader 处理,那么一定要指定 loader 执行的先后顺序:
                先执行 eslint 在执行 babel
            */
            {
                // 在 package.json 中 eslintConfig --> airbnb
                test: /\.js$/,
                exclude: /node_modules/,
                // 优先执行
                enforce: 'pre',
                loader: 'eslint-loader',
                options: {
                    fix: true
                }
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                useBuiltIns: 'usage',
                                corejs: {version: 3},
                                targets: {
                                    chrome: '60',
                                    firefox: '50'
                                }
                            }
                         ]
                    ]
                }
            },
            {
                test: /\.(jpg|png|gif)/,
                loader: 'url-loader',
                options: {
                    limit: 8 * 1024,
                    name: '[hash:10].[ext]',
                    outputPath: 'imgs',
                    esModule: false
                }
            },
            {
                test: /\.html$/,
                loader: 'html-loader'
            },
            {
                exclude: /\.(js|css|less|html|jpg|png|gif)/,
                loader: 'file-loader',
                options: {
                    outputPath: 'media'
                }
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'css/built.css'
        }),
        new OptimizeCssAssetsWebpackPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                collapseWhitespace: true,
                removeComments: true
            }
        })
    ],

    mode: 'production'
}