ZONO's World

welcome to my world

CSS

PostCSS

PostCSS 是一种 JavaScript 工具,可将你的 CSS 代码转换为抽象语法树 (AST),然后提供 API(应用程序编程接口)用于使用 JavaScript 插件对其进行分析和修改。什么是 PostCSS?如何使用插件自动化 CSS 任务 - 掘金 (juejin.cn)

Tailwind CSS

理解为内联的升级版,效用至上的基础 - Tailwind CSS 中文网 (nodejs.cn),里面有讲为什么不用内联

js

ESLint

Lint(Linter) 是一种静态代码分析工具,用于标记代码中某些编码错误、风格问题和不具结构性(易导致 bug)的代码。

主要是在运行时报错,可以通过插件来实现实时检测。

Install

手动下载npm i eslint -D

脚手架下载时配置

基本用法

一些rule

vscode中配置ESLint 和配置中文_vscode使用esline 错误提示如何显示中文-CSDN博客

TODO 以后细学

全部

Prettier

Prettier 是一个代码格式化工具,可以格式化代码,但不具备代码检查功能,它可以通过解析代码并使用自己的规则重新打印它,并考虑最大行长来强制一致的样式,并在必要时包装代码,如今,它已成为解决所有代码格式问题的优选方案,支持多种语言,可以将 ESLint 和 Prettier 结合使用,提高代码质量。

前端代码格式化 - 【Prettier】 - 常见配置 + 踩坑日记 - 掘金 (juejin.cn)

Webpack「v5.0」

概念 | webpack 中文文档 (docschina.org)
webpack是一个现代JavaScript应用程序的静态模块打包工具。当webpack处理应用程序时,它会在内部构建一个依赖图(dependency [/dɪˈpendənsi/] graph [/ɡræf/]),此依赖图会映射项目所需的每个模块,并生成一个或多个bundle /ˈbʌndl/ 包!

0. 预备知识

0.1 为啥要学webpack?

0.1.1 性能优化

见性能优化

之前我们在讲前端的时候,我们可以从以下几个方面,去提高页面第一次渲染的速度,以及运行时的性能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/* 
第一类:明显改善页面第一次加载的速度,减少白屏等待的时间
@1 使用骨架屏技术
+ 服务器骨架屏:页面首屏内容是基于服务器渲染的
+ 前端骨架屏:在真实内容渲染出来之前,我们给予相关位置用“色框”占位!(知乎?)
@2 减少HTTP请求的次数和大小
+ CSS/JS都要做合并压缩「尽可能合并为一个CSS和一个JS」
+ 图片的合并压缩,例如:雪碧图(CSS Sprit)
+ 使用图片BASE64来加快图片的渲染!
+ 图片一定要做延迟加载
+ 使用字体图片和矢量图,来代替位图!!
+ 音视频资源也要设置延迟加载「preload='none'」
+ 数据的异步加载
+ 开启服务器端的GZIP压缩,可以让访问的资源压缩60%+
@3 渲染页面中的优化
+ 因为<script>会阻碍GUI渲染,所以:把其放在页面末尾,或者设置async/defer!
+ 因为<link>是异步加载CSS资源,所以建议放在页面开始,尽快获取样式资源!!
+ 不要使用import导入CSS,因为其会阻碍GUI的渲染!
+ 样式代码较少的情况下,使用<style>内嵌式,尤其是移动端开发!
@4 在网络传输中的优化
+ 减少cookie的内容大小「因为只要向服务器发送请求,不论服务器是否需要,总会在请求头中把cookie传递给服务器,如果cookie比较大,会让所有的请求都变慢」
+ 资源分服务器部署「例如:web服务器、图片服务器、数据服务器」,这样可以降低服务器压力,提高服务器的并发,让资源能更加合理的被利用;但是也会导致DNS解析次数增加,此时可以基于DNS Prefetch来优化DNS解析!!
+ 基于HTTP/2.0来代替HTTP/1.1
+ 基于新的二进制格式,让传输的内容更加丰富健壮
+ header压缩,让传输速度更快(没改就不传)
+ 服务端自动推送,可以减少HTTP请求次数
+ 多路复用,让传输速度更快,避免线头阻塞(UDP)
+ 基于Connection:keep-alive保持TCP通道长链接「HTTP/1.1版本会自动开启」
+ 开启CDN「地域分布式服务器部署」
+ 对于静态资源文件采取“强缓存和协商缓存”,对于不经常更新的数据请求,设置数据缓存!

第二类:提高页面运行时候的性能
@1 减少循环嵌套,降低时间复杂度;避免出现死循环/死递归;
@2 使用事件委托来优化事件绑定,性能可以提高40%+
@3 减少DOM的回流(重排)和重绘
+ 样式分离读写「渲染队列机制」
+ 批量新增元素「字符串拼接、文档碎片」
+ 基于transform/opacity等方式操作样式
+ 把需要频繁修改样式的元素(例如:JS实现动画)脱离文档流
+ ...
@4 使用函数的防抖和节流处理高频触发操作
@5 合理使用闭包,避免内存泄漏,以及手动释放无用的内存!
@6 减少页面冗余代码,提高代码的重复使用率「也就是尽可能的做封装处理」
@7 尽可能不要使用for/in循环,因为其消耗性能
@8 避免使用eval/with等消耗性能的代码
@9 能用CSS3处理的动画坚决不用JS「JS动画尽可能基于requestAnimationFrame来代替定时器」
@10 避免使用CSS表达式,因为其非常消耗性能
@11 CSS选择器的前缀不要过长「因为CSS选择器渲染是从右到左」
@12 减少table布局「table的渲染是比较消耗性能的」
......
*/

我们

0.1.2为了兼容、预编译、开发预览

  • 平时开发的时候,一般会使用less/sass/stylus等CSS预编译器「需要基于vscode插件把其编译为CSS」;

  • 会直接使用ES6的语法「需要基于babel把其转换为ES5,以此兼容IE」;

  • 会给CSS3样式加很多的前缀,以此来处理兼容问题……

  • 我们还会基于vscode中的liveserver插件,创建一个本地web服务器,来预览我们的项目…..
    我们还要基于各种方案,来解决跨域访问的问题……

0.2 webpack可以帮我们干的事情

  • 代码转换:TypeScript编译成JavaScript、LESS/SCSS编译成CSS、ES6/7编译为ES5、虚拟DOM编译为真实的DOM等等…
  • 文件优化:压缩JS、CSS、HTML代码,压缩合并图片,图片BASE64等
  • 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码等
  • 模块合并:把模块分类合并成一个文件
  • 自动刷新:创建本地Web服务器,监听本地源代码的变化,自动重新构建,刷新浏览器
  • 代码校验:Eslint代码规范校验和检测、单元测试等
  • 自动发布:自动构建出线上发布代码并传输给发布系统
  • 跨域处理
  • ……

除了webpack外的其他:

  • grunt(淘汰)
  • gulp(少了、老了)
  • Parcel
  • vite(底层原理是rollup,比webpack快,但兼容不好)
  • rollup
  • Turbopack(据说比webpack快700倍,比vite快10倍)
  • ……

webpack问题

  • 项目“比较大”时,由于底层,打包速度比较慢。

1.webpack打包原理

2.webpack的基础操作

安装

为防止全局安装webpack导致版本冲突,真实项目中以本地安装为主
弊端:本地安装就需要配置webpack命令
npm比较慢建议使用yarn、pnmp

1
2
3
4
$ npm init -y
$ npm install webpack webpack-cli --save-dev
OR
$ yarn add webpack webpack-cli -D

零配置使用

1
2
3
4
5
6
/*
* 默认会打包SRC目录中的JS文件(入口默认index.js)
* 打包完成的目录默认是DIST/MAIN.JS
* webpack默认支持CommonJS和ES6 Module的模块规范,依此进行依赖打包
*/
$ npx webpack

自定义基础配置

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Node内置的路径处理模块
const path = require('path');

// 导出自定义配置项
module.exports = {
// 环境模式「生产环境:production 开发环境:development」
mode: 'production',
// 打包入口「相对路径」
entry: './src/index.js',
// 打包出口
output: {
// 生成的文件名. [hash]创建随机哈希值(方便缓存机制)
filename: 'bundle.[hash].js',
// 打包地址「绝对路径」
path: path.resolve(__dirname, 'dist')
}
};

html-webpack-plugin

https://www.webpackjs.com/plugins/html-webpack-plugin/
$ yarn add html-webpack-plugin -D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
// 指定视图模板
template: './public/index.html',
// 编译后视图的名字
filename: 'index.html',
// 是否压缩
minify: true
})
]
}

多入口 & 多出口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const HtmlWebpackPlugin = require('html-webpack-plugin');
// HtmlWebpackPlugin需要配置多套
const htmlPlugins = ['index', 'login'].map(chunk => {
return new HtmlWebpackPlugin({
template: `./public/${chunk}.html`,
filename: `${chunk}.html`,
// 指定导入的JS
chunks: [chunk],
minify: true
});
});
module.exports = {
mode: 'production',
// 配置多入口
entry: {
index: "./src/index.js",
login: "./src/login.js",
},
// 出口采用相同的规则
output: {
filename: "[name].[hash].js",
path: path.resolve(__dirname, "dist")
},
plugins: [
...htmlPlugins
]
};

clean-webpack-plugin

$ yarn add clean-webpack-plugin -D

1
2
3
4
5
6
7
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
...
plugins: [
new CleanWebpackPlugin()
]
};

webpack-dev-server

https://webpack.js.org/configuration/dev-server/
$ yarn add webpack-dev-server -D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* paclage.json */
"scripts": {
"start": "webpack server",
"build": "webpack"
}

/* webpack.config.js */
module.exports = {
...
devServer: {
// 域名
host: '127.0.0.1',
// 断口号
port: 3000,
// GZIP压缩
compress: true,
// 自动打开浏览器
open: true,
// 热更新
hot: true,
// 跨域代理
proxy: {
"/jian": {
target: "https://www.jianshu.com/asimov",
changeOrigin: true,
ws: true,
pathRewrite: { "^/jian": "" }
},
"/zhi": {
target: "https://news-at.zhihu.com/api/4",
changeOrigin: true,
ws: true,
pathRewrite: { "^/zhi": "" }
}
}
}
};
/*
测试接口
简书:
https://www.jianshu.com/asimov/subscriptions/recommended_collections
知乎:
https://news-at.zhihu.com/api/4/news/latest
*/

处理样式的loader「加载器」

$ yarn add css-loader style-loader less less-loader autoprefixer postcss-loader -D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
...
/* 配置模块加载器LOADER,执行顺序:从右向左、从下向上 */
module: {
rules: [{
test: /\.(css|less)$/, // 基于正则匹配哪些模块需要处理
use: [
"style-loader", // 把CSS插入到HEAD中
"css-loader", // 编译解析@import/URL()这种语法
"postcss-loader", // 设置前缀
"less-loader" // 把LESS编译为CSS
]
}]
}
};

postcss.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module.exports = {
plugins: [
require('autoprefixer')
]
};

// 或者在配置项中直接处理
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
require('autoprefixer')
]
}
}
},

package.json OR .browserslistrc

1
2
3
4
5
6
// https://github.com/browserslist/browserslist
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]

mini-css-extract-plugin 抽离CSS样式 /ˈekstrækt/

https://www.npmjs.com/package/mini-css-extract-plugin
$ yarn add mini-css-extract-plugin -D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
...
plugins: [
...
new MiniCssExtractPlugin({
// 设置编译后的文件名字
filename: 'main.[hash].css'
})
],
...
module: {
rules: [{
test: /\.(css|less)$/,
use: [
// 使用插件中的LOADER代替STYLE方式
MiniCssExtractPlugin.loader,
...
]
}]
}
};

基于babel实现ES6的转换

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

$ yarn add @babel/polyfill

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
...
module: {
rules: [{
test: /\.js$/,
use: ['babel-loader'],
// 设置编译时忽略的文件和指定编译目录
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}]
}
};

babel.config.js

1
2
3
4
5
module.exports = {
presets: [
"@babel/preset-env"
]
};

index.js

1
import '@babel/polyfill';

设置优化项:压缩CSS/JS

$ yarn add css-minimizer-webpack-plugin terser-webpack-plugin -D

1
2
3
4
5
6
7
8
9
10
11
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: {
// 设置压缩方式
minimizer: [
new CssMinimizerWebpackPlugin(),
new TerserPlugin()
]
}
};

设置解析器:配置别名

1
2
3
4
5
6
7
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
};

图片的处理

$ yarn add file-loader url-loader -D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|jpe?g|gif)$/i,
type: 'javascript/auto',
use: [{
// 把指定大小内的图片BASE64
loader: 'url-loader',
options: {
limit: 200 * 1024,
esModule: false,
name: 'images/[name].[hash].[ext]'
}
}]
}]
},
// 设置打包的最大资源大小
performance: {
maxAssetSize: 100 * 1024 * 1024 * 1024,
maxEntrypointSize: 100 * 1024 * 1024 * 1024
}
};

Babel 是一个 JavaScript 编译器。可以把使用ES6/ES7等“高级”语法编写的Javascript代码转换为ES5/ES3的“通俗”语法(也可以把JSX语法转为Javascript)。

前端性能优化思路

浏览器→资源→图片→代码层面

web前端性能优化(全汇总) - 掘金 (juejin.cn)

优化模块

1. 浏览器

1.1 减少HTTP请求

如Chrome浏览器最多同时允许对同一个域名Host建立6个TCP连接,不同的浏览器有所区别,减少http请求也就是减少我们html里css/js等资源的数量

1.2 使用HTTP2.0

http2.0优势:

  1. 采用二进制格式传输数据, 1.1是文本格式
  2. 对消息头采用Hpack进行压缩传输,能够节省消息头占用的网络流量,1.1每次请求,都会携带大量冗余的头信息,浪费了很多宽带资源
  3. 异步连接多路复用
  4. Server Push,服务器端能够更快的把资源推送到客户端
  5. 保持与HTTP 1.1语义的向后兼容性也是该版本的一个关键

1.3 设置浏览器缓存策略

1.4 白屏时间加载动画

用户体验

2. 资源

2.1 静态资源CDN

2.2 静态资源单独域名

2.3 gzip压缩

2.4 做服务端渲染(SSR)

2.5 将CSS放在文件头部,JavaScript文件放在底部

涉及到了浏览器的运行流程了

3. 图片

3.1 字体图标代替图片图标

3.2 精灵图

3.3 图片懒加载

金字塔

3.4 图片预加载

3.5 使用png格式的图片

3.6 小于10k的图片可以打包为base64格式

4. 代码

4.1 慎用全局变量

4.2 缓存全局变量

4.3 减少重绘回流

4.4 节流、防抖

4.5 少用闭包、减少内存泄漏

4.6 减少数据读取次数

4.7 文档碎片优化节点添加

4.8 减少判断层级

4.9 字面量与构造式

5. 项目方案提议

5.1 长列表优化

5.2 web worker

5.3 避免 ifarme 嵌套网页

6.webpack优化

6.1 减小代码体积

6.2 按需加载

6.3 提取第三库代码

6.4 webpack dll优化

前端性能优化

优化目标

pass

前端性能评估

2-5-8原则

GOOGLE建议

  • 页面加载时间(Page Load Time)
  • 首屏加载时间(First Contentful Paint):FCP

FCP>=FP

  • 用户可交互时间:
  • 白屏时间:FP,首次绘制时间
1
whidow.performance.getEntriesByType('paint')[0].startTime
  • 资源文件大小

性能指标计算方法(RATL)

RAILResponseAnimationIdleLoad 的首字母缩写

具体细节

浅谈前端性能指标

加载性能

  • First Meaning Paint(FMP):首次关键内容绘制,指浏览器渲染出第一个关键内容的时间。
  • Largest Contentful Paint(LCP):最大内容绘制
  • Time to Interactive:(TTI):可交互时间

渲染性能

前端性能检测工具

performance

深入react

1. react合成事件(react18中不再使用)

javascript - 探索 React 合成事件 - 前端自习课 - SegmentFault 思否

存在原因:兼容、垃圾回收

前置知识树

  1. 事件池:是浏览器事件处理中,为了节省内存和提高性能,对事件对象的重复利用。

    (待细看)React 合成事件系统之事件池 - 掘金 (juejin.cn)

  2. 生命周期(待看)

    一看就懂的React生命周期 - 掘金 (juejin.cn)

    看样子react生命周期已经被取代了【精选】【React全解4】useEffect–在函数组件中使用生命周期函数_react useeffect 生命周期-CSDN博客

2. 理解fiber

React 的 Fiber 树是什么? - 掘金 (juejin.cn)

React Fiber是什么 - 知乎 (zhihu.com)

前置知识树

  1. 轻松学会 React 钩子:以 useEffect() 为例 - 阮一峰的网络日志 (ruanyifeng.com)

  2. 什么是DOM?你了解DOM树吗?-CSDN博客

  3. 虚拟dom:React 的虚拟 DOM 使用以 JavaScript 对象为基础的结构,而 Vue 的虚拟 DOM 使用以 VNode 对象为基础的结构。

    Vue 虚拟 DOM 搞不懂?这篇文章帮你彻底搞定虚拟 DOM - 掘金 (juejin.cn)

3. React hook

React Hooks 入门教程 - 阮一峰的网络日志 (ruanyifeng.com)

3.2 useState

一些理解:快照

3.1memo

用代码实验的方式,让你彻底理解React.memo-哔哩哔哩

用于优化,避免因为别的组件被渲染了,它就渲染

​ useMemo和memo的区别

3.2 实现原理

4. redux

Umi

前置知识:

  • react
  • dva

学一个框架:

  • 脚手架相关配置
  • 路由处理
  • 数据的处理
  • 其他就是react的功能

介绍

Umi 介绍 (umijs.org)

MFSU:吹牛,改错了会自己退出

Umi更多的是对路由的处理

搭建

  • 配置环境,.env和在package.json中两种办法:可以配置ip和端口
  • umirc换成config

细节——配置

路由

配置路由、约定路由

Umi

前置知识:

  • react
  • dva

学一个框架:

  • 脚手架相关配置
  • 路由处理
  • 数据的处理
  • 其他就是react的功能

介绍

Umi 介绍 (umijs.org)

MFSU:吹牛,改错了会自己退出

Umi更多的是对路由的处理

搭建

  • 配置环境,.env和在package.json中两种办法:可以配置ip和端口
  • umirc换成config

细节——配置

路由

配置路由、约定路由

Next.js

前置知识

  • ESlent

  • webpack

  • Tailwind CSS

  • 必须使用打包程序(例如 webpack)打包代码,并使用 Babel 等编译器进行代码转换。

  • 你需要针对生产环境进行优化,例如代码拆分。

  • 你可能需要对一些页面进行预先渲染以提高页面性能和 SEO。你可能还希望使用服务器端渲染或客户端渲染。

  • 你可能必须编写一些服务器端代码才能将 React 应用程序连接到数据存储。

面试问题

  1. 事件轮询机制?

异步

阮一峰大佬写的异步操作

要说异步我们先来讲讲为什么要异步?
单线程是JavaScript的核心,js本身速度很快,但它的输入输出慢(也就是Ajax网络请求等),因为js是单线程如果有什么地方卡住了,那对于整个浏览器就会出现“卡死的情况”。于是为了解决这个问题就出现了“事件循环(Event Loop)”机制。

异步的概念

要理解异步,我们就得把同步拿过来。同步就是按顺序一个一个做,异步就是同时做。(简单理解咯)

异步的实现——事件轮询

定时器setTimeout()、setInterval()详解

定时器
**setTimeout()**用于在指定的毫秒数后调用函数或计算表达式

**setInterval()**在播放动画的时,每隔一定时间就调用函数,方法或对象

用处:节流、防抖

回调函数

promise

0%