Webpack入门

111 阅读11分钟

一、webpack概述

  1. 是什么:
    • 一款前端构建工具
  2. 特点:
    • webpack里一切皆模块
      • 这样能清晰描述出各个模块之间的依赖关系,方便组合打包模块
    • 按需打包模块到输出文件,并能自动处理资源的加载顺序和代码的转换
    • 有丰富的插件和内置功能,用于优化前端资源的加载和使用
    • 支持实时重新加载、热模块替换
    • 拥有广泛的社区支持和生态系统
    • 从Webpack2开始,已经内置了对ES6,CommonJS,AMD模块化语句的支持
  3. webpack工作流程: image.png
  4. 用途:
    • 构建、打包前端项目
      • 通过Loader转换文件,通过Plugin注入钩子,最后输出由多个模块组合成的文件
  5. 不足:
    • 只能用于采用模块化开发的项目
  6. 配置方式:
    • 方式1:通过一个js文件描述配置
    • 方式2:执行webpack可执行文件时通过命令行参数传入

二、为什么要用webpack

  1. 前端的发展角度论述:
    • web应用变得更加复杂、庞大,web前端技术的应用范围也更加广泛,单纯的前端开发方式无法应对当前web应用的发展
      • 结果:出现了很多新思想、框架
        • 新思想:
          • 模块化:
            • 是什么:
              • 把一个复杂的系统分解到多个模块以方便编码
            • 开始模块化改造的文件类型:
              • JS:采用CommonJS、AMD、ES6模块化规范
              • 样式文件:SCSS文件
          • JS模块化规范:
            • CommonJS:
              • 核心思想:
                • 通过require方法同步加载依赖的其他模块
                • 通过module.exports导出需要暴露的接口
              • 细分:
                • CommonJS1
                  • 只能通过exports.xx=xx方式导出
                • CommonJS2(CommonJS通常指这个)
              • 优点:
                • 代码可复用于node.js环境并运行
                • 通过npm发布的很多第三方模块都采用了此规范
              • 缺点:
                • 无法直接运行在浏览器环境下
            • AMD:
              • 干什么:
                • 解决浏览器环境的模块化问题
              • 核心思想:
                • 通过define定义一个模块
                • 通过require导入和使用
              • 优点:
                • 可直接运行在浏览器和Node.js环境中
                • 可异步加载依赖
                • 可并行加载多个依赖
              • 缺点:
                • 运行在环境前要先导入实现了AMD库
            • ES6模块化
              • 发展趋势:
                • 逐渐取代AMD和CommonJS规范,成为浏览器和服务器通用的模块解决方案
                • 核心思想
                  • import
                  • export
                • 优点:
                  • 为终极模块化方案
                • 缺点:
                  • 无法直接运行在大部分JS环境下
        • 新框架:
          • React
          • Vue
          • Angular2
        • 新语言:
          • ES6(ECMAScript6.0)
            • 是什么:
              • JS的下一代标准
            • 优点:
              • 为JS引入了很多新的语法和API,使得JS可用来编写复杂的大型应用程序
            • 不足:
              • 不同浏览器对新语法和API的支持不一致,可能会遇到无法运行的情况
                • 解决方法:使用Babel,将ES6转化为ES5
          • TS(TypeScript)
            • 是什么:
              • JS的一个超集
            • 优点:
              • 支持ES6的所有功能,提供静态类型检查
              • 采用TS编写的代码可被编译成符合ES5,ES6规范的JS
            • 不足:
              • 无法直接运行在浏览器或Node.js环境中
          • Flow
            • 是什么:
              • JS的一个超集
            • 对比TS:
              • 相似,但是更灵活,类型检查可以按需添加
          • SCSS
            • 是什么:
              • 一种CSS预处理器
            • 基本思想:
              • 用和CSS相似的编程语言写完后再编译成正常的CSS文件
            • 优点:
              • 可通过逻辑写出更灵活的代码
              • 可方便地管理代码
            • 不足:
              • 不能直接运行在浏览器环境

三、常见的构建工具和对比

  1. 构建:
    • 是工程化、自动化思想在前端开发中的体现
    • 给前端开发注入了更大的活力
  2. 构建工具
    • 开发环境:
      • Node.js(可胜任所有构建需求)
    • 有哪些:
      • Npm script
        • 是什么:
          • 任务执行者
          • 安装Node,js时附带的包管理器npm内置的一个功能
        • 用途:
          • 允许在package.json里使用script字段定义任务
            • script字段内的每个属性对应一段shell脚本
              • 可以通过调用shell去运行脚本命令
        • 优点:
          • 内置、无需安装其他依赖
        • 缺点:
          • 功能太简单,不方便管理多个任务之间的依赖
      • Grunt
        • 是什么:
          • 任务执行者
          • 相当于进化版的Npm Script
        • 优点:
          • 有大量现成的插件封装了常见的任务
          • 能管理任务之间的依赖关系
          • 能自动化执行依赖的任务
          • 灵活,只负责执行你定义的任务
        • 缺点:
          • 集成度不高,要写很多配置才能用,无法开箱即用
      • Gulp
        • 是什么:
          • 一个基于流的自动化构建工具
      • Webpack
      • Rollup
        • 是什么:
          • 专注于ES6的模块打包工具
        • 优点:
          • 能针对ES6源码进行Tree Shaking以去除那些已被定义但没被使用的代码,减小输出文件大小,提升性能
    • 用途:
      • 将无法直接运行的源代码转换成线上可执行的代码

四、通过Webpack构建一个简单项目

  1. 新建一个目录,执行npm init初始化,生成一个管理项目的配置文件package.json
  2. 安装webpack到本项目:
    • npm i -D webpack
      • -D是--save-dev的简写
  3. 搭建项目里的基础文件:
    • 参照深入浅出webpack的入门1-3
  4. 运行webpack:
    • 项目根目录下:node_modules/.bin/webpack运行webpack可执行文件
    • npm script里定义相关命令(会优先使用本项目下的webpack)
  5. 关于Loader:
    • 用途:
      • 告诉webpack在遇到哪些非js文件时使用Loader去加载、转换
        • 注:Webpack不原生支持解析非JS文件
    • 如何实现:
      • 配置:webpack.config.json->module.rules->test+use?参数
        • use:其值为一个由Loader名称组成的数组,执行顺序由后到前
          • 形式:数组、对象
      • 安装
  6. 关于Devserver
    • 用途:
      • 启动一个HTTP服务器用于服务网页请求,同时帮助启动webpack,并接收webpack发出的文件变更信号,通过websocket协议自动刷新网页做到实时预览
    • 特点:
      • 把Webpack构建出的文件保存在内存中,在要访问输出的文件时,必须通过HTTP服务访问
      • 不会理会webpack.config.js里配置的output.path属性
      • 通过devserver启动的webpack会开启监听模式
        • 工作原理:
          • devserver会让webpack在构建出的js代码里注入一个代理客户端用于控制网页,网页和devserver之间通过websocket协议通信,devserver在收到来自webpack文件变化通知时通过注入的客户端控制网页刷新
        • 注意:
          • 只有entry本身和依赖的文件才会被webpack添加到监听列表里
            • 因为webpack在启动时会以配置里的entry为入口去递归解析出entry所依赖的文件
    • 使用方法:
      • 安装:
        • npm i -D webpack-dev-server
      • 启动:
        • 执行webpack-dev-server命令:
          • npx webpack-dev-server
        • 注:启动后会一直在后台保持运行
    • 实现实时预览的方式:
      • 方式1:重新刷新网页
      • 方式2:模块热替换
        • 在不重新加载整个网页的情况下,通过将被更新过的模块替换老的模块,再重新执行一次来实现实时预览
        • 如何开启:
          • 启动devserver时带上--hot参数
  7. webpack如何开启监听模式:
    • webpack --watch
  8. webpack如何支持source map:
    • 启动时带上 --devtool source-map参数

五、webpack配置

  1. Entry:配置模块的入口
    • webpack执行构建的第一步:从入口开始搜寻及递归解析出所有入口依赖的模块
    • 配置项:
      • context
        • 默认为:执行启动webpack时所在的当前工作目录
        • 修改默认配置:
          • 方式1:context:path.resolve(_dirname,'app')
          • 方式2:命令行启动webpack时带上参数webpack --context path/filename
    • 类型:
      • string
        • 生成的chunk:一个,叫main
      • array
        • 配置output.library配置项使用时,只有数组里的最后一个入口文件的模块会被导出
        • 生成的chunk:一个,叫main
      • object
        • 生成的chunk:多个,名称为object键值对里键的名称
    • 配置动态entry:
      • 把Entry设置成一个函数去动态返回上面所说的配置
  2. Module:配置处理模块的规则
    • 配置Loader:
      • module.rules{test+use}
    • 配置不用解析和处理的模块:
      • noParse
    • 更细力度的配置哪些模板语法要解析哪些不解析
      • parser
  3. Resolve:配置webpack如何寻找模块所对应的文件
    • 配置项:
      • alias:配置通过别名来把原导入路径映射成一个新的导入路径
      • mainFields:配置优先采用的代码
      • extensions:配置在尝试过程中用到的后缀列表
      • modules:配置webpack去哪些目录下寻找第三方模块
      • description:配置描述第三方模块的文件名称
  4. devServer:
    • 配置方法:
      • 方法1:配置文件里通过devServer传入参数(通过devserver启动webpack其才能生效)
      • 方法2:通过命令行传入参数
    • 配置项:
      • hot:配置是否启用devserver中提到的模块热替换功能
        • 默认:不启用模块热替换,在发现源代码被更新后自动刷新整个页面来做到实时预览
        • 如果启用:将在不刷新整个页面的情况下通过用新模块替换老模块来做到实时预览
      • inline:配置是否自动注入代理客户端到将运行在页面里的chunk里去
      • historyApiFallback:
      • contentBase:配置devserver http服务器的文件根目录
  5. Plugin:配置扩展插件,用于扩展webpack的功能
    • 配置方法:
      • 先接入:require('要使用的plugin实例其path/filename')
      • 配置:开源社区可以找你要的plugin
  6. Output:配置如何输出最终想要的代码
    • 配置项:
      • filename:配置输出文件的名称
      • chunkFilename:配置无入口的chunk或者叫运行过程中生成的chunk在输出时的文件名称
      • path:配置输出文件存放在本地的目录
      • publicPath:配置发布到线上的URL前缀
      • crossOriginLoading:配置异步插入标签的crossorigin值
      • libraryTarget:配置以何种方式导出库
      • library:导出库的名称

五、webpack实战

  1. 使用ES6语言:
    • 使用Babel完成ES6->ES5
      • babel读取配置的位置:项目根目录下的.babelrc文件
        • 配置项:
          • plugins
            • 作用:
              • 告诉babel要使用哪些插件,插件可以控制如何转换代码
            • 选项:
              • transform-runtime(即babel-plugin-transform-runtime)
                • 作用:
                  • 不把辅助函数的内容注入到文件里。而是注入一条导入语句,减小babel编译出来的代码大小
                • 需要安装:
                  • babel-plugin-transform-runtime
                  • babel-runtime
          • Presets:
            • 作用:
              • 告诉要转换的源码使用了哪些新的语法特性
            • 本质:
              • 一组Plugins的集合(每个Plugin完成一个新语法的转换工作)
  2. 使用TS:
    • 创建tsconfig.json文件(项目根目录下):
      • 用于配置编译选项
      • 配置项:
        • compilerOptions:
          • 选项
            • "importHelpers":true
            • 作用:转换辅助函数为导入,避免了代码冗余
  3. 使用SCSS:
    • 安装:npm i -g node-sass
      • 同时要安装的依赖
        • npm i -D sass-loader css-loader style-loader node-sass
    • 编译:node-sass scss文件名 scss文件编译后的css文件名
    • 配置Loader
  4. 构建离线应用
    • 离线应用是什么:
      • 通过离线缓存技术,让资源在第一次被加载后缓存在本地,下次访问它时就直接返回本地的文件(没网也一样)
    • 离线应用的优点:
      • 没网也能打开网页
      • 提高了用户打开网页的速度
      • 减少服务器压力以及传输流量费用
    • 离线应用的核心:
      • 离线缓存技术(比如:Service Workers)
    • Service Workers:
      • 是什么:
        • 在一个浏览器后台运行的脚本
      • 特点:
        • 生命周期完全独立于网页
        • 无法直接访问DOM,但能通过postMessage接口发送消息来和UI进程通信
      • 注册service workers:
        • 调用serviceWorker.register注册
        • 注意:
          • 注册成功后,service workers会在其生命周期中派发出一些事件,通过监听对应的事件在特定的时间节点上做一些事情
      • 使用service workers实现离线缓存:
        • 监听install事件:
          • self.addEventListener('install',function(){执行缓存逻辑的代码})
            • self:当前的service workers实例
        • 监听网络请求事件去拦截请求。复用缓存
          • self.addEventListener('fetch',function(){})
      • 更新缓存:
        • 关于浏览器针对service workers的机制:
          • 每次打开接入了service workers的网页时,浏览器都会重新下载service workers的脚本文件
        • 监听activete事件:
          • self.addEventListener('activate',function(){书写清理旧缓存的逻辑代码})
    • webpack构建接入service workers的离线应用要解决的关键问题:
      • 如何生成sw.js文件,并且sw.js文件中的cacheFileList变量代表需要被缓存文件的URL列表
        • 方法:使用serviceworker-webpack-plugin插件
          • 安装:npm i -D serviceworker-webpack-plugin
  5. 检查代码:
    • 检查JS:
      • 工具:ESlint
        • 安装:npm i eslint
        • 生成ESlint配置文件.eslintrc:eslint --init
        • 检查文件:eslint yourfile.js
    • 检查TS:
      • 工具:TSLint
        • 安装:npm i tslint
        • 生成TSLint配置文件tslint.json
        • 检查文件:tslint yourfile.ts
    • 检查CSS
      • 工具:stylelint
        • 安装:npm i stylelint
        • 新建配置文件:.stylelintrc
        • 检查文件:stylelint "yourfile.css"
    • 结合webpack检查代码
      • 优点:
        • 在开发过程中通过webpack输出实时的检查结果
      • 问题:
        • webpack构建速度可能变慢(由于执行检查步骤计算量大)
      • 工具:
        • eslint-loader
        • tslint-loader
        • stylelintplugin