image.pngwebpack 是一个打包模块化 JavaScript 的工具,它会从入口模块出发,识别出源码中的模块化导入语句,递归地找出入口文件的所有依赖,将入口和其所有的依赖打包到一个单独的文件中。是工程化、自动化思想在前端开发中的体现。

webpack 安装

环境准备

在开始之前,请确保安装了 Node.js 的最新版本。使用 Node.js 的最新版本,可以提升 webpack 的打包速度。

安装方式

局部安装 (推荐)

  1. npm init -y # 初始化npm配置⽂件
  2. npm install --save-dev webpack # 安装核⼼库
  3. npm install --save-dev webpack-cli # 安装命令⾏⼯具
  4. # 安装最新的4.x稳定版本
  5. npm i -D webpack@4.44.0
  6. # 安装指定版本
  7. npm i -D webpack@<version>

全局安装 (不推荐)

  1. # 安装webpack V4+版本时,需要额外安装webpack-cli
  2. npm install webpack webpack-cli -g
  3. # 检查版本
  4. webpack -v
  5. # 卸载
  6. npm uninstall webpack webpack-cli -g

以全局的方式安装 webpack,会将项目中的 webpack 锁定到指定的版本,会造成不同的项目中因为 webpack 版本不同而导致冲突,构建失败,因此推荐以局部的方式将 webpack 安装到项目中。

启动 webpack

1、webpack 默认配置

  • webpack默认支持 JS 模块和 JSON 模块
  • 支持 CommonJS、ES module、AMD 等模块类型
  • webpack4 支持零配置使用,但是很弱,稍微复杂些的场景都需要额外扩展

2、执行构建前的准备

  1. 新建工程目录 webpack-demo
  2. 在 webpack-demo 根目录中新建 src 文件夹
  3. 在 webpack-demo 根目录中新建 webpack.config.js 文件,添加默认配置

    1. const path = require("path");
    2. module.exports = {
    3. // 必填 webpack执⾏构建⼊⼝
    4. entry: "./src/index.js",
    5. output: {
    6. // 将所有依赖的模块合并输出到main.js
    7. filename: "main.js",
    8. // 输出⽂件的存放路径,必须是绝对路径
    9. path: path.resolve(__dirname, "./dist")
    10. }
    11. };
  4. 在 src 文件夹中新建 index.js、index.json、other.js 文件

index.js

  1. // index.js
  2. const json = require("./index.json"); // commonJS 模块类型
  3. import { add } from "./other.js"; ES module 模块类型

index.json

  1. {
  2. name: "JSON"
  3. }

other.js

  1. export function add(num1, num2) {
  2. return num1 + num2
  3. }

3、执行构建

执行 webpack 构建有两种方式: npx 方式和 npm script 方式

npx 方式

  1. npx webpack

npm script 方式
使用这种方式执行 webpack 构建需要修改 package.json 文件中的 scripts 属性:

  1. "scripts": {
  2. "test": "webpack"
  3. }

4、构建成功

构建成功后我们会发现根目录下多出一个 dist 目录,该目录就是 webpack 构建后的文件输出目录。目录里面会有一个 main.js 文件,该文件的名称是我们在 webpack.config.js 的 output 中定义的。main.js 文件是一个可执行的 JavaScript 文件,里面包含 webpackBootstrap 启动函数。

webpack 配置核心概念

chunk:是指代码块,一个 chunk 可能由多个模块组合而成,也用于代码合并与分割
bundle:webpack构建成功后的输出文件
entry:webpack 执行构建任务的入口文件
output:webpack 执行构建后,配置资源的输出位置和名称等
loader:模块转换器,让webpack可以支持转换更多的模块类型
plugin:webpack的功能扩展,借助 plugin,可以让 webpack更加强大
mode:打包构建模式,每种模式都会对应开启webpack自带的plugin

配置基础结构

一个 webpack 配置的基础结构如下:

  1. module.exports = {
  2. entry: "./src/index.js", //打包⼊⼝⽂件
  3. output: "./dist", //输出结构
  4. mode: "production", //打包环境
  5. module: {
  6. rules: [
  7. //loader模块处理
  8. {
  9. test: /\.css$/,
  10. use: "style-loader"
  11. }
  12. ]
  13. },
  14. plugins: [new HtmlWebpackPlugin()] //插件配置
  15. };

entry

指定 webpack 打包的入口文件,webpack 执行构建的第一步将从 entry 开始,可抽象成输入。webpack会根据 entry 递归的去寻找依赖,每个依赖都将被它处理,最后输出到打包成果中。

entry 的配置方式有三种方式:

字符串类型
入口模块的文件路径,可以是相对路径

  1. entry: "./src/index.js"

数组类型
入口模块的文件路径,可以是相对路径

  1. entry: ['./src/index.js', './src/main.js']

Object 类型
配置多个入口,每个入口生成一个 chunk

  1. // 单入口 其本质是个字符串
  2. entry: {
  3. main: "./src/index.js"
  4. }
  5. // 上面的单入口配置方式相当于
  6. entry: "./src/index.js"
  7. // 多入口
  8. entry: {
  9. index: "./src/index.js",
  10. login: "./src/login.js"
  11. }

output

配置 webpack 打包转换后的文件输出到磁盘的位置,即配置如何输出 webpack 处理后的代码

output 是一个对象,必须有 filename 属性和 path 属性

  • filename:输出文件的文件名
  • path:输出文件到磁盘的目录,必须是绝对路径

单入口的输出

  1. output: {
  2. filename: "bundle.js",//输出⽂件的名称
  3. path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
  4. },

多入口的输出
多入口的输出需要使用占位符来区分输出的文件名

  1. output: {
  2. filename: "[name][chunkhash:8].js",//利⽤占位符,⽂件名称不要重复
  3. path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
  4. },

webpack 内置的占位符变量如下:

变量 描述
[id] chunk的唯一标识符,从 0 开始
[name] chunk 的名称
[hash] chunk 的唯一标识符的 hash
[chunkhash] chunk 内容的 hash
[query] chunk 的query,例如:文件名 ?后面的字符串

[hash][chunkhash] 的长度可以使用 [hash:16](默认为20)来指定。或者,通过指定output.hashDigestLength 在全局配置长度。

mode

用来指定当前的构建环境,mode 有三个值;

  • production
  • development
  • none | 选项 | 描述 | | —- | —- | | production | 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginUglifyJsPlugin. | | development | 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPluginNamedModulesPlugin | | none | 退出任何默认优化选项 |

设置mode可以⾃动触发webpack内置的函数,达到优化的效果;
如果没有设置,webpack 会将 mode 的默认值设置为 production;

记住,只设置 NODE_ENV,则不会自动设置 mode

loader

模块转换器,用于把模块的源内容按照需求转换成新的内容。
webpack 默认只支持 JS 和 JSON 模块的解析,其他格式的模块例如 css、图片等则需要相应的 loader 来处理。

  1. module: {
  2. rules: [
  3. {
  4. // 用正则取匹配要用该 loader 准换的 css 文件
  5. test: /\.css$/,
  6. use: ["style-loader", "css-loader"]
  7. }
  8. ]
  9. }

loader 的另外两个配置选项 include 和 exclude:

include 包含哪些目录

  1. module: {
  2. rules: [
  3. {
  4. // 用正则取匹配要用该 loader 准换的 css 文件
  5. test: /\.css$/,
  6. use: ["style-loader", "css-loader"],
  7. // 只包含 src 目录里的 css 文件,加快 webpack 的搜索速度
  8. include: path.resolve(__dirname, "src"),
  9. }
  10. ]
  11. }

exclude 排除哪些目录

  1. module: {
  2. rules: [
  3. {
  4. // 用正则取匹配要用该 loader 准换的 css 文件
  5. test: /\.css$/,
  6. use: ["style-loader", "css-loader"],
  7. // 排除 node_modules 目录下的文件
  8. exclude: path.resolve(__dirname, 'node_modules'),
  9. }
  10. ]
  11. }

常用 loader

  • style-loader
  • css-loader
  • sass-loader
  • ts-loader 将 ts 转换成 js
  • babel-loader 转换 ES6、ES7等 JavaScript 新特性语法
  • file-loader 处理非文本文件,如图片、字体文件、PDF文件等
  • eslint-loader

module

module 用于配置如何处理模块。在 webpack 里一切皆模块,一个模块对应着一个文件。webpack 会从 entry 开始递归找出所有依赖的模块。当 webpack 处理到不认识的模块时,就会去 module 里寻找对应的 loader 来处理其不认识的模块。因此我们需要在 module 里配置 loader,让webpack可以支持转换更多的模块类型。

  1. module:{
  2. rules:[
  3. {
  4. test:/\.xxx$/,//指定匹配规则
  5. use:{
  6. loader: 'xxx-load'//指定使⽤的loader
  7. }
  8. }
  9. ]
  10. }

在 module 的 rules 里配置模块的读取和解析规则,通常是用来配置 loader。其类型是一个数组,数组里的每一项都描述了如何去处理部分文件。

  1. module:{
  2. rules:[
  3. {
  4. test:/\./,
  5. use: ["style-loader", "css-loader"]
  6. }
  7. ]
  8. }

在上面的 loader 中:

  • css-loader 分析css模块之间的关系,并合成⼀个css
  • style-loader 会把css-loader⽣成的内容,以style挂载到⻚⾯的head标签里

plugins

plugins 用于扩展 webpack 功能,plugin的职责则是让webpack可以控制其构建流程,从⽽执⾏⼀些特殊的任务。插件的功能⾮常强⼤,可以完成各种各样的任务。

plugins 的配置很简单,plugins 配置项接受一个数组,数组里每一项都是一个要使用的 plugins 实例,plugins 需要的参数通过构造函数传入。

以 HtmlWebpackPlugin 为例:

  1. module.exports = {
  2. plugins: [
  3. new htmlWebpackPlugin({
  4. title: "My App",
  5. filename: "app.html",
  6. template: "./src/index.html"
  7. })
  8. ]
  9. };

htmlwebpackplugin会在打包结束后,⾃动⽣成⼀个html⽂件,并把打包⽣成的js模块引⼊到该html 中

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

htmlwebpackplugin 配置

  1. title: ⽤来⽣成⻚⾯的 title 元素
  2. filename: 输出的 HTML ⽂件名,默认是 index.html, 也可以直接配置带有⼦⽬录。
  3. template: 模板⽂件路径,⽀持加载器,⽐如 html!./index.html
  4. inject: true | 'head' | 'body' | false ,注⼊所有的资源到特定的 template 或者
  5. templateContent 中,如果设置为 true 或者 body,所有的 javascript 资源将被放置到 body元素的底部,'head' 将放置到 head 元素中。
  6. favicon: 添加特定的 favicon 路径到输出的 HTML ⽂件中。
  7. minify: {} | false , 传递 html-minifier 选项给 minify 输出
  8. hash: true | false, 如果为 true, 将添加⼀个唯⼀的 webpack 编译 hash 到所有包含的脚本和
  9. CSS ⽂件,对于解除 cache 很有⽤。
  10. cache: true | false,如果为 true, 这是默认值,仅仅在⽂件修改之后才会发布⽂件。
  11. showErrors: true | false, 如果为 true, 这是默认值,错误信息会写⼊到 HTML ⻚⾯中
  12. chunks: 允许只添加某些块 (⽐如,仅仅 unit test 块)
  13. chunksSortMode: 允许控制块在添加到⻚⾯之前的排序⽅式,⽀持的值:'none' | 'default' |
  14. {function}-default:'auto'
  15. excludeChunks: 允许跳过某些块,(⽐如,跳过单元测试的块)

htmlwebpackplugin 使用案例

  1. const path = require("path");
  2. const htmlWebpackPlugin = require("html-webpack-plugin");
  3. module.exports = {
  4. plugins: [
  5. new htmlWebpackPlugin({
  6. title: "My App",
  7. filename: "app.html",
  8. template: "./src/index.html"
  9. })
  10. ]
  11. };
  1. //index.html
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  8. <title><%= htmlWebpackPlugin.options.title %></title>
  9. </head>
  10. <body>
  11. <di v id="root"></div>
  12. </body>
  13. </html>