DayNote(Webpack)

439 阅读9分钟

截屏2021-07-30 上午9.23.34.png

webpack

静态模块打包器 (module bundler)

目标: webpack本身是, node的一个第三方模块包, 用于打包代码

截屏2021-07-30 上午9.37.20.png

  • 合并同类型文件
  • 压缩文件
  • 删除注释
  • 语法降级(将高版本语法 降级为低版本,兼容所有浏览器)

yarn

基础操作

# 初始化
yarn init -y

# 安装
yarn add 包名

yarn add 包名 --dev

# 升级
yarn upgrade 包

# 移除
yarn remove 包

webpack基础使用

image-20210421125257233.png

# 1.初始化包环境
yarn init

# 2.安装依赖包
yarn add webpack webpack-cli -D

# 3.配置scripts(自定义命令)--脚本命令 yarn build(打包文件)
scripts: {
	"build": "webpack"
}

# 4.新建目录src

# 5.新建src/add/add.js - 定义求和函数导出
export const addFn = (a, b) => a + b

# 6.新建src/index.js导入使用
import {addFn} from './add/add'

console.log(addFn(10, 20));

# 7.运行打包命令
yarn build // 相当于 yarn webpack
#或者 npm run build

# 打包完成后:src并列处, 生成默认dist目录和打包后默认main.js文件

# 静态文件夹--public/index.html

入口和出口

目标: 告诉webpack从哪开始打包, 打包后输出到哪里

默认入口: ./src/index.js

默认出口: ./dist/main.js

新建src并列处(即根目录), webpack.config.js

const path = require("path")

module.exports = {
    entry: "./src/main.js", // 入口
    output: { 
        path: path.resolve(__dirname, "dist"), // 出口路径
        filename: "bundle.js" // 出口文件名
    }
}

使用jquery

# 安装
yarn add jquery

# src/index.js 引入模块
import $ from 'jquery'

# 在 public/index.html引入打包后的js文件
<script src="../dist/main.js"></script>

Plugin | Loader

自动生成html文件 | plugin

让webpack打包后生成html文件并自动引入打包后的js

下载插件

yarn add html-webpack-plugin  -D

webpack.config.js配置

// 引入自动生成 html 的插件
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    // ...省略其他代码
    plugins: [// webpack插件配置
        new HtmlWebpackPlugin({
            template: './public/index.html' // 以此为基准生成打包后html文件
        })
    ]
}

打包后的index.html自动引入打包后的js文件

处理css文件 | loader

原因:webpack默认只认识 js 文件和 json文件

目标: loaders加载器, 可让webpack处理其他类型的文件, 打包到js中

文件位置:src/css/xxx.css

安装依赖

yarn add style-loader css-loader -D

webpack.config.js 配置

module.exports = {
    // ...其他代码
    module: { 
        rules: [ // loader的规则
          {
            test: /\.css$/, // 匹配所有的css文件
            // use数组里从右向左运行
            // 先用 css-loader 让webpack能够识别 css 文件的内容并打包
            // 再用 style-loader 将样式, 把css插入到dom中
            use: [ "style-loader", "css-loader"]
          }
        ]
    }
}

新建src/css/index.css - 去掉li默认样式

ul, li{
    list-style: none;
}

引入到src/index.js (因为这里是入口需要产生关系, 才会被webpack找到打包起来)

import "./css/index.css"

处理less文件 | loader

目标: less-loader让webpack处理less文件, less模块翻译less代码

文件所在位置:src/less/index.less

下载依赖包

yarn add less less-loader -D

webpack.config.js 配置

module: {
  rules: [ // loader的规则
    // ...省略其他
    {
    	test: /\.less$/,
    	// 使用less-loader, 让webpack处理less文件, 内置还会用less翻译less代码成css内容
        use: [ "style-loader", "css-loader", 'less-loader']
    }
  ]
}

src/less/index.less - 设置li字体大小24px

@size:24px;

ul, li{
    font-size: @size
}

引入 src/index.js中

import "./less/index.less"

处理图片文件 | loader

目标: 用asset module方式(webpack5版本新增)

文件位置:放在哪里,取什么名字都可以(src/assets/)

webpack.config.js 配置

  1. webpack5直接配置 type 注意:
  • 如果设置type为 asset
    • 小于8kb,会把图片转为base64字符串
    • 大于8kb,文件自动命名输出到dist文件下
{
    test: /\.(png|jpg|gif|jpeg)$/i,
    type: 'asset'// 匹配上面的文件,webpack会将其作为 静态资源 打包
}
  1. webpack4及以前的,在use里面配置
  • 先下载依赖包 yarn add url-loader file-loader -D
{
  test: /\.(png|jpg|gif|jpeg)$/i,
  use: [
    {
      loader: 'url-loader', // 匹配文件, 尝试转base64字符串打包到js中
      // 配置limit, 超过8k, 不转, file-loader复制, 随机名, 输出文件
      options: {
        limit: 8 * 1024,
      },
    },
  ],
}

在css/less/index.less - 把小图片用做背景图(<8kb)

  • src就是base64字符串格式
body{
    background: url(../assets/logo_small.png) no-repeat center;
}

在src/main.js - 把大图插入到创建的img标签上, 添加body上显示(>8kb)

  • src还是原地址
// 引入图片-使用
import imgUrl from './assets/1.gif'
const theImg = document.createElement("img")
theImg.src = imgUrl
document.body.appendChild(theImg)

webpack加载文件优缺点

图片转成 base64 字符串

  • 好处就是浏览器不用发请求了,直接可以读取
  • 坏处就是如果图片太大,再转base64就会让图片的体积增大 30% 左右

处理字体文件 | loader

目标: 用asset module技术, asset/resource直接输出到dist目录下

文件位置:src/assets/ - 放入字体库fonts文件夹

webpack5使用这个配置

{ // webpack5默认内部不认识这些文件, 所以当做静态资源直接输出即可
    test: /\.(eot|svg|ttf|woff|woff2)$/,
    type: 'asset/resource',
    generator: {
    	filename: 'font/[name].[hash:6][ext]'
    }
}

webpack4及以前使用下面的配置

 { // 处理字体图标的解析
     test: /\.(eot|svg|ttf|woff|woff2)$/,
         use: [
             {
                 loader: 'url-loader',
                 options: {
                     limit: 2 * 1024,
                     // 配置输出的文件名
                     name: '[name].[ext]',
                     // 配置输出的文件目录
                     outputPath: "fonts/"
                 }
             }
         ]
 }

在src/index.js引入iconfont.css

// 引入字体图标文件
import './assets/fonts/iconfont.css'

在public/index.html使用字体图标样式

<i class="iconfont icon-weixin"></i>

处理高版本js语法 | loader

目标: 让webpack对高版本 的js代码, 降级处理后打包

原因: webpack 默认仅内置了 模块化的 兼容性处理 import export

babel 的介绍 => 用于处理高版本 js语法 的兼容性 babel官网

解决: 让webpack配合babel-loader 对js语法做处理

安装包

yarn add -D babel-loader @babel/core @babel/preset-env

配置规则

module: {
  rules: [
    {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
            loader: 'babel-loader',
            options: {
                presets: ['@babel/preset-env'] // 预设:转码规则(用bable开发环境本来预设的)
            }
        }
    }
  ]
}

在src/index.js中使用 高级js语法

// 高级语法
const fn = () => {
  console.log("你好babel");
}
console.log(fn) // 这里必须调用, 不然webpack不会编译未使用的代码
// 没有babel集成时, 原样直接打包进lib/bundle.js
// 有babel集成时, 会翻译成普通函数打包进lib/bundle.js

WEBPACK 开发服务器

打包费时的原因:

  1. 构建依赖
  2. 磁盘读取对应的文件到内存, 才能加载
  3. 用对应的 loader 进行处理
  4. 将处理完的内容, 输出到磁盘指定目录

截屏2021-07-30 上午9.39.20.png 解决问题:

  1. 自动监控项目源代码(根据入口文件)

  2. 一旦 发现源代码 有改动,就会自动编译项目,将生产的结果自动保存到dist文件夹中

  3. 编译的结果 会被缓存到服务器内存

  4. 记录每个文件的hash值,一旦有任意文件发生改变,就只重新编译修改过的文件

  5. 浏览器可以直接访问 开发服务器,服务器会从dist目录中 读取内容并响应给浏览器

webpack-dev-server自动刷新

目标: 启动本地服务, 可实时更新修改的代码, 打包变化代码到内存中, 然后直接提供端口和网页访问

下载包

yarn add webpack-dev-server -D

在package.json中 配置自定义命令

scripts: {
	"build": "webpack",
	"serve": "webpack serve"
}

运行命令-启动webpack开发服务器

yarn serve
#或者 npm run serve

总结

1、什么是webpack

webpack是一个打包模块化javascript的工具,在webpack里一切文件皆模块,通过loader转换文件,通过plugin注入钩子,最后输出由多个模块组合成的文件,webpack专注构建模块化项目

2、Webpack的优点是什么?

  1. 专注于处理模块化的项目,能做到开箱即用,一步到位
  2. 通过plugin扩展,完整好用又不失灵活
  3. 通过loaders扩展, 可以让webpack把所有类型的文件都解析打包
  4. 区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展

3、webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

1. 初始化参数:从配置文件读取与合并参数,得出最终的参数
2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,开始执行编译
3. 确定入口:根据配置中的 entry 找出所有的入口文件
4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果

4、说一下 Webpack 的热更新原理

webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。

HMR的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上 WDS 与浏览器之间维护了一个 Websocket,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发起 Ajax 请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该chunk的增量更新。

后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由 HotModulePlugin 来完成,提供了相关 API 以供开发者针对自身场景进行处理,像react-hot-loader 和 vue-loader 都是借助这些 API 实现 HMR。

5、webpack与grunt、gulp的不同?

1) 三者之间的区别

三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。

grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。

webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。

2) 从构建思路来说

gulp和grunt需要开发者将整个前端构建过程拆分成多个Task,并合理控制所有Task的调用关系 webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工

3) 对于知识背景来说

gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路

6、有哪些常见的Loader?他们是解决什么问题的?

1、 file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件

2、 url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去

3、 source-map-loader:加载额外的 Source Map 文件,以方便断点调试

4、 image-loader:加载并且压缩图片文件

5、 babel-loader:把 ES6 转换成 ES5

6、 css-loader:加载 CSS,支持模块化、压缩、文件导入等特性

7、 style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。

8、 eslint-loader:通过 ESLint 检查 JavaScript 代码

7、Loader和Plugin的不同?

1) 不同的作用

Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。

Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

2) 不同的用法

Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)

Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。