# webpack常用配置解析

Webpack可以看做是模块打包机:它做的事情是,分析你的项⽬结构,找到JavaScript模块以及其它的⼀些浏览器不能直接运⾏的拓展语⾔(less,sass,typeScript等),并将其打包为合适的格式以供浏览器使⽤。

# 安装

npm install webpack --save-dev // 不建议全局安装
webpack -v // 查看版本 确定安装成功

# 基本配置

打包默认配置文件是 webpack.config.js

npx webpack //执⾏命令后,webpack会找到默认的配置⽂件,并使⽤执⾏

不使用默认配置文件:webpackconfig.js

npx webpack --config webpackconfig.js //指定webpackconfig.js⽂件来作为配置⽂件并执⾏

修改 package.json scripts 字段, 使用 npm run build 方式执行打包

package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "npx webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
npm run build

webpack.config.js 配置结构

module.exports = {
    entry: './src/index.js', // 入口文件
    output: './dist', // 输出位置
    mode: 'none', // 打包环境 production development none
    module: {
        rules: [
            //loader模块处理
            {
                test: /\.css$/,
                use: "style-loader"
            }
        ]
    },
    plugins: [] //插件配置
}

# 常用loader

webpack 处理到不认识的模块时,需要在 webpack 中的 module 处进⾏配置,当检测到是什么格式的模块,使⽤什么 loader 来处理。

  • style-loader // 处理样式
  • css-loader // 处理css
  • less-loader // 处理less
  • sass-loader // 处理sass
  • ts-loader //将Ts转换成js
  • babel-loader//转换ES6、7等js新特性语法
  • file-loader//处理图⽚⼦图等静态资源模块

# 样式处理 css-loader,style-loader,less-loader

css-loader:分析 css 模块之间的关系,并合成⼀个 css style-loader:style-loader 会把 css-loader ⽣成的内容,以 style 挂载到⻚⾯的head部分,(文件里面看不到,浏览器才能看到,放到了 index.js 等执行完head 才有) less-loader:webpackLess 编译为 CSSloader。 post-loader:预处理cssloader autoprefixer:样式⾃动添加前缀

const htmlWebpackPlugin = require("html-webpack-plugin"); // 通过 npm 安装
const path = require('path');
module.exports = {
    entry: './src/index.js', // 入口文件
    output: {
        filename: 'index.js',
        path: path.resolve(__dirname, './dist')
    },
    mode: 'development', // 打包环境 production development none
    module: {
        rules: [
            {
                test: /\.less$/, // 处理less文件 并插入到head
                use: ["style-loader", "css-loader", "less-loader"]
            },
            {
                test: /\.sass$/, // 处理sass文件 并插入到head
                use: ["style-loader", "css-loader", "sass-loader"]
            }
        ]
    },
    plugins: [
        // 以模版自动生成HTML 且生成的js会自动引入
        new htmlWebpackPlugin({
            title: 'webpack demo',
            template: path.join(__dirname, './src/index.html'),
            filename:'index.html'   //指定生成的页面名称
        })
    ] //插件配置
}

# 文件处理

file-loader:处理静态资源模块,把打包⼊⼝中识别出的资源模块,移动到输出⽬录,并且返回⼀个地址名称

module: {
    rules: [
        {
            test: /\.(png|jpe?g|gif)$/,
            use: {
                loader: "file-loader",
                // options额外的配置,⽐如资源名称
                options: {
                    name: "[name]_[hash].[ext]",
                    //打包后的存放位置
                    outputPath: "images/"
                }
            }
        }
    ]
}

url-loader:file-loader加强版本,不同的是会把 <limit 限制的图⽚转换成base64格式字符串并打包到js⾥。

module: {
    rules: [
        {
            test: /\.(png|jpe?g|gif)$/,
            use: {
                loader: "url-loader",
                // options额外的配置,⽐如资源名称
                options: {
                    name: "[name]_[hash].[ext]",
                    //打包后的存放位置
                    outputPath: "images/",
                    //⼩于2048,才转换成base64
                    limit: 2048
                }
            }
        }
    ]
}

# Babel处理ES6

npm i babel-loader @babel/core @babel/preset-env -D
//babel-loader是webpack 与 babel的通信桥梁,不会做把es6转成es5的⼯作。
// 这部分⼯作需要⽤到@babel/preset-env来做
//@babel/preset-env⾥包含了es6转es5的转换规则

webpack.config.js

{
     test: /\.js$/,
     exclude: /node_modules/,
     use: {
         loader: "babel-loader",
         options: {
            presets: ["@babel/preset-env"]
         }
     }
}

# 安装 es6 新特性

# 全局引入方式(全部引入)把所有特性注⼊进来
npm install --save @babel/polyfill
//index.js 顶部
import "@babel/polyfill";
# 按需加载

webpack.config.js

{
     test: /\.js$/,
     exclude: /node_modules/,
     use: {
         loader: "babel-loader",
         options: {
            presets: [
                [
                    "@babel/preset-env",
                    {
                        targets: {
                            edge: "17",
                            firefox: "60",
                            chrome: "67",
                            safari: "11.1"
                        },
                        corejs: 2,//新版本需要指定核⼼库版本
                        useBuiltIns: "usage"//按需注⼊
                    }
                ]
            ]
         }
     }
}

# 不污染全局

@babel/plugin-transform-runtime

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
{
     test: /\.js$/,
     exclude: /node_modules/,
     use: {
         loader: "babel-loader",
         options: {
            "plugins": [
                 "@babel/plugin-transform-runtime",
                 {
                 "absoluteRuntime": false,
                 "corejs": false,
                 "helpers": true,
                 "regenerator": true,
                 "useESModules": false
                 }
                 ]
            ]
         }
     }
}

usage 的⾏为类似 babel-transform-runtime,不会造成全局污染,因此也会不会对类似 Array.prototype.includes() 进⾏ polyfill。

# .babelrc⽂件

options部分移入该文件

{
 "plugins": [
     [
        "@babel/plugin-transform-runtime",
         {
             "absoluteRuntime": false,
             "corejs": false,
             "helpers": true,
             "regenerator": true,
             "useESModules": false
         }
     ]
     ]
}
{
     test: /\.js$/,
     exclude: /node_modules/,
     loader: "babel-loader"
}

# 插件Plugins

# HtmlWebpackPlugin

在打包结束后,自动生成一个html文件,并把打包⽣成的js模块引⼊到该html中。

npm install html-webpack-plugin --save-dev
const htmlWebpackPlugin = require("html-webpack-plugin"); // 通过 npm 安装
const path = require('path');
module.exports = {
    entry: './src/index.js', // 入口文件
    output: {
        filename: 'index.js',
        path: path.resolve(__dirname, './dist')
    },
    mode: 'development', // 打包环境 production development none
    module: {
        rules: [
            {
                test: /\.less$/, // 处理less文件 并插入到head
                use: ["style-loader", "css-loader", "less-loader"]
            },
            {
                test: /\.sass$/, // 处理sass文件 并插入到head
                use: ["style-loader", "css-loader", "sass-loader"]
            }
        ]
    },
    plugins: [
        // 以模版自动生成HTML 且生成的js会自动引入
        new htmlWebpackPlugin({
            title: 'webpack demo', // 页面标题
            template: path.join(__dirname, './src/index.html'), // 源html
            filename:'index.html'   //指定生成的页面名称
        })
    ] //插件配置
}

title 会赋值到 htmlWebpackPlugin.options.title,在html页面中用ejs语法指定title

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
    <div id="app">app</div>
</body>
</html>

# clean-webpack-plugin

输出前删除生成的文件夹

npm install clean-webpack-plugin --save-dev
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require("html-webpack-plugin");
const path = require('path');
module.exports = {
    entry: './src/index.js', // 入口文件
    output: {
        filename: 'index.js',
        path: path.resolve(__dirname, './dist')
    },
    mode: 'development', // 打包环境 production development none
    module: {
        rules: [
            {
                test: /\.less$/, // 处理less文件 并插入到head
                use: ["style-loader", "css-loader", "less-loader"]
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(),
        // 以模版自动生成HTML 且生成的js会自动引入
        new htmlWebpackPlugin({
            title: 'webpack demo', // 页面标题
            template: path.join(__dirname, './src/index.html'), // 源html
            filename:'index.html'   //指定生成的页面名称
        })
    ] //插件配置
}

# mini-css-extract-plugin

css提取为独立的文件的插件,对每个包含cssjs文件都会创建一个css文件。生成的文件会自动添加到index.html

const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const htmlWebpackPlugin = require("html-webpack-plugin");
const miniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
module.exports = {
    entry: './src/index.js', // 入口文件
    output: {
        filename: 'index.js',
        path: path.resolve(__dirname, './dist')
    },
    mode: 'development', // 打包环境 production development none
    module: {
        rules: [
            {
                test: /\.less$/, // 处理less文件 并插入到head
                use: [miniCssExtractPlugin.loader, "css-loader", "less-loader"] // 用了这个style-loader就不能写了
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(),
        new miniCssExtractPlugin({
            filename: "[name][chunkhash:8].css" // 单独生成指定css文件
        }),
        // 以模版自动生成HTML 且生成的js会自动引入
        new htmlWebpackPlugin({
            title: 'webpack demo', // 页面标题
            template: path.join(__dirname, './src/index.html'), // 源html
            filename:'index.html'   //指定生成的页面名称
        })
    ] //插件配置
}

# sourceMap

源代码与打包后的代码的映射关系,通过sourceMap定位到源代码。

devtool:"cheap-module-eval-source-map",// 开发环境配置
devtool:"cheap-module-source-map", // 线上⽣成配置

# WebpackDevServer

提升开发效率的利器

npm install webpack-dev-server -D

# 运行 webpack-dev-server

npx webpack-dev-server

配置 package.json

"scripts": {
    "server": "webpack-dev-server"
}
npm run server

该操作会运行服务到 http://localhost:8080

# 配置自定义端口

devServer: {
    contentBase: "./dist",
    open: true,
    port: 8081
}

# 跨域实现代理

devServer: {
    contentBase: "./dist",
    open: true,
    port: 8081,
    proxy: {
        '/api': 'http://localhost:3000'
    }
}

现在,对 /api/users 的请求会将请求代理到 http://localhost:3000/api/users

# Hot Module Replacement (HMR:热模块替换)

const webpack = require("webpack");

module.exports = {
    devServer: {
     contentBase: "./dist",
     open: true,
     hot:true // 启动hmr
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
}

注意启动HMR后,css抽离会不⽣效,需用 style-loader