Day11:Webpack 的使用方法 | 青训营笔记

71 阅读2分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 11 天。

为什么需要Webpack

前端项目由许许多多的资源文件构成。

手工管理、组织这些资源面临许许多多的问题:

  • 操作过程繁琐
  • 当代码文件之间有依赖的时候,就得严格按依赖顺序书写
  • 开发与生产环境一致,难以接入TS或JS新特性
  • 比较难接入Less、Sass等工具
  • JS、图片、CSS 资源管理模型不一致

为此,出现了许多管理、组织、处理资源文件的工具,即所谓的“工程化工具”。

Webpack就是一种工程化工具,其本质是一种前端资源的编译、打包工具:

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

Webpack的设计目标:模块化、一致地处理资源

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

Webpack初体验

安装

npm i -D webpack webpack-cli

使用实例

配置:声明输入、处理流程、输出

module.exports = {
    entry: "main.js",
    output: {
        filename:"[name].js"
    	path: path.join(__dirname, "./dist"),
    },
    module:{
        rules: [{
            test: /\.less$/i,
            use: ["style-loader", "css-loader", "less-loader"]
        }]
    }
}

编译

npx webpack

核心流程

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

配置Webpack

Webpack的使用基本都围绕【配置】展开,而这些配置大致可划分为两类:

  • 流程类:作用于流程中某个/若干个环节,直接影响打包效果的配置项
    • 输入配置
      • entry
      • context
    • 模块解析
      • resolve
      • externals
    • 模块转译
      • module
    • 后处理
      • optimization
      • mode
      • target
  • 工具类:主流程之外,提供更多工程化能力的配置项
    • 开发效率类:
      • watch
      • devtool
      • devServer
    • 性能优化类:
      • cache
      • performance
    • 日志类:
      • stats
      • infrastructureLogging
    • 其它:
      • amd
      • bail
      • ……

按使用频率(重要程度)排名:

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

参考:Configuration | webpack

流程类配置例子

  1. 声明输入entry、输出output(这两个必须有)

    const path = require("path");
    
    module.exports = {
        entry: "./src/index",
        output: {
            filename: "[name].js"
        	path: path.join(__dirname, "./dist"),
        },
    };
    
  2. 配置转换流程(Loader)1:以CSS处理为例

    安装:

    npm add -D css-loader style-loader
    

    配置:

    const path = require("path");
    
    module.exports = {
        entry: "./src/index",
        output: {
            filename: "[name].js"
        	path: path.join(__dirname, "./dist"),
        },
        module: {
            rules: [{
                test: /\.css$/,  // 文件匹配规则
                use: ["style-loader", "css-loader"]  // 指定处理用到的Loader
            }]
        },
    };
    

    其中use中的指令是按逆序来执行的,即先执行css-loader,再执行style-loader:

    • css-loader:解析CSS文件的@importurl(),会import/require(),经过此Loader后CSS文件转变为JS数组对象,其中的元素是CSS文件的原始内容
    • style-loader:通过上述的JS数组创建一个style标签
  3. 配置转换流程(Loader)2:以JS文件的Babel为例

    Babel:将ES6语法转换为旧式JS语法

    安装:

    npm i -D @babel/core @babel/preset-env babel-loader
    

    babel的preset是一些处理的规则集,常用的preset有:

    • @babel/preset-env
    • @babel/preset-react
    • @babel/preset-typescript

    配置:

    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"]
              ]
            }
          ]
        }]
      },
    };
    
  4. 配置转换流程(Plugin)3:以自动生成配套HTML文件为例

    安装:

    npm i -D html-webpack-plugin
    

    配置:

    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()]
    };
    

工具类配置例子

  • 模块热替换(源码修改,预览服务器即修改而不需要重新生成)

    module.exports = {
      // ...
      devserver: {
        hot: true
      }
    };
    
    npx webpack serve
    
  • 删除死代码

    module.exports = {
      // ...
      mode: "production"
      optimization: {
        usedExports: true
      }
    };