WebPack入门| 青训营笔记

44 阅读3分钟

什么是WebPack

前端项目由大量的资源构成,在前端发展初期,大量的资源依赖手工管理,存在大量缺点:

  • 操作过程繁琐,对开发效率影响较大,限制了页面规模
  • 当代码文件之间存在依赖时,需要严格按照依赖顺序书写
  • 开发与生产环境一致,难以引入TS或JS的新特性
  • 难以接入Less、Sass等工具
  • JS、图片、CSS资源管理模型不一致

类似WebPack等工具的出现,使得前端逐渐工程化。

WebPack本质上是一种前端资源编译、打包工具: image.png

WebPack应用示例

  1. 安装webpack
  2. 准备好两个需要打包的js文件
    1. bar.js
      export default 'bar';
      
    2. index.js
      import bar from './bar'
      console.log(`hello ${bar}`)
      
  3. 编辑配置文件
    const path = require("path");
    
    module.exports = {
        entry: './src/index',   // 定义项目入口
        mode: "development",
        devtool: false,
        output: {               // 定义项目打包完成后的存放路径
            filename: "[name].js",
            path: path.join(__dirname, "./dist"),
        }
    }
    
  4. 执行编译命令:npx webpack,可以将两个js文件打包为一个js文件

WebPack核心流程

  1. 入口处理:从entry文件开始,启动编译流程
  2. 依赖解析:从entry文件开始,根据requireimport等语句找到依赖资源
  3. 资源解析:根据module配置,调用资源转移器,将png、css等非标准js资源转译为js内容
  4. 递归调用第2、3步,直到所有资源处理完毕
  5. 资源合并打包:将转译后的资源内容合并打包为可直接在浏览器运行的js文件

WebPack主要工作

模块化 + 一致性:

  • 多个资源文件合并为一个,减少http请求数
  • 支持模块化开发
  • 支持高级JS特性
  • 只支持TypeScript、CofferScript方言
  • 同一图片、CSS、字体等其他资源的处理模型

WebPack使用

WebPack的使用核心是书写配置文件,配置文件中的配置项可大致分为两类:

  • 流程类:作用于流程中某个或若干个环节,直接影响打包效果的配置项
    • 常见流程类配置按流程步骤划分: 流程阶段|常用配置 --|-- 入口处理|entry,定义项目入口;context,定义WebPack寻找资源的路径 依赖解析|resolveexternals 资源解析|module 资源合并打包| optimizationmodetarget
  • 工具类:主流程之外,提供更多工程化能力的配置项
    • 常见的工具类配置按作用类别划分:

      类别常用配置
      开发效率类watchdevtooldevServer
      性能优化类cacheperformance
      日志类statsinfrastructureLogging
      其他amdbail

其中最常用的配置有:

  • entry/output
  • model/plugins
  • mode
  • watch/devServer/devtool

WebPack使用实例

使用WebPack至少需要有entryoutput

const path = require("path");

module.exports = {
    entry: './src/index',   // 定义项目入口
    output: {               // 定义项目打包完成后的存放路径
        filename: "[name].js",
        path: path.join(__dirname, "./dist"),
    }
}

非js文件处理

当需要处理非js文件,如css文件时的处理步骤:

  1. 安装Loader:npm add -D css-loader style-loader
  2. 准备好需要打包的js文件和css文件
  3. 在webpack配置中添加module处理css文件
    module: {
        rules: [{
            test: /\.css$/,     // 过滤文件:用正则表达式得到以css结尾的文件
            use: ['style-loader', 'css-loader']     // 指定处理所用的loader
        }]
    }
    

接入Babel

Babel本质上是一种代码转译工具,将Bable接入WebPack的方法:

  1. 安装依赖:npm i -D @babel/core @babel/preset-env babel-loader
  2. 准备使用ES6语法的js文件
  3. 在webpack配置中添加module处理js文件
    module: {
        rules: [{
            test: /\.js$/,      // 过滤出js文件
            use: [{
                loader: 'babel-loader',     // 使用babel-loader处理js文件
                options: {      // options会传入babel-loader中运行
                    presets: [
                        ['@babel/preset-env']
                    ]
                }
            }]
        }]
    }
    

生成HTML

在WebPack中,可以不写HTML文件,直接通过插件自动生成HTML:

  1. 安装依赖(插件):npm i -D html-webpack-plugin
  2. 准备需要插入HTML的js文件
  3. 在webpack配置中添加plugins使用html-webpack-plugin插件
    const path = require('path')
    const HTMLWebpackPlugin = require('html-webpack-plugin')
    
    module.exports = {
        entry: './src/index',
        mode: 'development',
        devtool: false,
        output: {
            filename: '[name].js',
            path: path.join(__dirname, './dist')
        },
        plugins: [new HTMLWebpackPlugin()]
    }
    
  4. 使用npx webpack命令后,会生成js和html文件两个产物

WebPack工具线

HMR

Hot Module Replacement(HMR,热模块替换),用户修改的代码可以立刻更新到浏览器当中,且浏览器不需要进行刷新操作。

开启HMR的方法:

  1. 安装依赖:npm i -D webpack-dev-server
  2. 在webpack配置中添加devServer配置,设置hot: true;添加watch: true配置
    const path = require('path')
    const HTMLWebpackPlugin = require('html-webpack-plugin')
    
    module.exports = {
        entry: './src/index',
        mode: 'development',
        devtool: false,
        watch: true,
        devServer: {
            hot: true,
            open: true
        },
        module: {
            rules: [{
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }]
        },
        output: {
            filename: '[name].js',
            path: path.join(__dirname, './dist')
        },
        plugins: [new HTMLWebpackPlugin()]
    }
    
  3. 使用npx webpack serve打包命令进行打包(配置中设置watch: true时不用加serve关键字,添加serve关键字时不会生成打包文件)

Tree-Shaking

Tree-Shaking插件可以用于删除Dead Code,如:

  • 代码未被用到,不可达到
  • 代码的执行结果未被使用
  • 代码只读不写等情况

开启Tree-Shaking的方法:

  1. 在webpack配置中设置mode: production
  2. 添加optimization配置:
    const path = require('path')
    
    module.exports = {
        entry: './src/index',
        devtool: false,
        mode: 'production',
        optimization: {
            usedExports: true
        },
        output: {
            filename: '[name].js',
            path: path.join(__dirname, './dist')
        }
    }
    

WebPack Loader

WebPack插件的功能主要是用于内容的转化,将非js资源转译为标准js。 使用loader的方法:

  1. 使用npm安装loader包
  2. 在webpack配置的module中添加rules配置,包含testuse两部分

Loader的运行流程

以打包js文件和less文件为例,分析loader的运行流程: image.png

打包js和less文件,使用了3个loader,其功能分别为:

  • less-loader:实现less => css的转换
  • css-loader:将CSS包装成类似module.exports = "${css}" 的内容,实现css => js的转换
  • style-loader:将css模块包进require语句,并在运行时调用injectStyle等函数将内容注入到页面的style标签

Loader的运行特性

  • 链式执行
  • 支持异步执行
  • 分normal和pitch两种模式
  • Loader的调用顺序与声明顺序相反,在声明要使用的Loader时要注意顺序 image.png

自定义Loader

可以根据需要自定义loader,loader的输入为源代码或上一个loader输出的内容,输出为自定义处理后的结果,调用的最后一个loader的输出结果会直接插入到webpack打包产物中。

自定义loader的基础写法如下:

module.exports = function (source){
    console.log(source);

    return source;
}

WebPack 插件

插件功能可以极大地提高应用的可扩展性和成长性,插件的常规使用流程:

  1. 使用npm安装需要的插件
  2. 在webpack配置文件中import要用的插件
  3. 在配置中实例化插件类:plugins: [new DashboardPlugin()];

理解插件

插件运行主要依赖于webpack中的钩子,钩子的核心信息:

  • 触发时机:编译过程的特定节点,Webpack会以钩子形式通知插件此刻正在发生什么事情;
  • 上下文(参数):通过tapable提供的回调机制,以参数方式传递上下文信息;
  • 交互:在上下文参数对象中附带了很多存在side effect的交互接口,插件可以通过这些接口改变