Webapck 体系基础

为什么要学习 Webpack

  • 理解前端“工程化”概念、工具、目标
  • 提高个人核心竞争力
  • 成为高阶前端工程师的必经之路

什么是 Webpack

  • 前端项目由什么构成?—— 资源
    image.png

    • 前端工程化工具出现之前靠手动管理资源文件,比如通过<link >标签引入样式文件,通过<script> </script>标签引入 JS 文件等,但这种做法会出现很多问题:
      • 操作过程繁琐
      • 存在依赖关系时要严格按照顺序书写
      • 开发与生产环境一致导致难以接入 TS 或者 JS 的新特性
      • 比较难接入 Less、Sass 等工具
      • JS、CSS、图片资源管理模型不一致等
    • 为了解决这些问题出现了许多前端工程化工具:Webpack、Vite、browserifyjs 等,某种程度上正是这些工具的出现,才有了前端工程这一概念
  • Webpack 本质上是一种前端资源编译、打包工具
    image.png

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

Webpack 的用法

  • 安装 Webpack:npm i -D webpack webpack-cli

  • 编辑配置文件 webpack.config.js

    // webpack.config.js
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: "[name].js",
            path: path.join(__dirname,"./dist"),
        },
        module: {
           rules: [{
               test: /\.less$/i,
               use: ['style-loader','css-loader','less-loader']
           }], 
        }
    }
    
  • 执行编译命令:npx webpack会在根目录的 dist 文件夹下得到编译出的打包文件 main.js(默认为main.js,可以修改)

  • 核心流程(极度简化版):入口处理、依赖解析、资源解析、资源合并打包
    image.png

  • Webpack 本质上完成的事情:模块化 + 一致性

    • 多个文件资源合并成一个,减少 HTTP 请求数
    • 支持模块化开发
    • 支持 typescript、CoffeeScript 语言
    • 统一图片、CSS、字体等其他资源的处理模型

使用 Webpack

  • 关于 Webpack 的使用方法,基本都围绕“配置”展开,可划分为两大类:
    • 流程类:作用于流程中的某个或若干个环节,直接影响打包效果的配置项
      image.png
    • 工具类:主流程之外,提供更多工程化能力的配置项
      image.png
    • Webpack 中的属性按使用频率来看:
      • entry / output
      • module / plugins
      • mode
      • watch / devServer / devtool

处理 CSS:例如在 JS 中引入 CSS 文件 import './index.css'

  • 安装 Webpack:npm i -D webpack webpack-cli

  • 安装依赖:需要使用的 loader:npm i -D style-loader css-loader

  • 编辑配置文件 webpack.config.js 添加 module 处理 CSS 文件

    const path = require('path');
    
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: "[name].js",
            path: path.join(__dirname, "./dist"),
        },
        module: {
            rules: [{
                // test: /\.less$/i,
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }],
        },
        mode: 'development',
    }
    
  • 终端使用 npx webpack 进行编译

使用 Webpack 处理 JavaScript:接入 Babel 将高版本 JS 代码转译成低版本 JS 代码

  • 安装依赖:npm i -D @babel/core @babel/preset-env babel-loader

  • 编辑配置文件 webpack.config.js

    const path = require('path');
    
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: "[name].js",
            path: path.join(__dirname, "./dist"),
        },
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.js$/,
                    use: [{
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                ['@babel/preset-env']
                            ],
                        },
                    }],
                },
            ],
        },
        mode: 'development',
    }
    
  • 终端使用 npx webpack 进行编译

使用 Webpack 处理 HTML:不使用 loader 而是使用 HTML 插件

  • 安装依赖 npm i -D html-webpack-plugin

  • 编辑配置文件 webpack.config.js

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: "[name].js",
            path: path.join(__dirname, "./dist"),
        },
        module: {
            rules: [
                {
                    // test: /\.less$/i,
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.js$/,
                    use: [{
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                ['@babel/preset-env']
                            ],
                        },
                    }],
                },
            ],
        },
        plugins: [new HtmlWebpackPlugin],
        mode: 'development',
    }
    
  • 终端使用 npx webpack 进行编译

使用 Webpack 进行热模块更新(HMR,Hot Module Replacement)

  • 写的代码能够立刻更新到浏览器中,并且不用刷新浏览器
  • 编辑配置文件 webpack.config.js 添加devServer属性
    module.exports = {
        //...
        devServer: {
            hot: true,
        },
    }
    
  • 启动 Webpack 使用 npx webpack serve 命令

使用 Webpack 进行 Tree-Shaking,用于删除 dead code

  • dead code:代码没有被用到或者不可到达、代码的执行结果不会被用到、代码只读不写…
  • 开启 Tree-Shaking:
    • mode: "production"

    • optimization: {usedExports: true}

      module.exports = {
          //...
          mode: "production",
          optimization: {
              usedExports: true,
          },
      }
      
    • 终端使用 npx webpack 进行编译

Loader 组件

  • Loader 的作用是进行资源内容的转化,Webpack 只认识 JS,Loader 用于处理非标准 JS 资源,翻译为标准 JS

  • 使用 Loader(以处理 less 文件为例):

    • 安装 Loader: npm i -D css-loader style-loader less-loader

    • 添加 module 处理 css 文件,其中 less-loader 实现了 less -> css 的转换;css-loader 将 CSS 包装成类似 module.exports = “${css}” 的内容,包装后的内容符合 JavaScript 语法;style-loader 将 CSS 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签。并且这三个 loader 还是以链式调用方式加载的
      image.png

      module.exports = {
            //...
            module: {
                rules: {
                    test: /\.less$/i,
                    use: ["css-loader","style-loader","less-loader"],
                },
            },
      }
      
  • Loader 的特性:

    • 链式执行(前一个 loader 的输出可能是另一个 loader 的输入)
    • 支持异步执行
    • 分为 normal 和 pitch 两种模式
  • 编写 Loader

    • 一个没有任何功能的 loader:
    module.exports = function(source, sourceMap?, data?){
        //source 是 loader 的输入也可能是前一个 loader 的输出
        return source;
    };
    
    • 在 webpack 中调用这个 loader:
    module.exports = {
          //...
          module: {
              rules: [
                {
                  test: /\.js$/,
                  use: [path.join(__dirname, './loader')]
                },
              ],
          },
      }
    
  • 常用 Loader
    image.png

Plugin 组件

  • Webpack 很多功能是靠插件实现的

  • 很多知名工具像 VS Code、Webstorm 等都设计了所谓的插件架构,Webpack 本身很多功能也是基于插件实现的

  • 不使用插件的话会有很多缺点:

    • 新人需要了解整个流程细节,上手成本高功能迭代成本高,牵一发动全身
    • 功能僵化,作为开源项目而言缺乏成长性
    • 也就是心智成本高、可维护性低、生命力弱
  • 插件架构的精髓:对扩展开放、对修改封闭

  • 插件的使用:

    • 例如 npm i -D webpack-dashboard
    • 引入和使用插件:
    // import the plugin
    const DashBoardPlugin = require("webpack-dashboard");
    
    // add it to your webpack configuration plugins
    module.exports = {
        // ...
        plugins : [new DashBoardPlugin()],
        // ...
    };
    
  • 编写一个插件

    • 插件围绕‘钩子’展开,钩子的作用在编译的某个环节触发钩子,某种程度上可以理解为事件
    class SomePlugin {
        apply(compiler){
            compiler.hooks.thisCompilation.tap('SomePlugin', (compilation) => {})
        }
    }
    
    • 钩子的核心信息:
      • 时机:编译过程的特定节点,Webpack 会以钩子形式通知插件此刻正在发生什么事情
      • 上下文:通过 tapable 提供的回调机制,以参数方式传递上下文信息
      • 交互:在上下文参数对象中附带了很多存在 side effect 的交互接口,插件可以通过这些接口改变
        image.png
      • 时机:compier.hooks.compilation
      • 参数:compilation 等
      • 交互:dependencyFactories.set

如何学习 Webpack

image.png

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值