构建Webpack知识体系|笔记

107 阅读9分钟

构建Webpack知识体系

Webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。它主要用于将项目中的所有依赖项(包括 JavaScript 文件、图片、CSS 等)打包成一个或多个 bundle,这些 bundle 可以被浏览器加载和执行。

为什么要学习Webpack?

  • 理解前端“工程化”概念、工具、目标
  • 一个团队总要有那么几个人熟悉Webpack,某种程度上可以成为个人的核心竞争力
  • 高阶前端必经之路

什么是Webpack

  • 前端项目由资源构成

    image-20241126200744604.png

  • 手动管理资源的问题

    • 依赖手工,比如有50个JS文件 ... 操作,过程繁琐
    • 当代码文件之间有依赖的时候,就得严格按依赖顺序书写
    • 开发与生产环境一致,难以接入TS或JS新特性
    • 比较难接入 Less、Sass 等工具
    • JS、图片、CSS资源管理模型不一致
  • 对开发效率影响非常大,直到出现了很多工程化工具,其中就有Webpack

Webpack

本质上是一种前端资源编译、打包工具

image-20241126201937431.png

  • 多份资源文件打包成一个 Bundle
  • 支持 Babel、Eslint、TS、CoffeScript、Less、Sass
  • 支持模块化处理 css、图片 等资源文件
  • 支持 HMR+开发服务器
  • 支持持续监听、持续构建
  • 支持代码分离
  • 支持 Tree-shaking
  • 支持 Source map
  • ...

使用Webpack

示例

  1. 安装

    image-20241126202328962.png

  2. 编辑配置文件:webpack.config.js

    const path = require('path')
    ​
    module.exports = {
        entry: './src/index',//定义当前项目的入口
        mode: "development",
        devtool: false,
        output: {//定义项目打包完之后放在哪里 出口
            filename: '[name].js',
            path: path.join(_dirname, './dist')
        }
    }
    
  3. 执行编译命令

    image-20241126202434158.png

把资源编译成产物

image-20241126202800215.png

核心流程

  1. entry--入口处理

    • 从entry文件开始,启动编译流程
  2. require/import--依赖解析

    • 从entry文件开始,根据require or import 等语句找到依赖资源
  3. module--资源解析

    • 根据module配置,调用资源转移器,将png、css 等非标准JS资源转译为JS内容
  4. output--资源合并打包

    • 将转译后的资源内容合并打包为可直接在浏览器运行的JS文件
  • 递归调用2、3,直到所有资源处理完毕

模块化+一致性

  • 多个文件资源合并成一个,减少 http 请求数
  • 支持模块化开发
  • 支持高级 JS 特性
  • 支持 Typescript、CoffeeScript 方言
  • 统一图片、CSS、字体 等其它资源的处理模型
  • ...

配置

关于 Webpack 的使用方法,基本都围绕“配置”展开,而这些配置大致可划分为两类:

常用
  • entry/output

    • entry(入口):指定Webpack的入口文件,告诉Webpack从哪个文件开始打包。可以是一个字符串、字符串数组或对象。
    • output(输出):定义了打包后的文件输出到哪里,以及输出文件的名称。通常包含path(输出路径)和filename(输出文件名)两个属性。
  • module/plugins

    • module:Webpack在处理文件时,会用不同的加载器(loaders)来处理不同类型的文件。这些加载器在module部分配置。
    • plugins:插件用于在构建过程中执行更复杂的任务,如优化JS文件、生成CSS文件、提供环境变量等。插件在plugins部分配置。
  • mode

    • mode:Webpack 4引入了mode属性,用于指定构建环境是开发(development)还是生产(production)。这个设置会影响Webpack内置的优化和插件行为。
  • watch/devServer/devtool

    • watch(监视):watch属性可以让Webpack在文件发生变化时自动重新构建项目。
    • devServer(开发服务器):Webpack DevServer是一个小型的静态服务器,用于在开发过程中提供网页。它支持热模块替换(HMR)。
    • devtool(源映射):devtool属性用于配置源映射,帮助开发者在浏览器中调试代码时映射回原始源代码。
基本使用方法

image-20241126215224584.png

  1. 声明入口entry

    module.exports = {
        entry: "./src/index"
    };
    
  2. 声明产物出口output

    const path = require("path");
    ​
    module.exports = {
        entry: './src/index.js', 
        output: {
            filename: '[name].js'
            path: path.join(__dirname, 'dist'),
        }
    };
    
  3. 运行npx webpack

处理CSS

image-20241126215155207.png

  1. 安装Loader

    pnpm add -D css-loader style-loader
    
  2. 添加module处理css文件

    const path = require("path");
    ​
    module.exports = {
        entry: "./src/index",
        output: {
            filename: "[name].js",
            path: path. join(_dirname, "./dist"),
        },
        module: {
            // css 处理器
            rules: [{
                test: /.css/i,//固定条件
                use: [
                    "style-loader",
                    "css-loader"
                ],//使用这两个来处理以.css结尾的文件
            }],
        },
    };
    
Loader

在 Webpack 中,"loader" 是一个特殊的模块,它用于在 Webpack 构建过程中对模块的源代码进行转换或处理。Loaders 允许你在打包文件之前对它们进行预处理,例如编译、打包、优化、转换等操作

主要特点:
  1. 转换文件

    • Loaders 可以将文件从一种格式转换为另一种格式,例如将 TypeScript 转换为 JavaScript,或将 SASS 转换为 CSS。
  2. 处理资源

    • Loaders 可以处理图片、字体等资源文件,并将它们转换为可以在 JavaScript 模块中使用的格式。
  3. 代码优化

    • Loaders 可以对代码进行压缩、去重、提取公共代码等优化操作。
  4. 模块化

    • Loaders 支持模块化处理,允许你将复杂的任务分解为多个 loader,每个 loader 负责处理一部分任务。
  5. 链式处理

    • Loaders 可以链式使用,Webpack 会根据配置的顺序从右到左处理 loader,允许你将多个 loader 应用于同一个文件。
常见的 Loaders:
  • babel-loader

    • 将 JavaScript 文件使用 Babel 转换为兼容更多浏览器的代码。
  • css-loaderstyle-loader

    • 将 CSS 文件加载为模块,并将其注入到 HTML 中。
  • file-loaderurl-loader

    • 处理图片和其他文件资源,将它们转换为 URL 或 Data URL。
  • html-loader

    • 将 HTML 文件加载为字符串。
  • eslint-loader

    • 在构建过程中对 JavaScript 代码进行 lint 检查。
参考资料:
处理JS--Babel

image-20241126215251015.png

  1. 安装依赖

    npm i -D @babel/core @babel/preset-env babel-loader
    
  2. 声明产物出口output

    const path = require("path");
    ​
    module.exports = {
        entry: "./src/index",
        output: {
            filename: "[name].js",
            path: path.join(_dirname, "./dist"),
        },
        module: {
            rules: [{
                test: /.js?$/,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            ['@babel/preset-env']
                        ]
                    }
                }]
            }]
        }
    }
    
  3. 执行npx webpack

Babel

是一个广泛使用的 JavaScript 编译器,它允许开发者使用最新的 JavaScript 语法特性编写代码,同时确保这些代码能够在当前和旧版的浏览器或其他环境中运行。Babel 通过转换代码,将 ES6+(ECMAScript 2015 及更高版本)的代码转换为向后兼容的 JavaScript 版本(如 ES5),从而使得现代 JavaScript 语法能够在不支持新语法的环境中运行。

主要功能:
  1. 代码转换

    • Babel 可以将 ES6+ 代码转换为 ES5 代码,使得可以在旧版浏览器中运行。
  2. 语法插件

    • Babel 通过插件支持各种新的 JavaScript 语法提案,这些插件可以单独使用或组合使用。
  3. polyfill

    • Babel 可以引入 polyfills 来提供那些在旧版环境中不存在的新功能。
  4. 代码优化

    • Babel 转换后的代码会进行优化,以提高运行效率。
  5. 模块转换

    • Babel 支持将 ES6 模块转换为 CommonJS 或 AMD 模块,以便于在不同环境中使用。
  6. 集成开发工具

    • Babel 可以集成到各种开发工具中,如 Webpack、Rollup、Gulp 等。
  7. 代码高亮和格式化

    • Babel 可以与代码编辑器和 IDE 集成,提供代码高亮和自动格式化功能。
参考资料:
处理HTML--自动生成HTML文件

image-20241126220422297.png

  1. 安装依赖

    npm i -D html-webpack-plugin
    
  2. 声明产物出口output

    const path = require("path");
    const HtmlWebpackPlugin = require('html-webpack-plugin');]module.exports = {
        entry: "./src/index",
        output: {
            filename: "[name].js",
            path: path. join(_dirname, "./dist"),
        },
        plugins: [new HtmlWebpackPlugin()]
    };
    
  3. 执行npx webpack

工具

HMR

Hot Module Replacement--模块热替换

HMR 允许在应用运行时动态地替换、添加或删除模块,而无需重新加载整个页面。

主要优势:
  1. 提升开发效率

    • 开发者在修改代码后,可以立即看到更改的效果,而无需手动刷新浏览器。
  2. 节省时间

    • 无需重新加载整个页面,减少了开发过程中的等待时间。
  3. 状态保持

    • HMR 可以在模块替换过程中保持应用的状态,不会被重置。
  4. 优化开发体验

    • 对于复杂的应用,HMR 可以提供更好的开发体验,尤其是在开发单页应用(SPA)时。
在Webpack中使用HMR:
  1. 开启HMR

    • webpack.config.js文件
    module.exports = {
      // ...
      devServer: {
        hot: true,
      }
    };
    
  2. 启动Webpack

    npx Webpack serve
    
工作原理:
  • 当Webpack检测到模块的更改时,它会使用HMR协议与运行中的应用程序通信。
  • 应用程序中的HMR运行时会接收到更新指令,并应用这些更改,通常是替换内存中的模块,而不是整个页面。
  • 浏览器不会失去状态,用户界面会根据新的模块进行更新。

image-20241127181907996.png

Tree-Shaking

Tree-Shaking--树摇,用于删除Dead Code

  • Dead Code

    • 代码没有被用到,不可到达
    • 代码的执行结果不会被用到
    • 代码只读不写
    • ...

Tree-Shaking把定义了但是没使用的代码删掉

在Webpack中使用Tree Shaking:

webpack.config.js文件

module.exports = {
    entry: "./src/index",
    mode: "production",//1.
    devtool: false,
    optimization: {
        usedExports: true,//2.
    },
};

PS:对工具类库如Lodash有奇效

其它工具
  • 缓存

    • Webpack 本身缓存:Webpack 会缓存构建结果,如果源文件没有变化,下一次构建会非常快。
    • 持久化缓存:通过使用如 cache-loader 这样的插件,可以在多次构建之间持久化缓存。
  • Sourcemap

    • Webpack 允许通过配置 devtool 选项来生成 Sourcemap,例如 devtool: 'source-map'
  • 性能监控

    • Webpack Bundle Analyzer:一个流行的插件,可以可视化地展示包内容,帮助开发者理解包的大小和组成。
    • performance hints:Webpack 会在构建时提供性能提示,警告那些体积过大的包。
  • 日志

    • 内置日志:Webpack 提供了基本的日志输出。
    • friendly-errors-webpack-plugin:一个插件,可以美化错误输出,使其更容易理解。
    • webpack-logger:一个插件,用于自定义日志记录。
  • 代码压缩

    • TerserWebpackPlugin:一个插件,用于压缩 JavaScript 和 JSON。
    • css-minimizer-webpack-plugin:用于压缩 CSS。
    • html-webpack-plugin:用于压缩 HTML 文件。
  • 分包

    • 动态导入:Webpack 支持 ES6 动态导入语法,允许代码分割。
    • SplitChunksPlugin:Webpack 的内置插件,用于自动分割代码。
    • 自定义分割点:通过配置 optimization.splitChunks 选项,可以指定特定的分割点。
  • ...