qugemingzizhenmafan / blog

0 stars 0 forks source link

webpack深入 #11

Open qugemingzizhenmafan opened 2 years ago

qugemingzizhenmafan commented 2 years ago
  1. 一般的loader是处理webpack默认不认识的内容,最后的loader好像是把webpack不认识的内容转化为js(主要), 例如style-loader把css转化为js?
qugemingzizhenmafan commented 2 years ago

webpack基础

功能作用

模块打包。 可以将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。利用打包我们就可以在开发的时候根据我们自己的业务自由划分文件模块,保证项目结构的清晰和可读性。

编译兼容。 在前端的“上古时期”,手写一堆浏览器兼容代码一直是令前端工程师头皮发麻的事情,而在今天这个问题被大大的弱化了,通过webpack的Loader机制,不仅仅可以帮助我们对代码做polyfill,还可以编译转换诸如.less, .vue, .jsx这类在浏览器无法识别的格式文件,让我们在开发的时候可以使用新特性和新语法做开发,提高开发效率。

能力扩展。 通过webpack的Plugin机制,我们在实现模块化打包和编译兼容的基础上,可以进一步实现诸如按需加载,代码压缩等一系列功能,帮助我们进一步提高自动化程度,工程效率以及打包输出的质量。

loader

webpack 默认支持处理 JS 与 JSON 文件,其他类型都处理不了,需要借助 Loader 来对不同类型的文件的进行处理。 module->rules->use:[style-loader, css-loader, postcss-loader, sass-loader] file-loader url-loader 类似file-loader, 小于limit转为base64 babel-loader

webpack5 asset module

module->rules->type可能值为 asset/resource 类似file-loader asset/inline dataUrl形式 以及其余两个

plugin

插件(Plugin)可以贯穿 Webpack 打包的生命周期,执行不同的任务 html-webpack-plugin clean-webapck-plugin mini-css-extract-plugin

devServer

webpack-dev-server

SourceMap

本地开发:推荐:eval-cheap-module-source-map 生产环境:推荐:(none)

三种hash值

hash :任何一个文件改动,整个项目的构建 hash 值都会改变; chunkhash:文件的改动只会影响其所在 chunk 的 hash 值; contenthash:每个文件都有单独的 hash 值,文件的改动只会影响自身的 hash 值;

打包流程

1、读取webpack的配置参数; 2、启动webpack,创建Compiler对象并开始解析项目; 3、从入口文件(entry)开始解析,并且找到其导入的依赖模块,递归遍历分析,形成依赖关系树; 4、对不同文件类型的依赖模块文件使用对应的Loader进行编译,最终转为Javascript文件; 5、整个过程中webpack会通过发布订阅模式,向外抛出一些hooks,而webpack的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。 webpack源码中主要依赖于compiler和compilation两个核心对象实现。 compiler对象是一个全局单例,他负责把控整个webpack打包的构建流程。 compilation对象是每一次构建的上下文对象,它包含了当次构建所需要的所有信息,每次热更新和重新构建,compiler都会重新生成一个新的compilation对象,负责此次更新的构建过程。 而每个模块间的依赖关系,则依赖于AST语法树。每个模块文件在通过Loader解析完成之后,会通过acorn库生成模块代码的AST语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。 最终Webpack打包出来的bundle文件是一个IIFE的执行函数。

qugemingzizhenmafan commented 2 years ago

webpack进阶

优化构建速度

构建速度分析:speed-measure-webpack-plugin

优化resolve配置

**1. alias配置别名

  1. extensions不带扩展名一一匹配解析
  2. modules告诉 webpack 优先 src 目录下查找需要解析的文件,会大大节省查找时间**
    resolve: {
    modules: [resolve('src'), 'node_modules'],
    },
  3. resolveLoader一般情况下保持默认配置就可以了,但如果你有自定义的 Loader 就需要配置一下

    externals

    从输出的 bundle 中排除依赖, 此功能通常对 library 开发人员来说是最有用的 我们可以用这样的方法来剥离不需要改动的一些依赖,大大节省打包构建的时间。

    缩小范围

    指定 loader 的作用目录或者需要排除的目录 include:符合条件的模块进行解析 exclude:排除符合条件的模块,不解析, 优先级更高 babel-loader解析src, 排除node_modules

    noParse

    使用 noParse 进行忽略的模块文件中不会解析 import、require 等语法 jquery|lodash

    IgnorePlugin

    多进程配置

    实际上在小型项目中,开启多进程打包反而会增加时间成本,因为启动进程和进程间通信都会有一定开销。 thread-loader

利用缓存

babel-loader

use: [
   {
        loader: 'babel-loader',
        options: {
            cacheDirectory: true // 启用缓存
        }
    },
]

cache-loader

缓存一些性能开销比较大的 loader 的处理结果

hard-source-webpack-plugin

为模块提供了中间缓存, webpack5 中已经内置了模块缓存,不需要再使用此插件

cache 持久化缓存

通过配置 cache 缓存生成的 webpack 模块和 chunk,来改善构建速度。

config = {
  cache: {
    type: 'filesystem',
  },
};

优化构建结果

构建结果分析

webpack-bundle-analyzer 可以直观的看到打包结果中,文件的体积大小、各模块依赖关系、文件是否重复等问题

压缩 CSS

optimize-css-assets-webpack-plugin

压缩 JS terser-webpack-plugin

在生成环境下打包默认会开启 js 压缩,但是当我们手动配置 optimization 选项之后,就不再默认对 js 进行压缩,需要我们手动去配置。 webpack5 内置了terser-webpack-plugin 插件

清除用不到的 CSS

purgecss-webpack-plugin会单独提取 CSS 并清除用不到的 CSS

Tree-shaking

webpack 默认支持,需要在 .bablerc 里面设置 model:false,即可在生产环境下默认开启

Scope Hoisting

Scope Hoisting 即作用域提升,原理是将多个模块放在同一个作用域下,并重命名防止命名冲突,通过这种方式可以减少函数声明和内存开销。 webpack 默认支持,在生产环境下默认开启 只支持 es6 代码

优化运行时体验

降低首屏加载文件体积,首屏不需要的文件进行预加载或者按需加载, 提升首屏的加载速度

入口点分割

配置多个打包入口,多页打包

splitChunks 分包配置

webpack 将根据以下条件自动拆分 chunks: 新的 chunk 可以被共享,或者模块来自于 node_modules 文件夹 新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积) 当按需加载 chunks 时,并行请求的最大数量小于或等于 30 当加载初始化页面时,并发请求的最大数量小于或等于 30

代码懒加载

import('./desc').then

预加载

<link rel="prefetch" href="/path/style.css" as="style">

prefetch

预先请求当前页需要的资源(提前加载后面会用到的关键资源) import( /* webpackPrefetch: true */ './desc').then

preload

在其他页面(非本页面)可能使用到的资源,那么浏览器会在空闲时,就去预先加载这些资源放在 http 缓存内(浏览器空闲的时候进行资源的拉取) import(/* webpackPreload: true */ 'ChartingLibrary')

qugemingzizhenmafan commented 2 years ago

tree-shaking

Tree-shaking 和 DCE 只是最终的结果是一致的,但是 2 者实现的过程不同,Tree-shaking 是保留 Live Code,而 DCE 是消除 Dead Code。 随着时间的推移,Rollup 对 Tree-shaking 的定义已经不仅仅是 ES Module 相关,此外它还支持了 DCE。 1.利用 ES Module 可以进行静态分析的特点来检测模块内容的导出、导入以及被使用的情况,保留 Live Code 2.消除不会被执行和没有副作用(Side Effect)的 Dead Code,即 DCE 过程

副作用

utils.js

export const name = "wjc";

export const sayHi = function () {
  console.log(`Hi ${name}`);
};

main.js

import { sayHi } from "./maths.js";

sayHi();

tree-shaking后

const name = "wjc";

const sayHi = function () {
  console.log(`Hi ${name}`);
};
sayHi();

可以看到,这里我们并没有直接导入 utils.js 文件中的 name 变量,但是由于在 sayHi() 函数中访问了它作用域之外的变量 name,产生了副作用,所以最后输出的结果也会有 name 变量。

AST

运用场景

编辑器的错误提示、代码格式化、代码高亮、代码自动补全; elint、pretiier 对代码错误或风格的检查; webpack 通过 babel 转译 javascript 语法;

步骤

读取 js 文件中的字符流,然后通过词法分析生成 token,之后再通过语法分析( Parser )生成 AST,最后生成机器码执行。 词法分析(分词):将整个代码字符串分割成最小语法单元tokens列表(一维数组) 语法分析:在分词基础上建立语法单元之间的关系,生成AST

qugemingzizhenmafan commented 2 years ago

babel