-
Notifications
You must be signed in to change notification settings - Fork 2
/
feed.json
306 lines (306 loc) · 316 KB
/
feed.json
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
{
"version": "https://jsonfeed.org/version/1",
"title": "花圃",
"subtitle": "理想的种子,于现实中绽放",
"icon": "https://zimu-66ccff.github.io/images/favicon.ico",
"description": "干净澄澈,真诚自然",
"home_page_url": "https://zimu-66ccff.github.io",
"items": [
{
"id": "https://zimu-66ccff.github.io/jsx/",
"url": "https://zimu-66ccff.github.io/jsx/",
"title": "react源码系列(一) jsx的转换",
"date_published": "2024-05-07T16:41:10.000Z",
"content_html": "<h1 id=\"我们写的-jsx-最后变成了什么样子\"><a class=\"anchor\" href=\"#我们写的-jsx-最后变成了什么样子\">#</a> 我们写的 JSX 最后变成了什么样子</h1>\n<h2 id=\"react17-之前\"><a class=\"anchor\" href=\"#react17-之前\">#</a> React17 之前</h2>\n<h3 id=\"利用-babel-将-jsx-转换成-reactcreateelement-的函数的形式从而转换成-reactelement\"><a class=\"anchor\" href=\"#利用-babel-将-jsx-转换成-reactcreateelement-的函数的形式从而转换成-reactelement\">#</a> 利用 babel 将 JSX 转换成 React.createElement 的函数的形式,从而转换成 ReactElement</h3>\n<ol>\n<li>原始的 jsx 代码</li>\n</ol>\n<figure class=\"highlight html\"><figcaption data-lang=\"HTML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span><span class=\"token punctuation\">></span></span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>TextComponent</span> <span class=\"token punctuation\">/></span></span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>div</span><span class=\"token punctuation\">></span></span>hello,world<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> let us learn React!</pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>div</span><span class=\"token punctuation\">></span></span></pre></td></tr></table></figure><ol start=\"2\">\n<li>babel 转换之后的形式</li>\n</ol>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>React<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token string\">'div'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> React<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span>TextComponent<span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> React<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">'div'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'hello,world'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token string\">'let us learn React!'</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure><p><strong>ps: 因为用到了 React.createElement 所以早起的 React 才要求必须引入 React</strong></p>\n<ol start=\"3\">\n<li>React.createElement 执行之后得到的 ReactElement 的形式</li>\n</ol>\n<h2 id=\"react17-之后\"><a class=\"anchor\" href=\"#react17-之后\">#</a> React17 之后</h2>\n<h3 id=\"利用-babel-将-jsx-转换成_jsx-函数的形式从而转换成-reactelement\"><a class=\"anchor\" href=\"#利用-babel-将-jsx-转换成_jsx-函数的形式从而转换成-reactelement\">#</a> 利用 babel 将 JSX 转换成_jsx 函数的形式,从而转换成 ReactElement</h3>\n<ol>\n<li>原始的 jsx 代码</li>\n<li>babel 转换之后的形式</li>\n<li>_jsx 执行之后得到的 ReactElement 的形式</li>\n</ol>\n<h1 id=\"reactelement-的类型定义\"><a class=\"anchor\" href=\"#reactelement-的类型定义\">#</a> ReactElement 的类型定义</h1>\n<h1 id=\"reactcreateelement-函数实现\"><a class=\"anchor\" href=\"#reactcreateelement-函数实现\">#</a> React.createElement 函数实现</h1>\n<h1 id=\"_jsx-函数实现\"><a class=\"anchor\" href=\"#_jsx-函数实现\">#</a> _jsx 函数实现</h1>\n",
"tags": [
"笔记",
"前端",
"React",
"React源码学习",
"前端",
"React",
"React源码"
]
},
{
"id": "https://zimu-66ccff.github.io/sdkSumary/",
"url": "https://zimu-66ccff.github.io/sdkSumary/",
"title": "前端埋点sdk搭建实践总结",
"date_published": "2024-03-31T06:23:47.000Z",
"content_html": "<h1 id=\"前端埋点-sdk-搭建实践总结\"><a class=\"anchor\" href=\"#前端埋点-sdk-搭建实践总结\">#</a> 前端埋点 sdk 搭建实践总结</h1>\n<h2 id=\"前端搭建监控体系是为了什么\"><a class=\"anchor\" href=\"#前端搭建监控体系是为了什么\">#</a> 前端搭建监控体系是为了什么?</h2>\n<h3 id=\"及时发现问题\"><a class=\"anchor\" href=\"#及时发现问题\">#</a> 及时发现问题</h3>\n<ol>\n<li>能够通过收集的性能指标,及时发现存在的性能问题</li>\n<li>能够通过白屏监控,及时发现出现了白屏问题</li>\n<li>能够通过通过 pv,uv 的变化,及时发现活跃量的变化;通过用户行为的监控,收集到用户的行为信息,从而进行针对性推荐和优化</li>\n<li>能够异常上报,及时发现各种异常、</li>\n<li>能够通过接口调用情况监控,及时发现流量大的后端服务,高频出错的后端服务</li>\n</ol>\n<h3 id=\"精确定位问题\"><a class=\"anchor\" href=\"#精确定位问题\">#</a> 精确定位问题</h3>\n<ol>\n<li>通过收集的页面加载事件的关键时间段,精准的定位到首屏时间主要是卡在哪个时间段</li>\n<li>通过用户行为,路由跳转的监控,及时定位到发生错误前后用户的操作,助力错误重现,修复</li>\n<li>通过异常监控,准确定位到发生错误的原因,所在文件,行,列,</li>\n<li>通过接口调用情况监控,及时定位出错的后端服务</li>\n</ol>\n<p>总结起来就简单的两句话 <code>如何及时的发现问题</code> , <code>如何准确的定位问题</code></p>\n<h2 id=\"前端监控需要监控哪些模块\"><a class=\"anchor\" href=\"#前端监控需要监控哪些模块\">#</a> 前端监控需要监控哪些模块</h2>\n<h3 id=\"性能监控\"><a class=\"anchor\" href=\"#性能监控\">#</a> 性能监控:</h3>\n<h4 id=\"性能监控究竟要监控什么数据从哪里入手\"><a class=\"anchor\" href=\"#性能监控究竟要监控什么数据从哪里入手\">#</a> 性能监控究竟要监控什么数据,从哪里入手?</h4>\n<h5 id=\"用户体验为王以用户为中心的性能指标\"><a class=\"anchor\" href=\"#用户体验为王以用户为中心的性能指标\">#</a> 用户体验为王,以用户为中心的性能指标:</h5>\n<h6 id=\"加载速度-用户什么时候可以感受到界面开始加载加载完成\"><a class=\"anchor\" href=\"#加载速度-用户什么时候可以感受到界面开始加载加载完成\">#</a> <code>加载速度</code> 用户什么时候可以感受到界面开始加载,加载完成:</h6>\n<ol>\n<li>\n<p>FP:首次非网页背景像素渲染的时间</p>\n<ul>\n<li>\n<p>建议改为收集 FCP</p>\n</li>\n<li>\n<p><strong>采集方法</strong>:</p>\n</li>\n<li>\n<ol>\n<li>\n<p>基于 PerformanceObserver</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">new</span> <span class=\"token class-name\">PerformanceObserver</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>entryList<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> entry <span class=\"token keyword\">of</span> entryList<span class=\"token punctuation\">.</span><span class=\"token function\">getEntriesByName</span><span class=\"token punctuation\">(</span><span class=\"token string\">'first-paint'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fp'</span><span class=\"token punctuation\">,</span> entry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">observe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'paint'</span><span class=\"token punctuation\">,</span> buffered<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n</ol>\n</li>\n</ul>\n</li>\n<li>\n<p>FCP:首次内容渲染的时间</p>\n<ul>\n<li>\n<p>收集的原因:用户首次感知到界面开始有东西</p>\n</li>\n<li>\n<p><strong>采集方法</strong>:</p>\n</li>\n<li>\n<ol>\n<li>基于 PerformanceObserver</li>\n</ol>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">new</span> <span class=\"token class-name\">PerformanceObserver</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>entryList<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> entry <span class=\"token keyword\">of</span> entryList<span class=\"token punctuation\">.</span><span class=\"token function\">getEntriesByName</span><span class=\"token punctuation\">(</span><span class=\"token string\">'first-contentful-paint'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fcp'</span><span class=\"token punctuation\">,</span> entry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">observe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'paint'</span><span class=\"token punctuation\">,</span> buffered<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n<li>\n<ol start=\"2\">\n<li>基于 web-vitals 包</li>\n</ol>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> getFCP <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'web-vitals'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\">// 当 FCP 可用时立即进行测量和记录。</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">getFCP</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n</ul>\n</li>\n<li>\n<p>LCP:可视区域的最大图像或者文本块渲染出来的时间</p>\n<ul>\n<li>\n<p>收集的原因:用户觉得页面基本上块渲染完毕的时间</p>\n</li>\n<li>\n<p><strong>采集方法</strong></p>\n</li>\n<li>\n<ol>\n<li>\n<p>基于 PerformanceObserver</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">new</span> <span class=\"token class-name\">PerformanceObserver</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>entryList<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token keyword\">const</span> entries <span class=\"token operator\">=</span> entryList<span class=\"token punctuation\">.</span><span class=\"token function\">getEntries</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token keyword\">const</span> entry <span class=\"token operator\">=</span> entries<span class=\"token punctuation\">[</span>entries<span class=\"token punctuation\">.</span>length <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'lcp'</span><span class=\"token punctuation\">,</span> entry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">observe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'largest-contentful-paint'</span><span class=\"token punctuation\">,</span> buffered<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n<li>\n<p>基于 web-vitals 包</p>\n<pre><code>import { getLCP } from 'web-vitals';\n// 当 LCP 可用时立即进行测量和记录。\ngetLCP(console.log);\n\n</code></pre>\n</li>\n</ol>\n</li>\n<li></li>\n</ul>\n</li>\n</ol>\n<h6 id=\"交互延迟-用户什么时候可以感受到界面可以开始交互交互后需要等待多久才有回应\"><a class=\"anchor\" href=\"#交互延迟-用户什么时候可以感受到界面可以开始交互交互后需要等待多久才有回应\">#</a> <code>交互延迟</code> 用户什么时候可以感受到界面可以开始交互,交互后需要等待多久才有回应:</h6>\n<ol>\n<li>\n<p>FID:用户首次于页面交互到浏览器做出相应开始执行时间处理程序的经过的时间</p>\n<ul>\n<li>\n<p>收集的原因:用户的第一次交互往往是很重要的,第一次交互迟迟没有响应,用户就可能放弃</p>\n</li>\n<li>\n<p><strong>采集方法</strong>:</p>\n</li>\n<li>\n<ol>\n<li>\n<p>基于 PerformanceObserver</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">new</span> <span class=\"token class-name\">PerformanceObserver</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>entryList<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token keyword\">const</span> entries <span class=\"token operator\">=</span> entryList<span class=\"token punctuation\">.</span><span class=\"token function\">getEntries</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token keyword\">const</span> entry <span class=\"token operator\">=</span> entries<span class=\"token punctuation\">[</span>entries<span class=\"token punctuation\">.</span>length <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token keyword\">const</span> delay <span class=\"token operator\">=</span> entry<span class=\"token punctuation\">.</span>processingStart <span class=\"token operator\">-</span> entry<span class=\"token punctuation\">.</span>startTime<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'FID:'</span><span class=\"token punctuation\">,</span> delay<span class=\"token punctuation\">,</span> entry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">observe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'first-input'</span><span class=\"token punctuation\">,</span> buffered<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n<li>\n<p>基于 web-vitals</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> getFID <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'web-vitals'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\">// 当 FID 可用时立即进行测量和记录。</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">getFID</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n</ol>\n</li>\n</ul>\n</li>\n<li>\n<p>INP:页面生命周期中用户与网页交互中最长的一次持续时间</p>\n<ul>\n<li>\n<p>收集的原因:用户浏览网页过程中,如果存在某次交互迟迟没有响应,用户就可能放弃</p>\n</li>\n<li>\n<p><strong>采集方法:</strong></p>\n</li>\n<li>\n<ol>\n<li>\n<p>基于 web-vitals</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> getINP <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'web-vitals'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\">// 当 INP 可用时立即进行测量和记录。</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">getINP</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n</ol>\n</li>\n</ul>\n</li>\n<li>\n<p>TTI:最早可交互时间:</p>\n<ul>\n<li>\n<p><strong>详细定义</strong>:</p>\n</li>\n<li>\n<p>TTI 指标用于衡量从网页开始加载到其主要子资源加载完成所用的时间,并且能够快速可靠地响应用户输入</p>\n</li>\n<li>\n<p><strong>标准计算方式</strong>:</p>\n</li>\n<li>\n<ol>\n<li>从 FCP 开始。</li>\n<li>向前搜索一个至少 5 秒的静默窗口,其中<em>静默窗口</em>的定义为:没有长任务且不超过两个进行中的网络 GET 请求。</li>\n<li>向后搜索静默窗口之前的最后一个长任务,如果找不到长任务,则停止在 FCP 处停止。</li>\n<li>TTI 是安静窗口之前的最后一个长任务的结束时间(如果未找到长任务,则与 FCP 值相同)。</li>\n</ol>\n<p><strong>开发中的计算方式:</strong></p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">const</span> navigation <span class=\"token operator\">=</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token comment\">// W3C Level2 PerformanceNavigationTiming</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token comment\">// 使用了 High-Resolution Time,时间精度可以达毫秒的小数点好几位。</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> performance<span class=\"token punctuation\">.</span><span class=\"token function\">getEntriesByType</span><span class=\"token punctuation\">(</span><span class=\"token string\">'navigation'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>length <span class=\"token operator\">></span> <span class=\"token number\">0</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token operator\">?</span> performance<span class=\"token punctuation\">.</span><span class=\"token function\">getEntriesByType</span><span class=\"token punctuation\">(</span><span class=\"token string\">'navigation'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token operator\">:</span> performance<span class=\"token punctuation\">.</span>timing<span class=\"token punctuation\">;</span> <span class=\"token comment\">// W3C Level1 (目前兼容性高,仍然可使用,未来可能被废弃)。</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token constant\">TTI</span> <span class=\"token operator\">=</span> navigation<span class=\"token punctuation\">.</span>domInteractive <span class=\"token operator\">-</span> navigation<span class=\"token punctuation\">.</span>fetchStart<span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n</ul>\n<blockquote>\n<p><strong>注意</strong>:是一项实验室指标,虽然可以衡量现场 TTI,但不建议这样做,因为用户互动可能会对网页的 TTI 造成影响,导致报告中出现大量差异。若要了解网页在该字段中的互动情况,应该衡量 INP。</p>\n</blockquote>\n</li>\n</ol>\n<h6 id=\"视觉稳定界面视觉上的变化对用户造成的负面影响大小\"><a class=\"anchor\" href=\"#视觉稳定界面视觉上的变化对用户造成的负面影响大小\">#</a> <code>视觉稳定</code> :界面视觉上的变化对用户造成的负面影响大小</h6>\n<ol>\n<li>\n<p>CLS:网页生命周期内发生的每次意外布局偏移的最大<em>布局偏移得分</em>,每当一个已渲染的可见元素的位置从一个可见位置变更到下一个可见位置时,就发生了 <strong>布局偏移</strong></p>\n<ul>\n<li>\n<p>收集的原因:用户很讨厌页面布局偏移过大,比如,当用户点击一个按钮的时候,突然按钮的位置变了,导致用户点到了其他的东西,比如广告之类的。</p>\n</li>\n<li>\n<p><strong>采集方法:</strong></p>\n</li>\n<li>\n<ol>\n<li>\n<p>基于 web-vitals:</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> getCLS <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'web-vitals'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token comment\">// 当 CLS 可用时立即进行测量和记录。</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token function\">getCLS</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n</ol>\n</li>\n</ul>\n</li>\n</ol>\n<h5 id=\"精准定位问题以技术为中心的关键时间点时间段\"><a class=\"anchor\" href=\"#精准定位问题以技术为中心的关键时间点时间段\">#</a> 精准定位问题,以技术为中心的关键时间点,时间段:</h5>\n<h6 id=\"页面加载过程关键数据获取方式\"><a class=\"anchor\" href=\"#页面加载过程关键数据获取方式\">#</a> 页面加载过程关键数据获取方式:</h6>\n<p>利用 <code>performance.getEntriesByType('navigation')[0]</code> or <code>performance.timing</code> (如果前者浏览器不支持,使用这个) 得到的数据对象身上的字段:</p>\n<p><code>navigationStart</code> :表示上一个文档卸载结束时的 unix 时间戳,如果没有上一个文档,则等于 fetchStart。</p>\n<p><code>unloadEventStart</code> :表示前一个网页(与当前页面同域)unload 的时间戳,如无前一个网页 unloade 或前一个网页与当前不同域,则为 0。</p>\n<p><code>unloadEventEnd</code> : 返回前一个 unload 时间绑定的回调执行完毕的时间戳。</p>\n<p><code>redirectStart</code> :前一个 Http 重定向发送时的时间。有跳转且是同域名内重定向,否则为 0。</p>\n<p><code>redirectEnd</code> :前一个 Http 重定向完成时的时间。有跳转且是同域名内重定向,否则为 0。</p>\n<p><code>fetchStart</code> :浏览器准备使用 http 请求文档的时间,在检查本地缓存之前。</p>\n<p><code>domainLookupStart/domainLookupEnd</code> :DNS 域名查询开始 / 结束的时间,如果使用本地缓存(则无需 DNC 查询)或持久链接,则和 fetchStart 一致。</p>\n<p><code>connectStart</code> :HTTP(TCP)开始或重新建立链接的时间,如果是持久链接,则和 fetchStart 一致。</p>\n<p><code>connectEnd</code> :HTTP(TCP)完成建立链接的时间(完成握手),如果是持久链接,则和 fetchStart 一致。</p>\n<p><code>secureConnectionStart</code> :Https 链接开始的时间,如果不是安全链接则为 0。</p>\n<p><code>requestStart</code> :http 在建立链接之后,正式开始请求真实文档的时间,包括从本地读取缓存。</p>\n<p><code>responseStart</code> :http 开始接收响应的时间(获取第一个字节),包括从本地读取缓存。</p>\n<p><code>responseEnd</code> :http 响应接收完全的时间(最后一个字节),包括从本地读取缓存。</p>\n<p><code>domLoading</code> :开始解析渲染 DOM 树的时间。</p>\n<p><code>domInteractive</code> :完成解析 DOM 树的时间 (这个时候放在 html 头部的脚本已经执行完毕,async,defter 属性的脚本已经开始加载)。</p>\n<p><code>domContentLoadedEventStart</code> :DOM 解析完成,同步的脚本,defter,async 属性的脚本下载并执行完毕后,页面内资源加载开始的时间,此时 dom 依赖的图片、子框架和异步脚本,css 样式表等其他内容不一定完成加载加载。</p>\n<p><code>domContentLoadedEventEnd</code> :domContentLoadedEvent 事件结束</p>\n<p><code>domComplete</code> :当文档的 DOM 树已经构建完成、所有的子资源(如样式表、脚本、图片等)都已经下载完成时。这意味着文档的结构已经完全准备好,但是可能一些外部资源(如图片等)还在进行下载或者脚本在执行。在这个阶段,页面已经可以被渲染和展示给用户了,但可能还有些许的异步加载的资源没有完成加载。</p>\n<p><code>loadEventStart</code> :整个页面及所有依赖资源如样式表和图片都已完成加载时触发,这个时候可以认为 dom 渲染完毕</p>\n<p><code>loadEventEnd</code> :load 函数执行完毕的事件、</p>\n<h6 id=\"可以计算出来的页面加载过程的关键时间段\"><a class=\"anchor\" href=\"#可以计算出来的页面加载过程的关键时间段\">#</a> 可以计算出来的页面加载过程的关键时间段</h6>\n<ul>\n<li>页面卸载阶段:\n<ol>\n<li>上一个页面卸载耗时:unloadEventEnd - unloadEventStart</li>\n</ol>\n</li>\n<li>网络部分:\n<ol>\n<li>重定向耗时:redirectEnd - redirectStart</li>\n<li>文档开始获取时间时间:fetchStart</li>\n<li>取缓存耗时:domainLookupStart - fetchStart</li>\n<li>DNS 查询耗时:domainLookupEnd - domainLookupStart</li>\n<li>ssl 四次握手耗时:connectEnd - secureConnectionStart</li>\n<li>TCP 建立耗时:connectEnd - connectStart</li>\n<li>请求响应耗时:responseStart - requestStart</li>\n<li>响应传输耗时:responseEnd - responseStart。</li>\n</ol>\n</li>\n<li>页面解析渲染部分:\n<ol>\n<li>dom 开始解析时间(dom 树开始构建的时间):domLoading</li>\n<li>dom 解析完毕时间(dom 树构建完成的时间):domInteractive</li>\n<li>dom 解析完毕并且脚本执行完毕的时间:domContendLoadEventStart</li>\n<li>所有资源加载完成,dom 完全渲染的时间:loadEventStart</li>\n</ol>\n</li>\n</ul>\n<h6 id=\"资源加载过程中关键数据的获取方式\"><a class=\"anchor\" href=\"#资源加载过程中关键数据的获取方式\">#</a> 资源加载过程中关键数据的获取方式:</h6>\n<p>利用 <code>performance.getEntriesByType('resource')</code> 获取到所有静态资源加载的关键信息</p>\n<h6 id=\"可以得到的静态资源信息和加载中的关键时间段\"><a class=\"anchor\" href=\"#可以得到的静态资源信息和加载中的关键时间段\">#</a> 可以得到的静态资源信息和加载中的关键时间段</h6>\n<ul>\n<li>静态资源信息\n<ol>\n<li><code>name</code> : 资源地址</li>\n<li><code>initiatorType</code> : 资源类型</li>\n<li><code>transferSize</code> : 资源大小</li>\n<li><code>startTime</code> : 开始时间</li>\n<li><code>responseEnd</code> : 结束时间</li>\n<li><code>duration</code> : 消耗时间</li>\n</ol>\n</li>\n<li>网络部分\n<ol>\n<li>重定向耗时:redirectEnd - redirectStart</li>\n<li>文档开始获取时间时间:fetchStart</li>\n<li>取缓存耗时:domainLookupStart - fetchStart</li>\n<li>DNS 查询耗时:domainLookupEnd - domainLookupStart</li>\n<li>ssl 四次握手耗时:connectEnd - secureConnectionStart</li>\n<li>TCP 建立耗时:connectEnd - connectStart</li>\n<li>请求响应耗时:responseStart - requestStart</li>\n<li>响应传输耗时:responseEnd - responseStart。</li>\n</ol>\n</li>\n</ul>\n<h6 id=\"静态资源加载的缓存命中率的计算\"><a class=\"anchor\" href=\"#静态资源加载的缓存命中率的计算\">#</a> 静态资源加载的缓存命中率的计算</h6>\n<ol>\n<li>直接判断 <code>performance.getEntriesByType('resource')</code> 返回的资源数据对象数组中的元素的 <code>deliveryType</code> 属性是否为 <code>cache</code></li>\n<li>同时满足 <code>durantion === 0</code> 和 <code>transferSize === 0</code></li>\n</ol>\n<h3 id=\"行为监控\"><a class=\"anchor\" href=\"#行为监控\">#</a> 行为监控:</h3>\n<h4 id=\"行为监控中需要监控一些什么提供一些什么功能\"><a class=\"anchor\" href=\"#行为监控中需要监控一些什么提供一些什么功能\">#</a> 行为监控中需要监控一些什么,提供一些什么功能?</h4>\n<h5 id=\"监控-pvuv从而得到流量变化统计出热点页面\"><a class=\"anchor\" href=\"#监控-pvuv从而得到流量变化统计出热点页面\">#</a> 监控 pv,uv,从而得到流量变化,统计出热点页面</h5>\n<h6 id=\"pv-页面访问量\"><a class=\"anchor\" href=\"#pv-页面访问量\">#</a> pv: 页面访问量</h6>\n<p><strong>获取方法</strong>:路由跳转就说明访问了页面,在路由跳转的时候上报也就是 <code>popState</code> 事件触发时,上报此时的事件,页面信息,用户来路</p>\n<h6 id=\"uv用户访问量\"><a class=\"anchor\" href=\"#uv用户访问量\">#</a> uv:用户访问量</h6>\n<p>获取方法:对外暴露一个设置用户唯一标识的方法,让用户在合适的时候调用这个方法设置唯一标识,后续每次数据上报时都带上这个唯一标识,后端来通过时间戳和这个唯一标识,来统计不同时间段的 uv</p>\n<h5 id=\"监控用户设备信息浏览器信息从而得到大多数用户的屏幕数据浏览器类型从而更好的适配\"><a class=\"anchor\" href=\"#监控用户设备信息浏览器信息从而得到大多数用户的屏幕数据浏览器类型从而更好的适配\">#</a> 监控用户设备信息,浏览器信息,从而得到大多数用户的屏幕数据,浏览器类型从而更好的适配</h5>\n<p>利用 <code>window.navigation</code> 获取到 userAgent, 再利用 <code>broser</code> 和 <code>ua-parser-js</code> 这两个包对其进行解析</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">import</span> parser <span class=\"token keyword\">from</span> <span class=\"token string\">'ua-parser-js'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">import</span> Bowser <span class=\"token keyword\">from</span> <span class=\"token string\">'bowser'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token keyword\">function</span> <span class=\"token function\">resolveUserAgent</span><span class=\"token punctuation\">(</span>userAgent<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token keyword\">const</span> browserData <span class=\"token operator\">=</span> Bowser<span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>userAgent<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token keyword\">const</span> parserData <span class=\"token operator\">=</span> <span class=\"token function\">parser</span><span class=\"token punctuation\">(</span>userAgent<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token keyword\">const</span> browserName <span class=\"token operator\">=</span> browserData<span class=\"token punctuation\">.</span>browser<span class=\"token punctuation\">.</span>name <span class=\"token operator\">??</span> parserData<span class=\"token punctuation\">.</span>browser<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">;</span> <span class=\"token comment\">// 浏览器名</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token keyword\">const</span> browserVersion <span class=\"token operator\">=</span> browserData<span class=\"token punctuation\">.</span>browser<span class=\"token punctuation\">.</span>version <span class=\"token operator\">??</span> parserData<span class=\"token punctuation\">.</span>browser<span class=\"token punctuation\">.</span>version<span class=\"token punctuation\">;</span> <span class=\"token comment\">// 浏览器版本号</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token keyword\">const</span> osName <span class=\"token operator\">=</span> browserData<span class=\"token punctuation\">.</span>os<span class=\"token punctuation\">.</span>name <span class=\"token operator\">??</span> parserData<span class=\"token punctuation\">.</span>os<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">;</span> <span class=\"token comment\">// 操作系统名</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token keyword\">const</span> osVersion <span class=\"token operator\">=</span> parserData<span class=\"token punctuation\">.</span>os<span class=\"token punctuation\">.</span>version <span class=\"token operator\">??</span> browserData<span class=\"token punctuation\">.</span>os<span class=\"token punctuation\">.</span>version<span class=\"token punctuation\">;</span> <span class=\"token comment\">// 操作系统版本号</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token keyword\">const</span> deviceType <span class=\"token operator\">=</span> browserData<span class=\"token punctuation\">.</span>platform<span class=\"token punctuation\">.</span>type <span class=\"token operator\">??</span> parserData<span class=\"token punctuation\">.</span>device<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">;</span> <span class=\"token comment\">// 设备类型</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token keyword\">const</span> deviceVendor <span class=\"token operator\">=</span> browserData<span class=\"token punctuation\">.</span>platform<span class=\"token punctuation\">.</span>vendor <span class=\"token operator\">??</span> parserData<span class=\"token punctuation\">.</span>device<span class=\"token punctuation\">.</span>vendor <span class=\"token operator\">??</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 设备所属公司</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token keyword\">const</span> deviceModel <span class=\"token operator\">=</span> browserData<span class=\"token punctuation\">.</span>platform<span class=\"token punctuation\">.</span>model <span class=\"token operator\">??</span> parserData<span class=\"token punctuation\">.</span>device<span class=\"token punctuation\">.</span>model <span class=\"token operator\">??</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 设备型号</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> <span class=\"token keyword\">const</span> engineName <span class=\"token operator\">=</span> browserData<span class=\"token punctuation\">.</span>engine<span class=\"token punctuation\">.</span>name <span class=\"token operator\">??</span> parserData<span class=\"token punctuation\">.</span>engine<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">;</span> <span class=\"token comment\">//engine 名</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> <span class=\"token keyword\">const</span> engineVersion <span class=\"token operator\">=</span> browserData<span class=\"token punctuation\">.</span>engine<span class=\"token punctuation\">.</span>version <span class=\"token operator\">??</span> parserData<span class=\"token punctuation\">.</span>engine<span class=\"token punctuation\">.</span>version<span class=\"token punctuation\">;</span> <span class=\"token comment\">//engine 版本号</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> browserName<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> browserVersion<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> osName<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre> osVersion<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> deviceType<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> deviceVendor<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> deviceModel<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> engineName<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre> engineVersion<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><h5 id=\"监控用户的行为路由跳转接口请求当前访问的页面信息-并按顺序存入用户行为栈从而准确定位用户的操作\"><a class=\"anchor\" href=\"#监控用户的行为路由跳转接口请求当前访问的页面信息-并按顺序存入用户行为栈从而准确定位用户的操作\">#</a> 监控用户的行为,路由跳转,接口请求,当前访问的页面信息, 并按顺序存入用户行为栈,从而准确定位用户的操作</h5>\n<h6 id=\"用户行为的监控\"><a class=\"anchor\" href=\"#用户行为的监控\">#</a> 用户行为的监控:</h6>\n<p>考虑到监听所有元素的所有方法会过于消耗性能,所以支持用户通过配置对象的方式在初始化 sdk 的时候配置 <code>elementTrackedList</code> , <code>classTrackedList</code> , <code>eventTrackedList</code> 从而监听指定元素 和 指定 class 的元素的指定事件。</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">private</span> <span class=\"token function\">initDomHandler</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>eventTrackedList<span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>eventName<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> eventName<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token keyword\">let</span> target <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>elementTrackedList<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target <span class=\"token keyword\">as</span> HTMLElement<span class=\"token punctuation\">)</span><span class=\"token operator\">?.</span>tagName<span class=\"token operator\">?.</span><span class=\"token function\">toLocaleLowerCase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target <span class=\"token keyword\">as</span> HTMLElement<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token operator\">:</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> target <span class=\"token operator\">=</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> target <span class=\"token operator\">??</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token builtin\">Array</span><span class=\"token punctuation\">.</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target <span class=\"token keyword\">as</span> HTMLElement<span class=\"token punctuation\">)</span><span class=\"token operator\">?.</span>classList<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>className<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>classTrackedList<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>className<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> <span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target <span class=\"token keyword\">as</span> HTMLElement<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> <span class=\"token operator\">:</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>target<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> <span class=\"token keyword\">const</span> domData <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> tagInfo<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> id<span class=\"token operator\">:</span> target<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> classList<span class=\"token operator\">:</span> <span class=\"token builtin\">Array</span><span class=\"token punctuation\">.</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span>target<span class=\"token punctuation\">.</span>classList<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre> tagName<span class=\"token operator\">:</span> target<span class=\"token punctuation\">.</span>tagName<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre> text<span class=\"token operator\">:</span> target<span class=\"token punctuation\">.</span>textContent<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre> pageInfo<span class=\"token operator\">:</span> <span class=\"token function\">getPageInformation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre> time<span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getTime</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre> timeFormat<span class=\"token operator\">:</span> <span class=\"token function\">formatDate</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre></pre></td></tr><tr><td data-num=\"33\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">[</span>UserActionMetricsName<span class=\"token punctuation\">.</span><span class=\"token constant\">DBR</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">[</span>UserActionMetricsName<span class=\"token punctuation\">.</span><span class=\"token constant\">DBR</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> <span class=\"token punctuation\">[</span>eventName<span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>domData<span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre> <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">[</span>UserActionMetricsName<span class=\"token punctuation\">.</span><span class=\"token constant\">DBR</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>eventName<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"36\"></td><td><pre> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">[</span>UserActionMetricsName<span class=\"token punctuation\">.</span><span class=\"token constant\">DBR</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>eventName<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span>domData<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"37\"></td><td><pre> <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"38\"></td><td><pre> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">[</span>UserActionMetricsName<span class=\"token punctuation\">.</span><span class=\"token constant\">DBR</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>eventName<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>domData<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"39\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"40\"></td><td><pre></pre></td></tr><tr><td data-num=\"41\"></td><td><pre> <span class=\"token keyword\">const</span> hehaviorStackData <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"42\"></td><td><pre> name<span class=\"token operator\">:</span> eventName<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"43\"></td><td><pre> page<span class=\"token operator\">:</span> <span class=\"token function\">getPageInformation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>pathname<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"44\"></td><td><pre> value<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"45\"></td><td><pre> tagInfo<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"46\"></td><td><pre> id<span class=\"token operator\">:</span> target<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"47\"></td><td><pre> classList<span class=\"token operator\">:</span> <span class=\"token builtin\">Array</span><span class=\"token punctuation\">.</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span>target<span class=\"token punctuation\">.</span>classList<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"48\"></td><td><pre> tagName<span class=\"token operator\">:</span> target<span class=\"token punctuation\">.</span>tagName<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"49\"></td><td><pre> text<span class=\"token operator\">:</span> target<span class=\"token punctuation\">.</span>textContent<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"50\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"51\"></td><td><pre> pageInfo<span class=\"token operator\">:</span> <span class=\"token function\">getPageInformation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"52\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"53\"></td><td><pre> time<span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getTime</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"54\"></td><td><pre> timeFormat<span class=\"token operator\">:</span> <span class=\"token function\">formatDate</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"55\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"56\"></td><td><pre> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>hehaviorStack<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>hehaviorStackData<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"57\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"58\"></td><td><pre> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"59\"></td><td><pre> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"60\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"61\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr></table></figure><h6 id=\"页面基本信息获取\"><a class=\"anchor\" href=\"#页面基本信息获取\">#</a> 页面基本信息获取:</h6>\n<ol>\n<li>通过 <code>window.location</code> 获取到当前页面的 <code>protocol</code> , <code>host</code> , <code>port</code> <code>origin</code> , <code>href</code> , <code>pathname</code> , <code>search</code></li>\n<li>利用 <code>window.screen</code> 获取到用户屏幕的宽高</li>\n<li>通过 <code>document.title</code> 获取到网页的 title</li>\n</ol>\n<h6 id=\"路由跳转的监控\"><a class=\"anchor\" href=\"#路由跳转的监控\">#</a> 路由跳转的监控</h6>\n<ul>\n<li>\n<p>监控 <code>hash</code> 路由</p>\n<p><code>hash</code> 路由的 <code>hash</code> 变化会触发 <code>hashchange</code> 时间,但是也会触发 <code>popstate</code> 事件,所以我们统一监听 <code>popstate</code> 事件即可</p>\n</li>\n<li>\n<p>监控 <code>history</code> 路由</p>\n<ol>\n<li>\n<p><code>history</code> 路由的 <code>back</code> , <code>forword</code> , <code>go</code> 方法都会触发 <code>popstate</code> 事件,所以我们可以监听 <code>popstate</code> 事件</p>\n</li>\n<li>\n<p>但是 <code>pushState</code> , <code>replaceState</code> 方法不会触发对应的事件和 <code>popstate</code> 事件,所以我们需要对其进行重写,在原有功能的基础上通过 <code>window.dispatch</code> 派发事件</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">writePushStateAndReplaceState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> history<span class=\"token punctuation\">.</span>pushState <span class=\"token operator\">=</span> <span class=\"token function\">writeHistoryEvent</span><span class=\"token punctuation\">(</span><span class=\"token string\">'pushState'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> history<span class=\"token punctuation\">.</span>replaceState <span class=\"token operator\">=</span> <span class=\"token function\">writeHistoryEvent</span><span class=\"token punctuation\">(</span><span class=\"token string\">'replaceState'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token keyword\">function</span> <span class=\"token function\">writeHistoryEvent</span><span class=\"token punctuation\">(</span>type<span class=\"token operator\">:</span> <span class=\"token keyword\">keyof</span> History<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token keyword\">const</span> originEvent <span class=\"token operator\">=</span> history<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token keyword\">return</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token operator\">:</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token keyword\">const</span> result <span class=\"token operator\">=</span> <span class=\"token function\">originEvent</span><span class=\"token punctuation\">.</span><span class=\"token function\">apply</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">,</span> arguments<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token keyword\">const</span> event <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Event</span><span class=\"token punctuation\">(</span>type<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> window<span class=\"token punctuation\">.</span><span class=\"token function\">dispatchEvent</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token keyword\">return</span> result<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure></li>\n</ol>\n</li>\n</ul>\n<h6 id=\"界面停留事件的监控\"><a class=\"anchor\" href=\"#界面停留事件的监控\">#</a> 界面停留事件的监控</h6>\n<ol>\n<li>在 load 事件里记录初次进入界面的事件,把该界面的信息(url, startTime, endTime)推送进栈中</li>\n<li>在 popSate 事件触发,也就是路由跳转时,记录上一个界面也就是栈顶的哪个界面信息的结束时间</li>\n<li>在 beforeunload 中计算出最后一个界面的结束时间</li>\n</ol>\n<h6 id=\"访客来路的监控\"><a class=\"anchor\" href=\"#访客来路的监控\">#</a> 访客来路的监控:</h6>\n<p>监控访客来路的原因:</p>\n<ol>\n<li>\n<p>获取到流量是从哪个界面来的</p>\n<ul>\n<li>\n<p>获取方法:</p>\n</li>\n<li>\n<p>通过 <code>document.referer</code> 来获取到网页前一个地址</p>\n</li>\n<li>\n<blockquote>\n<p>注意:以下场景获取到的值为空</p>\n<ul>\n<li>直接在地址栏中输入地址跳转</li>\n<li>直接通过浏览器收藏夹打开</li>\n<li>从 https 的网站直接进入一个 http 协议的网站</li>\n</ul>\n</blockquote>\n</li>\n</ul>\n</li>\n<li>\n<p>当发生 404 等问题的时候,知道是从哪个界面调过来的</p>\n<p>获取方法:</p>\n<p>利用 <code>window.performance.navigation.type</code> 属性,它返回一个整数,有以下 4 种情况</p>\n<ul>\n<li>\n<ul>\n<li><code>0</code> : 点击链接、地址栏输入、表单提交、脚本操作等。</li>\n</ul>\n</li>\n<li>\n<ul>\n<li><code>1</code> : 点击重新加载按钮、location.reload。</li>\n</ul>\n</li>\n<li>\n<ul>\n<li><code>2</code> : 点击前进或后退按钮。</li>\n</ul>\n</li>\n<li>\n<ul>\n<li><code>255</code> : 任何其他来源。即非刷新 / 非前进后退、非点击链接 / 地址栏输入 / 表单提交 / 脚本操作等。</li>\n</ul>\n</li>\n</ul>\n</li>\n</ol>\n<h6 id=\"对外暴露上传数据的接口从而支持用户自己手动埋点提高灵活性\"><a class=\"anchor\" href=\"#对外暴露上传数据的接口从而支持用户自己手动埋点提高灵活性\">#</a> 对外暴露上传数据的接口,从而支持用户自己手动埋点,提高灵活性</h6>\n<ol>\n<li>通过对外暴露 <code>report</code> 方法,支持用户自定义埋点,上传数据和数据类型</li>\n<li>并且每次的上报都会默认带上 <code>appID</code> 来区别不同的 app, <code>uid</code> 来区别不同的用户统计 uv, <code>time</code> 来记录时间, <code>extra</code> 来支持用户通过对外暴露的 <code>setExtra</code> 方法来配置每次请求都必须带上的数据</li>\n</ol>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">public</span> <span class=\"token generic-function\"><span class=\"token function\">report</span><span class=\"token generic class-name\"><span class=\"token operator\"><</span><span class=\"token constant\">T</span> <span class=\"token keyword\">extends</span> Record<span class=\"token operator\"><</span><span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> <span class=\"token builtin\">any</span><span class=\"token operator\">>></span></span></span><span class=\"token punctuation\">(</span>data<span class=\"token operator\">:</span> <span class=\"token constant\">T</span><span class=\"token punctuation\">,</span> type<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token keyword\">const</span> params <span class=\"token operator\">=</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">assign</span><span class=\"token punctuation\">(</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">,</span> type <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> appId<span class=\"token operator\">:</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>appId<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> uid<span class=\"token operator\">:</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>uid<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> extra<span class=\"token operator\">:</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>extra<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> time<span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getTime</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> timeFormat<span class=\"token operator\">:</span> <span class=\"token function\">formatDate</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token keyword\">const</span> blob <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Blob</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>params<span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> navigator<span class=\"token punctuation\">.</span><span class=\"token function\">sendBeacon</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>options<span class=\"token punctuation\">.</span>requestUrl <span class=\"token keyword\">as</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> blob<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr></table></figure><h3 id=\"异常监控\"><a class=\"anchor\" href=\"#异常监控\">#</a> 异常监控:</h3>\n<h4 id=\"js-运行错误监控\"><a class=\"anchor\" href=\"#js-运行错误监控\">#</a> js 运行错误监控</h4>\n<ol>\n<li>在全局监控 <code>error</code> 事件</li>\n<li>根据错误类型,文件名,信息生成一个随机 id,避免相同的错误重复上传</li>\n<li>将 event.message, <span class=\"exturl\" data-url=\"aHR0cDovL2V2ZW50LmVycm9yLm5hbWU=\">event.error.name</span>(错误类型),event.error (错误堆栈,可以让 gpt 写一个函数来解析这个错误堆栈), event.filename, event.colno, event.lineno 上传</li>\n</ol>\n<h4 id=\"资源加载错误src-or-href-错了\"><a class=\"anchor\" href=\"#资源加载错误src-or-href-错了\">#</a> 资源加载错误(src or href 错了)</h4>\n<ol>\n<li>在全局监控 error 事件,通过 event.targrt.tagName 是不是 link or script or img or a 来判断是不是资源加载错误</li>\n<li>根据错误类型,src 生成一个随机 id,避免相同的错误重复上传</li>\n<li>将 event.tatget.src, event.target.tagName, outerHTMl 上传</li>\n</ol>\n<h4 id=\"promise-错误监控\"><a class=\"anchor\" href=\"#promise-错误监控\">#</a> promise 错误监控</h4>\n<ol>\n<li>在全局监控 <code>unhandledRejection</code> 事件</li>\n<li>根据错误信息,错误名字,生成一个随机 id,避免相同的错误重复上传</li>\n<li>上传 event.reason.message, <span class=\"exturl\" data-url=\"aHR0cDovL2V2ZW50LnJlYXNvbi5uYW1l\">event.reason.name</span>, event.reason (错误堆栈,可以让 gpt 写一个函数来解析这个错误堆栈)</li>\n</ol>\n<h4 id=\"跨域错误\"><a class=\"anchor\" href=\"#跨域错误\">#</a> 跨域错误</h4>\n<ol>\n<li>在全局监听 <code>error</code> 事件</li>\n<li>通过 event.message 是否为 <code>Script error</code> 来判断是否是跨域请求</li>\n<li>上报跨域请求错误</li>\n</ol>\n<h3 id=\"http-请求监控\"><a class=\"anchor\" href=\"#http-请求监控\">#</a> http 请求监控</h3>\n<p>我们通常需要监控 http 请求的各种信息, <code>请求地址</code> , <code>方法</code> , <code>状态码</code> , <code>请求耗时</code> , <code>请求体</code> , <code>响应</code> , 从而在接口报错时及时发现,统计出流量大的后端服务,经常出问题的后端服务。</p>\n<h4 id=\"xmlhttprequest-的劫持\"><a class=\"anchor\" href=\"#xmlhttprequest-的劫持\">#</a> XMLHTTPRequest 的劫持:</h4>\n<ol>\n<li>\n<p>重写 xhr 对象的 <code>open</code> 方法,在里面采集到请求的 url 和 method</p>\n</li>\n<li>\n<p>重写 xhr 对象的 <code>send</code> 方法,在里面采集到请求的 body,并记录时间,为后续记录接口耗时做准备</p>\n</li>\n<li>\n<p>监听 xhr 对象的 loadend 事件,然后从 xhr 对象中得到,状态码,状态码短语,response, 然后执行传递的函数来讲数据添加进 sdk 的 data 等待上报</p>\n<figure class=\"highlight ts\"><figcaption data-lang=\"TypeScript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">proxyXmlHttp</span><span class=\"token punctuation\">(</span><span class=\"token function-variable function\">loadHandler</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>args<span class=\"token operator\">:</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token string\">'XMLHttpRequest'</span> <span class=\"token keyword\">in</span> window <span class=\"token operator\">&&</span> <span class=\"token keyword\">typeof</span> window<span class=\"token punctuation\">.</span>XMLHttpRequest <span class=\"token operator\">===</span> <span class=\"token string\">'function'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token keyword\">const</span> oXMLHttpRequest <span class=\"token operator\">=</span> window<span class=\"token punctuation\">.</span>XMLHttpRequest<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token punctuation\">(</span>window <span class=\"token keyword\">as</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>oXMLHttpRequest<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token comment\">//oXMLHttpRequest 为原生的 XMLHttpRequest,可以用以 SDK 进行数据上报,区分业务</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token punctuation\">(</span>window <span class=\"token keyword\">as</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>oXMLHttpRequest <span class=\"token operator\">=</span> oXMLHttpRequest<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token punctuation\">(</span>window <span class=\"token keyword\">as</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function-variable function\">XMLHttpRequest</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token comment\">// 覆写 window.XMLHttpRequest</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token comment\">// eslint-disable-next-line new-cap</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token keyword\">const</span> xhr <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">oXMLHttpRequest</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token comment\">// eslint-disable-next-line @typescript-eslint/unbound-method</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> open<span class=\"token punctuation\">,</span> send <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> xhr<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> <span class=\"token comment\">// eslint-disable-next-line @typescript-eslint/consistent-type-assertions</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> <span class=\"token keyword\">let</span> httpMetrics<span class=\"token operator\">:</span> HttpMetrics <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> <span class=\"token keyword\">as</span> HttpMetrics<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> xhr<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">open</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>method<span class=\"token punctuation\">,</span> url<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> httpMetrics<span class=\"token punctuation\">.</span>method <span class=\"token operator\">=</span> method<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> httpMetrics<span class=\"token punctuation\">.</span>url <span class=\"token operator\">=</span> url<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> <span class=\"token function\">open</span><span class=\"token punctuation\">.</span><span class=\"token function\">call</span><span class=\"token punctuation\">(</span>xhr<span class=\"token punctuation\">,</span> method<span class=\"token punctuation\">,</span> url<span class=\"token punctuation\">,</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> xhr<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">send</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>body<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> httpMetrics<span class=\"token punctuation\">.</span>body <span class=\"token operator\">=</span> body <span class=\"token operator\">??</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> httpMetrics<span class=\"token punctuation\">.</span>requestTime <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getTime</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> httpMetrics<span class=\"token punctuation\">.</span>requestTimeFormat <span class=\"token operator\">=</span> <span class=\"token function\">formatDate</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre> <span class=\"token function\">send</span><span class=\"token punctuation\">.</span><span class=\"token function\">call</span><span class=\"token punctuation\">(</span>xhr<span class=\"token punctuation\">,</span> body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre> xhr<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'loadend'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> status<span class=\"token punctuation\">,</span> statusText<span class=\"token punctuation\">,</span> response <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> xhr<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre> httpMetrics <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre> <span class=\"token operator\">...</span>httpMetrics<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre> status<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre> statusText<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre> response<span class=\"token operator\">:</span> response <span class=\"token operator\">&&</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre> responseTime<span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getTime</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre> responseTimeFormat<span class=\"token operator\">:</span> <span class=\"token function\">formatDate</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"36\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"37\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">typeof</span> loadHandler <span class=\"token operator\">===</span> <span class=\"token string\">'function'</span><span class=\"token punctuation\">)</span> <span class=\"token function\">loadHandler</span><span class=\"token punctuation\">(</span>httpMetrics<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"38\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"39\"></td><td><pre> <span class=\"token keyword\">return</span> xhr<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"40\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"41\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"42\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure></li>\n</ol>\n<h2 id=\"前端监控需要注意的点\"><a class=\"anchor\" href=\"#前端监控需要注意的点\">#</a> 前端监控需要注意的点:</h2>\n<h3 id=\"数据的上报方式\"><a class=\"anchor\" href=\"#数据的上报方式\">#</a> 数据的上报方式:</h3>\n<h4 id=\"使用的上报方法\"><a class=\"anchor\" href=\"#使用的上报方法\">#</a> 使用的上报方法:</h4>\n<ol>\n<li>\n<p>优先使用 sendBeacon 方法</p>\n<p><strong>原因:</strong></p>\n<ul>\n<li>\n<p>是异步发送数据,不会阻塞页面的卸载和跳转</p>\n</li>\n<li>\n<p>可靠性很高,不会因为页面的关闭 or 跳转 而 终止发送</p>\n</li>\n<li>\n<p>虽然只支持 post 请求,但是用来发送埋点的统计数据,却足够了,也极为合适</p>\n</li>\n</ul>\n</li>\n<li>\n<p>如果浏览器不支持 sendBeacon 方法再降级使用 ajax 方法</p>\n</li>\n</ol>\n<h3 id=\"数据的上报时机\"><a class=\"anchor\" href=\"#数据的上报时机\">#</a> 数据的上报时机:</h3>\n<h4 id=\"需要实时上报的\"><a class=\"anchor\" href=\"#需要实时上报的\">#</a> 需要实时上报的:</h4>\n<ol>\n<li>异常上报,需要实时上报</li>\n<li>pv,用户行为都是触发就上报</li>\n</ol>\n<h4 id=\"不需要实时上报的\"><a class=\"anchor\" href=\"#不需要实时上报的\">#</a> 不需要实时上报的</h4>\n<ol>\n<li>用户行为栈,http 请求记录都放到各自的一个队列里,满了再集中上报</li>\n<li>其他不会很多的数据在界面卸载前上报</li>\n</ol>\n<h3 id=\"当流量爆炸的时候怎么进行削峰限流\"><a class=\"anchor\" href=\"#当流量爆炸的时候怎么进行削峰限流\">#</a> 当流量爆炸的时候,怎么进行削峰限流</h3>\n<h4 id=\"1-简单方法\"><a class=\"anchor\" href=\"#1-简单方法\">#</a> 1. 简单方法:</h4>\n<p>直接丢弃百分之 20 的用户的数据,具体方法,Math.radom()生成一个随机的方法,丢其小于 0.2 的用户的数据</p>\n<h3 id=\"异常上报的时候需要根据异常的信息生成一个唯一性标识避免同一错误的重复上报\"><a class=\"anchor\" href=\"#异常上报的时候需要根据异常的信息生成一个唯一性标识避免同一错误的重复上报\">#</a> 异常上报的时候,需要根据异常的信息生成一个唯一性标识,避免同一错误的重复上报</h3>\n<h2 id=\"前端监控提供的监控模块应该支持用户按需选择其需要的\"><a class=\"anchor\" href=\"#前端监控提供的监控模块应该支持用户按需选择其需要的\">#</a> 前端监控提供的监控模块,应该支持用户按需选择其需要的:</h2>\n<ol>\n<li>支持用户通过配置对象,按需选择它需要的性能监控,行为监控,异常监控,http 监控功能</li>\n<li>当用户开启性能监控的时候,应支持用户通过配置对象,按需选择自己需要收集的性能指标和关键时间段,缓存命中率</li>\n<li>当用户开启行为监控的时候,应支持用户通过配置对象,按需选择自己是否需要收集,pv,uv, 设备信息,界面信息,来源信息,路由跳转信息,用户行为栈,页面停留时间。</li>\n<li>当用户开启异常监控的时候应支持用户通过配置对象,按需选择自己是否需要 js 运行错误监控,资源加载错误监控,promise 错误监控,跨域错误监控,白屏错误监控</li>\n</ol>\n",
"tags": [
"笔记",
"前端",
"前端监控",
"前端",
"前端监控",
"sendSeacon"
]
},
{
"id": "https://zimu-66ccff.github.io/webpackKnowlege/",
"url": "https://zimu-66ccff.github.io/webpackKnowlege/",
"title": "webpack八股文整理",
"date_published": "2024-03-13T06:26:25.000Z",
"content_html": "<h1 id=\"1-常见的-loader\"><a class=\"anchor\" href=\"#1-常见的-loader\">#</a> 1. 常见的 loader</h1>\n<ol>\n<li><strong>资源加载处理</strong></li>\n</ol>\n<ul>\n<li><code>file-loader</code> : 通常用来处理图片和字体,用来将文件输出到一个文件夹中,代码中通过相对 url 来引用输出的文件</li>\n<li><code>url-loader</code> :和 file-loader 类似,不同的是可以设定一个阈值,小于这个阈值的返回它的 base-64 形式编码,大的交给 file-loader 处理</li>\n<li><code>image-loader</code> :用来加载和压缩图片</li>\n<li><code>svg-inline-loader</code> :用来将压缩后的 svg 内容注入到代码中</li>\n<li><code>json-loader</code> :用来加载 json</li>\n</ul>\n<ol start=\"2\">\n<li><strong>代码加载处理转换</strong></li>\n</ol>\n<ul>\n<li><code>ts-loader</code> : 用来将 ts 转换成 js</li>\n<li><code>awesome-typescript-loader</code> :和 ts-loader 一样,但是性能比 ts-loader 好</li>\n<li><code>babel-loader</code> :用来将 es6 的代码转换成 es5 的代码</li>\n<li><code>sass-loader</code> :用来将 sass 代码转换成 css 代码</li>\n<li><code>less-loader</code> :用来将 less 代码转换成 css 代码</li>\n<li><code>postcss-loader</code> :用来加载扩展的 css 代码,支持使用下一代 css,可以配合 autoprefixer 来自动补齐 css3 前缀</li>\n<li><code>css-loader</code> :用来加载 css</li>\n<li><code>style-loader</code> :用来将 css 注入到 js 中,通过 dom 的形式去操作 css</li>\n</ul>\n<ol start=\"3\">\n<li><strong>代码检查</strong></li>\n</ol>\n<ul>\n<li><code>tslint-loader</code> :用来检查 ts 代码的质量</li>\n<li><code>eslint-loader</code> :用来检查 js 代码的质量</li>\n</ul>\n<ol start=\"4\">\n<li><strong>测试覆盖率</strong></li>\n</ol>\n<ul>\n<li><code>caverjs-loader</code> :用来加载测试的覆盖率</li>\n</ul>\n<ol start=\"5\">\n<li><strong>支持第三方框架 vue</strong></li>\n</ol>\n<ul>\n<li><code>vue-loader</code> :用来加载 vue 的单文件组件</li>\n</ul>\n<ol start=\"6\">\n<li><strong>国际化</strong></li>\n</ol>\n<ul>\n<li><code>i18-loader</code> :用于国际化</li>\n</ul>\n<ol start=\"7\">\n<li><strong>缓存</strong></li>\n</ol>\n<ul>\n<li><code>cache-loader</code> :可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里</li>\n</ul>\n<ol start=\"8\">\n<li><strong>调试</strong></li>\n</ol>\n<ul>\n<li><code>source-map-loader</code> : 生成对应的 map 文件,方便对应的断点调试</li>\n</ul>\n<h1 id=\"2-有哪些常见的-plugin你用过哪些-plugin\"><a class=\"anchor\" href=\"#2-有哪些常见的-plugin你用过哪些-plugin\">#</a> 2. 有哪些常见的 Plugin?你用过哪些 Plugin?</h1>\n<ul>\n<li><code>define-plugin</code> :定义环境变量 (Webpack4 之后指定 mode 会自动配置)</li>\n<li><code>ignore-plugin</code> :忽略部分文件</li>\n<li><code>html-webpack-plugin</code> :简化 HTML 文件创建 (依赖于 html-loader)</li>\n<li><code>web-webpack-plugin</code> :可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用</li>\n<li><code>uglifyjs-webpack-plugin</code> :不支持 ES6 压缩 (Webpack4 以前)</li>\n<li><code>terser-webpack-plugin</code> : 支持压缩 ES6 (Webpack4)</li>\n<li><code>webpack-parallel-uglify-plugin</code> : 多进程执行代码压缩,提升构建速度</li>\n<li><code>mini-css-extract-plugin</code> : 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代 extract-text-webpack-plugin)</li>\n<li><code>serviceworker-webpack-plugin</code> :为网页应用增加离线缓存功能</li>\n<li><code>clean-webpack-plugin</code> : 目录清理</li>\n<li><code>speed-measure-webpack-plugin</code> : 可以看到每个 Loader 和 Plugin 执行耗时 (整个打包耗时、每个 Plugin 和 Loader 耗时)</li>\n<li><code>webpack-bundle-analyzer</code> : 可视化 Webpack 输出文件的体积</li>\n</ul>\n<h1 id=\"3-loader-和-plugin-的区别\"><a class=\"anchor\" href=\"#3-loader-和-plugin-的区别\">#</a> 3. Loader 和 Plugin 的区别?</h1>\n<p><code>loader</code> : 因为 webpack 本身只是针对 js 模块的打包器,所以本身只认识和加载 js 模块,而 loader 就是用来加载和转移其他模块的。本质上是一个函数,对内容进行转换,返回转换后的结果<br />\n <code>plugin</code> : plugin 是插件,用来扩展 webpack 的功能,会监听 webpack 生命周期中广播出的事件,从而做一切其他事情,扩展 webpack 的功能</p>\n<h1 id=\"4-webpack-的构建流程\"><a class=\"anchor\" href=\"#4-webpack-的构建流程\">#</a> 4. webpack 的构建流程</h1>\n<ol>\n<li><code>初始化</code> :通过从配置文件和 shell 脚本中读取参数,得到最终的参数,加载插件,并实列化 compiler,调用 run 方法进行编译</li>\n<li><code>编译</code> :从 entry 入口文件开始,利用配置的 loader 递归的加载并编译模块,并得到依赖关系</li>\n<li><code>输出</code> :根据入口模块的依赖关系,组装一个个 chunk,最后打包成一个单独的文件,按照配置文件输出。</li>\n</ol>\n<h1 id=\"5-如何优化-webpack-的构建速度\"><a class=\"anchor\" href=\"#5-如何优化-webpack-的构建速度\">#</a> 5. 如何优化 webpack 的构建速度</h1>\n<ul>\n<li><code>多进程构建</code> : 使用 thread-loader 来实现多进程构建</li>\n<li><code>代码压缩</code>\n<ul>\n<li>多进程并行压缩 js 代码\n<ul>\n<li>webpack-paralle-uglifyjs-plugin</li>\n<li>uglifyjs-webpack-plugin 开启 paraller 参数</li>\n<li>terser-webpack-plugin 开启 parallel 参数</li>\n</ul>\n</li>\n<li>通过 mini-css-extra-plugin 将 css 代码提取到单独的文件,利用 css-loader 的 minimize 选项开启 cssnano 压缩 css 代码</li>\n</ul>\n</li>\n<li><code>图片压缩</code>\n<ul>\n<li>使用 imagemin 库来压缩图片</li>\n<li>配置 image-loader 来压缩图片</li>\n</ul>\n</li>\n<li><code>缩小打包域</code>\n<ul>\n<li>通过 include,exclude 来缩小 loader 的范围</li>\n<li>通过 ignorePlugin 来忽略指定模块</li>\n</ul>\n</li>\n<li><code>利用cdn来引入一些小的基础包</code>\n<ul>\n<li>利用 html-webpack-plugin 生成一个 html 文件,在这个 html 文件里将一些小的基础包通过 cdn 引入,不打包</li>\n</ul>\n</li>\n<li><code>提取公共第三⽅库</code>\n<ul>\n<li>SplitChunksPlugin 插件来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码</li>\n</ul>\n</li>\n<li><code>利用缓存提升二次构建速度</code>\n<ul>\n<li>babel-loader 开启缓存</li>\n<li>terser-webpack-plugin 开启缓存</li>\n<li>使用 cache-loader</li>\n</ul>\n</li>\n<li><code>Tree shaking</code>\n<ul>\n<li>可以通过在启动 webpack 时追加参数 --optimize-minimize 来实现</li>\n</ul>\n</li>\n<li><code>Scope hoisting</code></li>\n</ul>\n<h1 id=\"6-webpack-文件监听原理\"><a class=\"anchor\" href=\"#6-webpack-文件监听原理\">#</a> 6. webpack 文件监听原理</h1>\n<p>在发现源码发生变化时,自动重新构建出新的输出文件。<br />\nWebpack 开启监听模式,有两种方式:</p>\n<ul>\n<li>启动 webpack 命令时,带上 --watch 参数</li>\n<li>在配置 webpack.config.js 中设置 watch:true</li>\n</ul>\n<p>缺点:每次需要手动刷新浏览器</p>\n<p>原理:轮询判断文件的最后编辑时间是否变化,如果某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等 aggregateTimeout 后再执行。</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>module<span class=\"token punctuation\">.</span>export <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token comment\">// 默认 false,也就是不开启</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token literal-property property\">watch</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> watchOptions <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token comment\">// 不监听的文件或者文件夹</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token literal-property property\">ignored</span><span class=\"token operator\">:</span> <span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">node_modules</span><span class=\"token regex-delimiter\">/</span></span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token comment\">// 监听到变化后会等 aggregateTimeout 后再去执行,默认是 300ms</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token literal-property property\">aggregateTimeout</span><span class=\"token operator\">:</span> <span class=\"token number\">300</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token comment\">// 判断文件是否发生变化时通过不停的询问指定文件有没有变化实现的,默认每秒问 1000 词</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token literal-property property\">poll</span><span class=\"token operator\">:</span> <span class=\"token number\">1000</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><h1 id=\"7-webpack-热更新原理\"><a class=\"anchor\" href=\"#7-webpack-热更新原理\">#</a> 7. webpack 热更新原理</h1>\n<p><img data-src=\"https://i0.imgs.ovh/2024/03/12/cAqtU.webp\" alt=\"HMR\" /></p>\n<ul>\n<li>监视阶段\n<ul>\n<li>webpack 的 watch 模式会监视文件的变化,一旦文件有变化,就会对该文件重新编译打包,然后将重新编译打包后的代码存在一个 js 对象里</li>\n<li><code>webpack-dev-server</code> 的中间件 <code>webpack-dev-middleware</code> 会对代码进行监控,一旦有代码发生改变,就会通知 webpack 将代码打包到内存中</li>\n<li>当 <code>devServer.watchContentBase</code> 设置为 <code>true</code> 的时候,server 就会监视这些配置文件夹里面的静态文件的变化,一旦有变化就会让浏览器刷新也就是 <code>live reload</code> 。</li>\n</ul>\n</li>\n<li>传递阶段\n<ul>\n<li><code>webpack-dev-server</code> 和 <code>webpack-dev-server/client</code> 客户端之间会维护一个 websockt 长连接,将 webpack 的信息传递给客户端,其中最主要的是传递新模块的 hash 值。</li>\n<li>因为客户端 <code>webpack-dev-server/client</code> 不能请求更新的代码,所以它会将信息传递给 <code>webpack/hot/dev-server</code> .</li>\n<li><code>webpack/hot/dev-server</code> 会将新模块的 hash 值与 <code>devSever</code> 配置里面允许进行热更新模块的模块的 hash 值进行比对,如果一致,则说明需要热更新,就会把 hash 值进一步传递给 <code>HotModuleReplacementRuntime</code> ,不过不一致则会直接刷新浏览器。</li>\n<li><code>HotModuleReplacementRuntime</code> 会通过 <code>jsonpMainTemplateRuntime</code> 来发送 Ajax 请求,来返回一个 json,这个 json 文件包括了所有要进行热更新的模块的 hash 值,然后会再发送一个 jsonp 请求,获取到最新的模块代码。</li>\n</ul>\n</li>\n<li>比对阶段\n<ul>\n<li><code>HotModulePlugin</code> 会对新旧模块进行对比,来决定是否进行热更新,在决定热更新后,就会更新模块,以及模块的依赖</li>\n</ul>\n</li>\n</ul>\n<h1 id=\"8-文件指纹是什么怎么用\"><a class=\"anchor\" href=\"#8-文件指纹是什么怎么用\">#</a> 8. 文件指纹是什么?怎么用?</h1>\n<p>文件指纹是打包后输出的文件名的后缀。</p>\n<ul>\n<li><code>Hash</code> :和整个项目的构建相关,只要项目文件有修改,整个项目构建的 hash 值就会更改</li>\n<li><code>Chunkhash</code> :和 Webpack 打包的 chunk 有关,不同的 entry 会生出不同的 chunkhash</li>\n<li><code>Contenthash</code> :根据文件内容来定义 hash,文件内容不变,则 contenthash 不变</li>\n</ul>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"webpack",
"打包工具"
]
},
{
"id": "https://zimu-66ccff.github.io/bfc/",
"url": "https://zimu-66ccff.github.io/bfc/",
"title": "bfc-块级格式化上下文",
"date_published": "2023-11-25T10:03:11.000Z",
"content_html": "<h1 id=\"什么是-bfc\"><a class=\"anchor\" href=\"#什么是-bfc\">#</a> 什么是 BFC</h1>\n<p>BFC 就是一个 css 布局区域,这个区域内元素布局有一定的规则</p>\n<h1 id=\"哪些元素是-bfc怎么让元素成为-bfc\"><a class=\"anchor\" href=\"#哪些元素是-bfc怎么让元素成为-bfc\">#</a> 哪些元素是 BFC(怎么让元素成为 BFC)</h1>\n<ol>\n<li>body 标签就是一个 bfc</li>\n<li>inline-block 是 bfc</li>\n<li>float 的元素 是 bfc</li>\n<li>除了 static, relative 的定位元素 是 bfc</li>\n<li>overflow 设置为 hidden,auto 的元素 是 bfc</li>\n</ol>\n<h1 id=\"bfc-的规则bfc-的特点\"><a class=\"anchor\" href=\"#bfc-的规则bfc-的特点\">#</a> BFC 的规则,BFC 的特点</h1>\n<ol>\n<li>BFC 区域内的普通的块级元素垂直方向由上到下排列<br />\n我们平时写的 html 标签都在 body 标签里面,也就是都在 bfc 渲染区域内,所以要遵守这个规则,所以才会从上到下排列</li>\n<li>BFC 计算高度的时候,会计算浮动元素和定位元素的高度。<br />\n基于这一点,可以去除浮动带来的副作用(让父元素变成 bfc, 这样就会计算浮动元素的高度)</li>\n<li>BFC 渲染区域内的上下相邻的普通的块级元素垂直方向会出现外边距合并</li>\n<li>BFC 的样式不受外界影响<br />\n基于这个可以解决外边距合并的问题,只需要让其中一个元素成为 BFC,因为成为 BFC 的元素的外边距是自己的属性,也就是 BFC 自身的属性</li>\n<li>BFC 不会和浮动元素重叠<br />\n基于这一点可以做两栏布局,和三栏布局</li>\n</ol>\n",
"tags": [
"笔记",
"前端",
"CSS",
"前端",
"CSS",
"BFC"
]
},
{
"id": "https://zimu-66ccff.github.io/whyUnocss/",
"url": "https://zimu-66ccff.github.io/whyUnocss/",
"title": "为什么选择unocss",
"date_published": "2023-11-25T09:20:45.000Z",
"content_html": "<h1 id=\"什么是原子化-css\"><a class=\"anchor\" href=\"#什么是原子化-css\">#</a> 什么是原子化 css</h1>\n<p>原子化 css 就是提供了很多 <code>preset class</code> (预设类),就是提前写好了很多类名,这些类名都有自己的样式,可以直接用这些类名,就不需要写 css 了(提供的预设类是足够的,完全不需要写 css)</p>\n<h1 id=\"早期原子化-css-带来的问题现在都解决了\"><a class=\"anchor\" href=\"#早期原子化-css-带来的问题现在都解决了\">#</a> 早期原子化 css 带来的问题(现在都解决了)</h1>\n<ol>\n<li>不能按需引入预设类,导致项目里有很多用不上的预设类,影响构建速度<br />\n<strong>解决方案</strong>:现在可以构建阶段扫描代码,能够按照代码中的实际使用情况生成工具类,解决了原子类使 CSS 产物膨胀问题。</li>\n<li>不能使用提供的预设类来自定义类,导致不能完全脱离 css 代码<br />\n<strong>解决方案</strong>:针对原子类堆叠降低可读性的问题,提供了 <code>@apply</code> 语法支持在 CSS 中对多个原子类进行合并,与语义化 CSS 实现了很好的配合。</li>\n<li>没有插件提供,提升我们使用预设类的效率<br />\n<strong>解决方案</strong>:现在都推出了 VSCode 插件,为编写原子类提供了充分的提示与自动补全。</li>\n</ol>\n",
"tags": [
"笔记",
"前端",
"CSS",
"前端",
"CSS",
"原子化css"
]
},
{
"id": "https://zimu-66ccff.github.io/whySendSeacon/",
"url": "https://zimu-66ccff.github.io/whySendSeacon/",
"title": "前端监控中为什么选择sendBeacon来发送数据",
"date_published": "2023-11-20T03:11:40.000Z",
"content_html": "<h1 id=\"前端监控中发送数据通常有什么样的问题\"><a class=\"anchor\" href=\"#前端监控中发送数据通常有什么样的问题\">#</a> 前端监控中发送数据通常有什么样的问题</h1>\n<p>前端监控中通常尝试在卸载(unload)文档之前向 Web 服务器发送数据。</p>\n<ol>\n<li>过早的发送数据可能导致错过收集数据的机会。</li>\n<li>然而,对于开发者来说保证在文档卸载期间发送数据一直是一个困难。\n<ul>\n<li>在 <code>unload</code> 时,无法保证数据被可靠的稳定的发送出去了,因为浏览器通常会忽略在 <code>unload</code> 事件处理器中产生的异步 <code>XMLHttpRequest。</code></li>\n<li>发送数据可能会迫使浏览器延迟卸载文档,并使得下一个导航出现的更晚。</li>\n</ul>\n</li>\n</ol>\n<h1 id=\"各种技术发送数据时的优缺点\"><a class=\"anchor\" href=\"#各种技术发送数据时的优缺点\">#</a> 各种技术发送数据时的优缺点</h1>\n<h2 id=\"xmlhttprequest-或-fetch-api\"><a class=\"anchor\" href=\"#xmlhttprequest-或-fetch-api\">#</a> XMLHttpRequest 或 Fetch API:</h2>\n<h3 id=\"优点\"><a class=\"anchor\" href=\"#优点\">#</a> 优点:</h3>\n<ol>\n<li>支持各种请求方法: <code> XMLHttpRequest</code> 和 <code>Fetch API</code> 支持多种请求方法,包括 <code>GET</code> 、 <code>POST</code> 等。</li>\n</ol>\n<h3 id=\"缺点\"><a class=\"anchor\" href=\"#缺点\">#</a> 缺点:</h3>\n<ol>\n<li>同步请求可能阻塞页面: 如果在页面卸载或跳转时同步发送请求,可能会阻塞页面的卸载或跳转,影响用户体验。</li>\n<li>不适用于页面关闭时的异步请求:浏览器通常会忽略在 <code>unload</code> 事件处理器中产生的异步 <code>XMLHttpRequest。</code></li>\n</ol>\n<h2 id=\"image-对象\"><a class=\"anchor\" href=\"#image-对象\">#</a> image 对象</h2>\n<h3 id=\"优点-2\"><a class=\"anchor\" href=\"#优点-2\">#</a> 优点:</h3>\n<ol>\n<li>简单: 通过创建 Image 对象,可以简单地发送 GET 请求。</li>\n</ol>\n<h3 id=\"缺点-2\"><a class=\"anchor\" href=\"#缺点-2\">#</a> 缺点:</h3>\n<ol>\n<li>仅支持 GET 请求: 由于是通过图片的 src 属性发送请求,只能发送 GET 请求。</li>\n<li>不可靠: 无法确定请求是否成功,不能获得服务器的响应状态。</li>\n</ol>\n<h2 id=\"sendbeacon\"><a class=\"anchor\" href=\"#sendbeacon\">#</a> sendBeacon</h2>\n<h3 id=\"优点-3\"><a class=\"anchor\" href=\"#优点-3\">#</a> 优点:</h3>\n<ol>\n<li>异步方式发送请求: <code>sendBeacon</code> 是异步的,不会阻塞页面的卸载或者跳转,适用于页面关闭时仍需要发送统计数据的场景。</li>\n<li>可靠性: 由于是浏览器在后台默默处理,不会因为页面的关闭或者跳转而中断发送。</li>\n</ol>\n<h3 id=\"缺点-3\"><a class=\"anchor\" href=\"#缺点-3\">#</a> 缺点:</h3>\n<ol>\n<li>仅支持 <code>POST</code> 请求: <code>sendBeacon</code> 只支持使用 <code>POST</code> 方法发送数据,因此不适用于所有类型的请求。</li>\n</ol>\n<h1 id=\"前端监控中为什么选择-sendbeacon-来发送数据\"><a class=\"anchor\" href=\"#前端监控中为什么选择-sendbeacon-来发送数据\">#</a> 前端监控中为什么选择 sendBeacon 来发送数据</h1>\n<ol>\n<li>是异步发送数据,不会阻塞页面的卸载和跳转</li>\n<li>可靠性很高,不会因为页面的关闭 or 跳转 而 终端发送</li>\n<li>虽然只支持 <code>post</code> 请求,但是用来发送埋点的统计数据,却足够了,也极为合适</li>\n</ol>\n<h1 id=\"sendbeacon-使用方法\"><a class=\"anchor\" href=\"#sendbeacon-使用方法\">#</a> sendBeacon 使用方法</h1>\n<p><code>navigator.sendBeacon(url, data);</code> <br />\n <code>url</code> : 上报地址(接口地址)<br />\n <code>data</code> : 可以是 <code>ArrayBufferView</code> , <code>Blob</code> , <code>DOMString</code> , <code>Formdata</code></p>\n<p>根据官方规范,需要 <code>request header</code> 为 CORS-safelisted-request-header,在这里则需要保证 <code>Content-Type </code> 为以下三种之一:</p>\n<ul>\n<li><code>application/x-www-form-urlencoded</code></li>\n<li><code>multipart/form-data</code></li>\n<li><code>text/plain</code></li>\n</ul>\n<p>我们一般会用到 DOMString , Blob 和 Formdata 这三种对象作为数据发送到后端,下面以这三种方式为例进行说明。</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">import</span> queryString <span class=\"token keyword\">from</span> <span class=\"token string\">'query-string'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\">// 1. DOMString 类型,该请求会自动设置请求头的 Content-Type 为 text/plain</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">reportData</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">url<span class=\"token punctuation\">,</span> data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> navigator<span class=\"token punctuation\">.</span><span class=\"token function\">sendBeacon</span><span class=\"token punctuation\">(</span>url<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\">// 2. 如果用 Blob 发送数据,这时需要我们手动设置 Blob 的 MIME type,</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\">// 一般设置为 application/x-www-form-urlencoded。</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token comment\">// 然后可以用 query-string 库来做编吗将 data 编码成 query-string 格式</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">reportData</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">url<span class=\"token punctuation\">,</span> data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token keyword\">const</span> blob <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Blob</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> queryString<span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'application/x-www-form-urlencoded'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> navigator<span class=\"token punctuation\">.</span><span class=\"token function\">sendBeacon</span><span class=\"token punctuation\">(</span>url<span class=\"token punctuation\">,</span> blob<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre></pre></td></tr><tr><td data-num=\"21\"></td><td><pre><span class=\"token comment\">// 3. 发送的是 Formdata 类型,</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre><span class=\"token comment\">// 此时该请求会自动设置请求头的 Content-Type 为 multipart/form-data。</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">reportData</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">url<span class=\"token punctuation\">,</span> data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> <span class=\"token keyword\">const</span> formData <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FormData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre> Object<span class=\"token punctuation\">.</span><span class=\"token function\">keys</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">key</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre> <span class=\"token keyword\">let</span> value <span class=\"token operator\">=</span> data<span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">typeof</span> value <span class=\"token operator\">!==</span> <span class=\"token string\">'string'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre> <span class=\"token comment\">//formData 只能 append string 或 Blob</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre> value <span class=\"token operator\">=</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre> formData<span class=\"token punctuation\">.</span><span class=\"token function\">append</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">,</span> value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre> navigator<span class=\"token punctuation\">.</span><span class=\"token function\">sendBeacon</span><span class=\"token punctuation\">(</span>url<span class=\"token punctuation\">,</span> formData<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure>",
"tags": [
"笔记",
"前端",
"前端监控",
"前端",
"前端监控",
"sendSeacon"
]
},
{
"id": "https://zimu-66ccff.github.io/globLearn/",
"url": "https://zimu-66ccff.github.io/globLearn/",
"title": "glob语法详解",
"date_published": "2023-11-16T10:55:54.000Z",
"content_html": "<h1 id=\"基础语法\"><a class=\"anchor\" href=\"#基础语法\">#</a> 基础语法</h1>\n<h2 id=\"分隔符和片段\"><a class=\"anchor\" href=\"#分隔符和片段\">#</a> 分隔符和片段</h2>\n<h3 id=\"概念\"><a class=\"anchor\" href=\"#概念\">#</a> 概念:</h3>\n<p>分隔符是・,通过・得到的数组每一项是片段。</p>\n<h3 id=\"示例\"><a class=\"anchor\" href=\"#示例\">#</a> 示例:</h3>\n<ul>\n<li><code>src/index.js</code> 有两个片段,分别是 <code>src</code> 和 <code>index.js</code></li>\n<li><code>src/**/*.js</code> 有三个片段,分别是 <code> src</code> 、 <code>**</code> 和 <code>*.js</code></li>\n</ul>\n<h2 id=\"单个星号\"><a class=\"anchor\" href=\"#单个星号\">#</a> 单个星号</h2>\n<h3 id=\"概念-2\"><a class=\"anchor\" href=\"#概念-2\">#</a> 概念:</h3>\n<p>单个星号 <code>*</code> 用于匹配单个片段中的零个或多个字符。</p>\n<h3 id=\"示例-2\"><a class=\"anchor\" href=\"#示例-2\">#</a> 示例:</h3>\n<ul>\n<li><code>src/*.js</code> 表示 <code>src</code> 目录下所有以 <code>js</code> 结尾的文件,但是不能匹配 <code>src </code> 子目录中的文件,例如 <code>src/login/login.js</code></li>\n<li><code>/home/*/.bashrc </code> 匹配所有用户的 .bashrc 文件<div class=\"note danger\">\n<p>需要注意的是, <code>*</code> 不能匹配分隔符 <code>/</code> ,也就是说不能跨片段匹配字符。</p>\n</div>\n</li>\n</ul>\n<h2 id=\"问号\"><a class=\"anchor\" href=\"#问号\">#</a> 问号</h2>\n<h3 id=\"概念-3\"><a class=\"anchor\" href=\"#概念-3\">#</a> 概念:</h3>\n<p>问号 <code>?</code> 匹配单个片段中的单个字符。</p>\n<h3 id=\"示例-3\"><a class=\"anchor\" href=\"#示例-3\">#</a> 示例:</h3>\n<ul>\n<li><code>test/?at.js </code> 匹配形如 <code>test/cat.js</code> 、 <code>test/bat.js</code> 等所有 3 个字符且后两位是 <code>at</code> 的 js 文件,但是不能匹配 <code>test/flat.js</code></li>\n<li><code>src/index.??</code> 匹配 <code>src</code> 目录下以 <code>index</code> 打头,后缀名是两个字符的文件,例如可以匹配 <code>src/index.js </code> 和 <code>src/index.md</code> ,但不能匹配 <code>src/index.jsx</code></li>\n</ul>\n<h2 id=\"中括号\"><a class=\"anchor\" href=\"#中括号\">#</a> 中括号</h2>\n<h3 id=\"概念-4\"><a class=\"anchor\" href=\"#概念-4\">#</a> 概念:</h3>\n<p>同样是匹配单个片段中的单个字符,但是字符集只能从括号内选择,如果字符集内有 <code>-</code> ,表示范围。</p>\n<h3 id=\"示例-4\"><a class=\"anchor\" href=\"#示例-4\">#</a> 示例:</h3>\n<ul>\n<li><code>test/[bc]at.js </code> 只能匹配 <code>test/bat.js</code> 和 <code>test/cat.js</code></li>\n<li><code>test/[c-f]at.js</code> 能匹配 <code> test/cat.js</code> 、 <code>test/dat.js</code> 、 <code>test/eat.js</code> 和 <code>test/fat.js</code></li>\n</ul>\n<h2 id=\"惊叹号\"><a class=\"anchor\" href=\"#惊叹号\">#</a> 惊叹号</h2>\n<h3 id=\"概念-5\"><a class=\"anchor\" href=\"#概念-5\">#</a> 概念:</h3>\n<p>表示取反,即排除那些去掉惊叹号之后能够匹配到的文件。</p>\n<h3 id=\"示例-5\"><a class=\"anchor\" href=\"#示例-5\">#</a> 示例:</h3>\n<p><code>test/[!bc]at.js</code> 不能匹配 <code>test/bat.js</code> 和 <code>test/cat.js</code> ,但是可以匹配 <code>test/fat.js</code> <br />\n <code>!test/tmp/**</code> 排除 <code>test/tmp</code> 目录下的所有目录和文件</p>\n<h1 id=\"扩展语法\"><a class=\"anchor\" href=\"#扩展语法\">#</a> 扩展语法</h1>\n<h2 id=\"两个星号\"><a class=\"anchor\" href=\"#两个星号\">#</a> 两个星号</h2>\n<h3 id=\"概念-6\"><a class=\"anchor\" href=\"#概念-6\">#</a> 概念:</h3>\n<p>两个星号 <code>**</code> 可以跨片段匹配零个或多个字符,也就是说 <code>**</code> 是递归匹配所有文件和目录的,如果后面有分隔符,即 <code>**/ </code> 的话,则表示只递归匹配所有目录(不含隐藏目录)。</p>\n<h3 id=\"示例-6\"><a class=\"anchor\" href=\"#示例-6\">#</a> 示例:</h3>\n<ul>\n<li><code>/var/log/**</code> 匹配 <code>/var/log</code> 目录下所有文件和文件夹,以及文件夹里面所有子文件和子文件夹</li>\n<li><code>/var/log/**/*.log</code> 匹配 <code>/var/log</code> 及其子目录下的所有以 .log 结尾的文件</li>\n<li><code>/home/*/.ssh/**/*.key</code> 匹配所有用户的 <code>.ssh</code> 目录及其子目录内的以 <code>.key</code> 结尾的文件</li>\n</ul>\n<h2 id=\"大括号\"><a class=\"anchor\" href=\"#大括号\">#</a> 大括号</h2>\n<h3 id=\"概念-7\"><a class=\"anchor\" href=\"#概念-7\">#</a> 概念:</h3>\n<p>匹配大括号内的所有模式,模式之间用逗号进行分隔,支持大括号嵌套,支持用 <code>..</code> 匹配连续的字符,即 <code>{start..end}</code> 语法。</p>\n<h3 id=\"示例-7\"><a class=\"anchor\" href=\"#示例-7\">#</a> 示例:</h3>\n<ul>\n<li><code>a.{png,jp{,e}g}</code> 匹配 <code>a.png</code> 、 <code>a.jpg</code> 、 <code>a.jpeg</code></li>\n<li><code>{a..c}{1..2}</code> 匹配 <code>a1`` a2</code> <code>b1</code> <code>b2 ``c1</code> <code>c2</code></li>\n</ul>\n<div class=\"note info\">\n<p>注意: <code>{}</code> 与 <code>[]</code> 有一个很重要的区别:如果匹配的文件不存在, <code>[]</code> 会失去模式的功能,变成一个单纯的字符串,而 <code> {}</code> 依然可以展开。</p>\n</div>\n<h2 id=\"小括号\"><a class=\"anchor\" href=\"#小括号\">#</a> 小括号</h2>\n<h3 id=\"概念-8\"><a class=\"anchor\" href=\"#概念-8\">#</a> 概念:</h3>\n<p>小括号必须跟在 <code> ?</code> 、 <code>*</code> 、 <code>+</code> 、 <code>@</code> 、 <code>!</code> 后面使用,且小括号里面的内容是一组以 <code>| </code> 分隔符的模式集合,例如: <code>abc|a?c|ac*</code> 。</p>\n<h3 id=\"示例-8\"><a class=\"anchor\" href=\"#示例-8\">#</a> 示例:</h3>\n<ul>\n<li><code>?(pattern|pattern|pattern)</code> :匹配 0 次或 1 次给定的模式</li>\n<li><code>*(pattern|pattern|pattern)</code> :匹配 0 次或多次给定的模式</li>\n<li><code>+(pattern|pattern|pattern)</code> :匹配 1 次或多次给定的模式</li>\n<li><code>@(pattern|pattern|pattern)</code> :严格匹配给定的模式</li>\n<li><code>!(pattern|pattern|pattern)</code> :匹配非给定的模式</li>\n</ul>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"glob"
]
},
{
"id": "https://zimu-66ccff.github.io/gitLearn/",
"url": "https://zimu-66ccff.github.io/gitLearn/",
"title": "git命令详解",
"date_published": "2023-11-16T09:39:47.000Z",
"content_html": "<h1 id=\"创建本地-git-仓库\"><a class=\"anchor\" href=\"#创建本地-git-仓库\">#</a> 创建本地 git 仓库</h1>\n<p><code>git init</code> 会在当前目录下创建一个.git 隐藏文件夹</p>\n<h1 id=\"将本地仓库和远程仓库相关联\"><a class=\"anchor\" href=\"#将本地仓库和远程仓库相关联\">#</a> 将本地仓库和远程仓库相关联</h1>\n<ol>\n<li><code>git remote add origin <registry-url></code> 将本地仓库和远程仓库相关联</li>\n<li><code>git remote -v</code> 查看关联的远程仓库</li>\n</ol>\n<h1 id=\"将本地对应的代码提交到暂存区\"><a class=\"anchor\" href=\"#将本地对应的代码提交到暂存区\">#</a> 将本地对应的代码提交到暂存区:</h1>\n<ol>\n<li><code>git add <file> </code> 将指定的 file 提交到暂存区</li>\n<li><code>git add . </code> 将所有有变动的文件提交到暂存区</li>\n</ol>\n<h1 id=\"将暂存区的代码提交到本地-git-仓库\"><a class=\"anchor\" href=\"#将暂存区的代码提交到本地-git-仓库\">#</a> 将暂存区的代码提交到本地 git 仓库:</h1>\n<p><code>git commit -m '<commit-msg>'</code></p>\n<h1 id=\"查看文件状态\"><a class=\"anchor\" href=\"#查看文件状态\">#</a> 查看文件状态</h1>\n<p><code>git status</code> 可以查看哪些文件被修改了,哪些文件提交到暂存区了但是还没有 commit</p>\n<h1 id=\"提交本地-git-仓库代码到远程仓库\"><a class=\"anchor\" href=\"#提交本地-git-仓库代码到远程仓库\">#</a> 提交本地 git 仓库代码到远程仓库:</h1>\n<ol>\n<li><code>git push</code> 会将当前分支的最新的 commit 提交到远程仓库对应的分支,然后本地的对应的远程分支 ( <code>remotes/origin/对应当前分支名</code> ) 也会自动更新</li>\n<li><code>git push origin <source> </code> 会将本地的 <code><source>分支</code> 的最新 commit 提交到远程仓库对应的分支,然后本地的对应的远程分支( <code>remotes/origin/<source></code> )也会自动更新</li>\n<li><code>git push origin <source>:<destination></code> 会将本地的 <code><source>分支</code> 的最新 commit 提交到远程仓库的 <code><destination>分支</code> 然后本地对应的远程分支 ( <code>remotes/origin<destination></code> ) 也会自动更新。 如果 <code><destination>分支</code> 不存在,会在远程仓库自动创建 <code><destination>分支</code> ,然后在本地创建对应的远程分支 ( <code>remotes/origin/<destination></code> ) 并更新</li>\n<li><code>git push origin :<destination> </code> 会在远程仓库直接删除 <code><destination></code> (个人感觉这样设计是因为 push 了一个空给 <code><destination></code> ,所以 git 就理解为你要删除 <code><destination></code> )</li>\n</ol>\n<h1 id=\"拉取远程仓库代码\"><a class=\"anchor\" href=\"#拉取远程仓库代码\">#</a> 拉取远程仓库代码:</h1>\n<ol>\n<li><code>git fetch</code> 会拉取远程仓库的<ins>所有分支</ins>各自对应的最新代码 将远程仓库所有的分支各自的最新的 commit 添加到对应的本地的各个远程分支( <code>remotes/origin/\\*</code> ) <ins>但是不会合并分支</ins>。<ins>也就是说 只需一次命令 就可以将远程仓库的所有的最新更新给拉下来</ins></li>\n<li><code>git fetch origin <source></code> 拉取远程仓库的 <code><source>分支</code> 的最新 commit 然后添加到本地对应的远程分支( <code>remotes/origin/source</code> )但是不会合并分支</li>\n<li><code>git fetch origin <source>:<destination> </code> 拉取远程仓库的 <code><source>分支</code> 的最新 commit 然后添加到本地的 <code><destination>分支</code> 但是不会合并分支。如果 <code><destination></code> 不存在,会在本地以当前分支为基本自动创建 <code><destination></code> 。<br />\n <code>git fetch origin :<destination></code> 会在本地新建一个 <code><destination>分支</code> (感觉这样设计是因为,相当于 fetch 了一个空到本地,所以 git 就会理解为你要新建一个分支)</li>\n</ol>\n<h1 id=\"拉取远程仓库代码并和本地的分支做一个合并\"><a class=\"anchor\" href=\"#拉取远程仓库代码并和本地的分支做一个合并\">#</a> 拉取远程仓库代码,并和本地的分支做一个合并:</h1>\n<ol>\n<li><code>git pull</code> 其实就是 <code>git fetch</code> 和 <code>git merge</code> 的缩写,在 <code>git fetch</code> 的基础上 会将远程分支( <code>remotes/origin/对应当前分支名</code> )和本地当前分支做一个合并</li>\n<li><code>git pull origin <source></code> 会拉取远程仓库的 <code><source>分支</code> 的最新 commit, 然后添加到对应的本地的远程分支上面 ( <code>remotes/origin/<source></code> ),再将这个远程分支和本地当前分支做一个合并</li>\n<li><code>git pull origin <source>:<destination></code> 会将远程仓库的 <code><source>分支</code> 的最新的 commit 添加到本地的 <code><destination></code> 分支上面(如果 <code><destination></code> 不存在,会自动创建),然后将 <code><destination></code> 合并到当前分支。</li>\n</ol>\n<h1 id=\"创建分支\"><a class=\"anchor\" href=\"#创建分支\">#</a> 创建分支:</h1>\n<p><code>git branch <branch-name></code></p>\n<h1 id=\"查看分支\"><a class=\"anchor\" href=\"#查看分支\">#</a> 查看分支:</h1>\n<ol>\n<li><code>git branch</code> 查看本地分支</li>\n<li><code>git branch -r</code> 查看远程分支</li>\n<li><code>git branch -a</code> 查看所有分支</li>\n</ol>\n<h1 id=\"删除分支\"><a class=\"anchor\" href=\"#删除分支\">#</a> 删除分支:</h1>\n<ol>\n<li><code>git branch -d <branch-name></code> 当被删除分支有新内容没有被合并的时候,使用 - d,会提示该分支有新内容没有被合并,不执行删除。</li>\n<li><code>git branch -D <branch-name></code> 当被删除分支有新内容没有被合并的时候,使用 - D,会直接删除</li>\n</ol>\n<h1 id=\"切换分支\"><a class=\"anchor\" href=\"#切换分支\">#</a> 切换分支:</h1>\n<p><code>git checkout <branch-name></code></p>\n<h1 id=\"创建并切换分支\"><a class=\"anchor\" href=\"#创建并切换分支\">#</a> 创建并切换分支:</h1>\n<p><code>git checkout -b <branch-name></code></p>\n<h1 id=\"将分支移动到指定-commit\"><a class=\"anchor\" href=\"#将分支移动到指定-commit\">#</a> 将分支移动到指定 commit:</h1>\n<p><code>git branch -f <branch-name> <commit-hash></code> <br />\n 以<ins>相对移动</ins>的方式将分支移动到指定 commit<br />\n <code>git branch -f <branch-name> HEAD{^[num], ~[num]}</code></p>\n<h1 id=\"代码回滚\"><a class=\"anchor\" href=\"#代码回滚\">#</a> 代码回滚</h1>\n<ol>\n<li><code>git reset --mixed <commit-hash></code> <code>git reset <commit-hash></code> 默认就是这个命令,将<ins>暂存区, 本地 git 仓库</ins>回滚到指定 commit</li>\n<li><code>git reset --hard <commit-hash></code> 将<ins>本地代码,暂存区,本地 git 仓库</ins>回滚到指定 commit</li>\n<li><code>git reset --soft <commit-hash></code> 将<ins>本地 git 仓库</ins>回滚到指定 commit</li>\n<li><code>git revert <commit-hash> </code> 会在当前分支新添加一个 commit 这个 commit 的作用是抵消之前的对应的 commit,也可以用于回滚分支。<br />\n<img data-src=\"https://i.imgs.ovh/2023/11/16/ndPCv.png\" alt=\"ndPCv.png\" /><div class=\"note info\">\n<p>从<ins>数据安全</ins>上角度, <code>revert</code> 比 <code>reset</code> 安全,因为它的操作可以回溯,反转了还可以倒回来。 <code>reset </code> 比较彻底,是直接丢弃了,不过可以考虑想第一个例子中创建一个备份分支来保证安全。<br />\n从<ins>分支历史</ins>的长期维护角度, <code>reset</code> 的历史比较干净, <code>revert </code> 的反转提交没多大意义,毕竟很少有需求让你滚来滚去的。<br />\n在被撤销提交,不在分支顶端的场景上, <code>reset</code> 无法使用, <code>revert</code> 可以做到,。</p>\n</div>\n</li>\n</ol>\n<h1 id=\"合并分支\"><a class=\"anchor\" href=\"#合并分支\">#</a> 合并分支:</h1>\n<ol>\n<li><code>git merge <branch-name></code> 将分支合并到当前分支,会在当前分支新增一个 commit(用来合并需要合并的分支)并且当前分支会自动更新 <ins>不是线性的</ins></li>\n<li><code>git rebase <target-branch-name></code> 将当前分支有的,但是目标分支没有的 commit 直接线性的添加到目标分支 但是目标分支不会自动更新 <ins>是线性的</ins><br />\n<img data-src=\"https://i.imgs.ovh/2023/11/16/nYGdI.png\" alt=\"gitlearn01.png\" /></li>\n</ol>\n<h1 id=\"合并指定的-commit\"><a class=\"anchor\" href=\"#合并指定的-commit\">#</a> 合并指定的 commit:</h1>\n<ol>\n<li><code>git check-chery <commit-hash></code> 将指定的 commit 添加到当前分支 可以一次添加多个 <code>commit</code></li>\n</ol>\n<h1 id=\"切换-head\"><a class=\"anchor\" href=\"#切换-head\">#</a> 切换 HEAD:</h1>\n<ol>\n<li><code>git checkout <commit hash></code></li>\n<li><code>git checkout HEAD{^[num], ~[num]} </code> 注:^ 后面的 num 指的是切换到第几个 parent commit (横向的) ~ 后面的 num 是指以当前 HEAD 为参考,切换到上面第几个 commit</li>\n</ol>\n<h1 id=\"查看-head-指针的移动记录\"><a class=\"anchor\" href=\"#查看-head-指针的移动记录\">#</a> 查看 HEAD 指针的移动记录</h1>\n<p><code>git reflog</code></p>\n<h1 id=\"查看分支历史\"><a class=\"anchor\" href=\"#查看分支历史\">#</a> 查看分支历史</h1>\n<ol>\n<li><code>git log</code> 显示 commit 的 SHA1 值,创建作者和时间,提交信息,会多行显示</li>\n<li><code>git log --oneline</code> 只显示提交的 SHA1 值和提交信息,SHA1 还是缩短显示前几位,只在一行显示</li>\n</ol>\n<h1 id=\"推荐一个特别好的-git-的交互式学习网站\"><a class=\"anchor\" href=\"#推荐一个特别好的-git-的交互式学习网站\">#</a> 推荐一个特别好的 git 的交互式学习网站</h1>\n<p><span class=\"exturl\" data-url=\"aHR0cHM6Ly9sZWFybmdpdGJyYW5jaGluZy5qcy5vcmcv\">https://learngitbranching.js.org/</span></p>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"git"
]
},
{
"id": "https://zimu-66ccff.github.io/npmLink/",
"url": "https://zimu-66ccff.github.io/npmLink/",
"title": "npm link 详解",
"date_published": "2023-11-12T13:20:41.000Z",
"content_html": "<h1 id=\"npm-link-的应用场景\"><a class=\"anchor\" href=\"#npm-link-的应用场景\">#</a> npm link 的应用场景</h1>\n<ol>\n<li>开发脚手架时,在本地调试命令<br />\n开发脚手架时,在项目所在目录,执行 <code>npm link</code> 命令,就可以在全局执行项目的 <code>package.json</code> 文件的 <code>bin</code> 属性里面配置的命令</li>\n<li>可以在项目里,直接使用本地包,从而对本地包进行调试<br />\n当我们开发包 <code>a</code> 时,可以在发布前直接 <code>npm link</code> ,将包 <code>a</code> 链接到全局,然后在项目里 <code>npm link a</code> ,这样就可以在项目里面使用包 <code>a</code> ,从而对包进行调试</li>\n<li>MultiRepo 多仓库多模块应用 本地开发时,多模块之间共享代码的一种解决方案<br />\n当仓库 <code>a</code> 要使用仓库 <code>b</code> 提供的代码的时候,可以在 <code>b</code> 仓库目录下, <code>npm link</code> 从而将仓库 <code>b</code> 链接到全局,然后再在仓库 <code>a</code> 里执行 <code>npm link b</code> , 然后就可以在 <code>a</code> 里导入 <code>b</code> 了。从而实现多仓库共享代码</li>\n</ol>\n<h1 id=\"本地包里执行-npm-link-发生了什么\"><a class=\"anchor\" href=\"#本地包里执行-npm-link-发生了什么\">#</a> 本地包里执行 npm link 发生了什么?</h1>\n<ol>\n<li>\n<p>在 npm 的全局模块目录(node 安装目录下的 <code>node_modules</code> )下会创建一个 <code>软连接(符号链接)</code> ,指向本地包。</p>\n</li>\n<li>\n<p>根据 <code>bin</code> 配置的命令,在可执行目录下创建一个符号链接,指向 <code>bin</code> 里配置的可执行文件。<br />\n例如,如果你的 <code> package.json</code> 文件中有如下配置:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"your-project\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1.0.0\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token property\">\"bin\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token property\">\"your-script\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"./bin/your-script.js\"</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>执行 <code>npm link</code> 后,将在全局的可执行文件目录下创建一个名为 <code>your-script</code> 的符号链接,指向你项目中 <code>./bin/your-script.js</code> 文件。所以当我们在命令行里执行 <code>your-script</code> 的时候,实际相当于执行了 <code>./bin/your-script.js</code></p>\n<div class=\"note info\">\n<p>当我们全局安装包的时候,对 <code>bin</code> 的处理也是类似的,在全局的可执行目录下创建一个符号链接,指向 npm 全局模块目录下我们安装的全局包对应的可执行文件</p>\n</div>\n</li>\n</ol>\n<h1 id=\"项目里面执行-npm-link-package-name-发生了什么\"><a class=\"anchor\" href=\"#项目里面执行-npm-link-package-name-发生了什么\">#</a> 项目里面执行 <code>npm link <package-name></code> 发生了什么</h1>\n<ol>\n<li>在项目的 <code>node_modules</code> 目录下创建一个符号链接,指向 npm 的 <code>全局模块目录</code> 下对应的符号链接(这个符号链接是我们在对应的本地包里执行 <code>npm link</code> 的时候创建的)。然后当我们导入这个包的时候,就会在项目的 <code>node_modules</code> 里找,从而就会找到对应的符号链接,然后这个符号链接又指向 npm 全局模块目录下的符号链接,而这个符号链接又指向本地包文件,从而正确的导入和使用。</li>\n<li>在项目的 <code>node_modules/.bin</code> 目录下根据对应本地包的 <code>bin</code> 创建对应的符号链接指向 npm 全局模块的对应的符号链接的可执行文件。<div class=\"note info\">\n<p>当我们使用 <code>npx</code> 执行命令的时候,实际上是在 <code>node_modules/.bin</code> 找的对应的可执行文件执行的</p>\n</div>\n</li>\n</ol>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"npm link"
]
},
{
"id": "https://zimu-66ccff.github.io/whyMonorepo/",
"url": "https://zimu-66ccff.github.io/whyMonorepo/",
"title": "为什么选择monorepo架构",
"date_published": "2023-11-10T00:14:05.000Z",
"content_html": "<h1 id=\"monolith-和-multirepo-存在什么问题\"><a class=\"anchor\" href=\"#monolith-和-multirepo-存在什么问题\">#</a> Monolith 和 MultiRepo 存在什么问题</h1>\n<h2 id=\"monolith-单仓库巨石应用\"><a class=\"anchor\" href=\"#monolith-单仓库巨石应用\">#</a> Monolith 单仓库巨石应用</h2>\n<p>用一个 git 仓库来维护项目代码,随着业务复杂度的上升,代码量会急剧上升,最终项目会变得十分庞大,复杂, 难以继续维护,更新迭代,并且构建效率也会降低。</p>\n<ul>\n<li>存在的问题:\n<ol>\n<li>代码耦合度非常高,可能改了这里,又会影响那里,并且当我们排查问题时,难度也变得非常高,可能很多时间都花在了找代码上面。</li>\n<li>代码量非常大,项目构建的效率低下,明明只改了一点点代码,却要重新构建整个代码,构建花费的时间非常长。</li>\n</ol>\n</li>\n</ul>\n<h2 id=\"multirepo-多仓库多模块应用\"><a class=\"anchor\" href=\"#multirepo-多仓库多模块应用\">#</a> MultiRepo 多仓库多模块应用</h2>\n<p>将一个项目拆解为多个多个模块,放在多个 git 仓库里面管理,直接的对项目进行了解耦,每个单独的模块都可以独立的编码,测试,发布。</p>\n<ul>\n<li>存在的问题\n<ol>\n<li>各个仓库之间的代码共享非常困难,粗糙,一般想要进行代码的共享只有如下几种方式:\n<ol>\n<li>将需要共享的代码复制粘贴到自己的仓库里<br />\n这种方式会明显的造成<ins>代码体积变大</ins>,从而<ins>影响构建效率</ins></li>\n<li>将需要共享的代码单独维护成一个仓库,发布成 npm 包,<br />\n这样方式很麻烦,<ins>每次都需要,重新发布 npm 包,然后在使用了这些共享的代码的仓库里 <code>npm install</code> 更新 npm 包</ins>。<br />\n<ins>并且当维护的 npm 包出现了 <code>break change</code> 的时候,只有等到 npm 包发布,并且各个仓库更新了 npm 包的时候,才能发现问题,问题发现不及时,导致排查问题,解决问题,十分困难</ins>。</li>\n<li>通过 <code>npm link</code> 来实现本地开发的时候共享代码,这种方式相比上面两种方式好了很多,但是依旧需要手动在需要共享代码的仓库里 <code>npm link</code> ,在需要使用其他仓库共享的代码的仓库里 <code>npm link <package-name></code></li>\n</ol>\n</li>\n<li>版本管理很困难,当一个仓库有更新,需要发布的时候,需要在其他所有依赖这个仓库的仓库里执行 <code>npm install</code> 来使用这个刚更新仓库的最新版本。</li>\n<li>无法积累一个统一的工程化配置,从而复用,每次有新的项目的时候都要重新配置一次几乎一摸一样的, <code>ci</code> , <code>lint</code> , <code>构建</code> ,等流程</li>\n</ol>\n</li>\n</ul>\n<h1 id=\"采用-monorepo-架构-可以解决这些问题吗会有哪些好处\"><a class=\"anchor\" href=\"#采用-monorepo-架构-可以解决这些问题吗会有哪些好处\">#</a> 采用 Monorepo 架构 可以解决这些问题吗?会有哪些好处</h1>\n<h2 id=\"将-monolith-巨石应用-换成-monorepo-架构\"><a class=\"anchor\" href=\"#将-monolith-巨石应用-换成-monorepo-架构\">#</a> 将 Monolith 巨石应用 换成 Monorepo 架构</h2>\n<ol>\n<li>将巨石应用,分为了不同的模块,在一定程度上进行了<ins>解耦</ins>,明显的降低了耦合性,既<ins>降低了维护成本(找代码,改代码)</ins>,<ins>也降低了新人上手门槛</ins>。</li>\n<li>当代码有更新,有变动的时候,只需要进行<ins>增量构建</ins>,只构建,发布,有变动的模块和使用了有变动的模块的模块,而不需要构建所有的代码,大大提升了<ins>构建效率</ins>。</li>\n</ol>\n<h2 id=\"将-multirepo-多仓库多模块应用-换成-monorepo-架构\"><a class=\"anchor\" href=\"#将-multirepo-多仓库多模块应用-换成-monorepo-架构\">#</a> 将 MultiRepo 多仓库多模块应用 换成 Monorepo 架构</h2>\n<ol>\n<li>模块之间的代码共享,更加<ins>便捷</ins>,<ins>安全</ins>,<ins>问题发现更加及时</ins>。所有的模块都在一个仓库里,可以很轻松的使用维护的对外共享代码的模块共享的代码,并且当对外共享代码的模块出现问题时,在<ins>开发阶段</ins>就可以及时发现,解决,而不是像 <code>MultiRepo</code> 一样,只能等到 npm 包发布,才能发现。</li>\n<li>现代的众多 <code>monorepo</code> 工具可以实现<ins>自动的版本管理</ins>,当有模块更新的时候,自动更新该模块,和使用了该模块的模块。</li>\n<li>可以<ins>积累下统一的工程化配置</ins>,多模块共同使用,<ins>当有新的项目的时候,可以作为一个新的模块直接接入,不再需要进行重复的工程化配置</ins>。</li>\n<li>所有的项目,公共函数库,公共组件库,都作为一个模块在一个仓库里,作为<ins>数据资产落地</ins>下来,<ins>便于新人快速上手</ins>,知晓有哪些公共函数,公共组件,可以使用,并维护,提升开发效率。</li>\n</ol>\n<h1 id=\"直接无脑的使用-monorepo-架构会带来哪些问题呢可以解决吗\"><a class=\"anchor\" href=\"#直接无脑的使用-monorepo-架构会带来哪些问题呢可以解决吗\">#</a> 直接无脑的使用 Monorepo 架构,会带来哪些问题呢,可以解决吗?</h1>\n<h2 id=\"可能带来的问题\"><a class=\"anchor\" href=\"#可能带来的问题\">#</a> 可能带来的问题</h2>\n<ol>\n<li>所有的项目都作为模块在同一个仓库里,可能出现改了其他模块的代码,并且负责该模块的同事还不知道,结果出现了问题。</li>\n<li>在维护对外共享代码的模块(比如,组件库,函数库, hooks 库)的时候,无意间造成了 <code>break change</code> ,从而影响了其他使用了该模块的模块的正常运转。</li>\n<li>在更新对外共享代码的模块的时候,不通知更新内容,从而使其他同事不知道公共模块多了哪些东西,导致对外共享模块形同虚设,无法发挥作用。</li>\n</ol>\n<h2 id=\"解决方案\"><a class=\"anchor\" href=\"#解决方案\">#</a> 解决方案</h2>\n<p>团队需要有严格的 <code>commit msg</code> 规范,每次的 <code>commit msg</code> 必须附上,更改的模块名;当公共模块有更新的时候,必须写上更新内容,并告知团队成员,一方面当不小心造成 <code>break change</code> 时,团队成员能够及时发现,并解决。另一方面,团队成员可以及时知道公共模块更新了哪些内容,自己是否可以用到,从而放公共模块发挥作用。<br />\n团队需要有严格的 <code>code review</code> 作为兜底</p>\n<h1 id=\"总结\"><a class=\"anchor\" href=\"#总结\">#</a> 总结</h1>\n<p>Monorepo 架构确实拥有着很大的优势(解耦;增量构建,提升构建效率;代码共享;积累统一的工程化配置,公共库,从而提高开发效率,积累数据资产;降低新人上手门槛),可以带来很多积极的作用,但是对团队规范有一定的要求,无脑的使用,可能会带来很多致命的问题,但是可以通过严格的团队规范来避免。</p>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"monorepo"
]
},
{
"id": "https://zimu-66ccff.github.io/pnpmLearn/",
"url": "https://zimu-66ccff.github.io/pnpmLearn/",
"title": "为什么选择pnpm来替代npm,yarn",
"date_published": "2023-10-31T08:51:37.000Z",
"content_html": "<h1 id=\"npm-yarn-遇到了什么问腿\"><a class=\"anchor\" href=\"#npm-yarn-遇到了什么问腿\">#</a> npm, yarn, 遇到了什么问腿?</h1>\n<p>为了得到这个问题的答案,我们需要对 npm,yarn 执行 <code>npm install</code> or <code>yarn install</code> 后,在 <code>node_modules</code> 文件夹里面是怎么管理依赖的。</p>\n<h2 id=\"npm3-版本之前对依赖的管理\"><a class=\"anchor\" href=\"#npm3-版本之前对依赖的管理\">#</a> npm3 版本之前对依赖的管理</h2>\n<p>npm3 版本之前在生成的 <code>node_modules</code> 文件夹对依赖的管理是<ins>嵌套结构</ins>的</p>\n<p>假设我们有一个项目,它依赖于 <code>b</code> 包, <code>c </code> 包, <code>b</code> 包又依赖于 <code>d</code> 包和 <code>f</code> 包, <code>c</code> 包又依赖于 <code>d</code> 包和 <code>f</code> 包<br />\n依赖关系如下:<br />\n<img data-src=\"https://i0.imgs.ovh/2023/10/31/AIEns.png\" alt=\"pnpmLearn01.png\" /></p>\n<p>当我们运行 <code>npm install</code> 的时候,生成的 <code>node_modules</code> 文件夹中对依赖的管理会是嵌套结构的,如下:</p>\n<pre><code>node_modules\n├── b\n| └── node_modules\n| └── d\n| └── f\n├── c\n| └── node_modules\n| └── d\n| └── e\n</code></pre>\n<p>我们可以发现,是和依赖关系对应的嵌套结构</p>\n<h2 id=\"npm3-版本之前对依赖的管理方式嵌套式的-node_modules-文件结构的缺陷\"><a class=\"anchor\" href=\"#npm3-版本之前对依赖的管理方式嵌套式的-node_modules-文件结构的缺陷\">#</a> npm3 版本之前对依赖的管理方式:嵌套式的 node_modules 文件结构的缺陷</h2>\n<ol>\n<li>嵌套的可能会非常深,就像 <code>d</code> 又依赖于 <code>d1</code> , <code>d1</code> 又依赖于 <code>d2</code> , <code>d2</code> 又依赖于 <code>d3</code> , 如此下去,嵌套的就会非常深,有的操作系统可能就难以支持了</li>\n<li>同一个项目里会出现依赖重复安装,我们可以看到 d 包是被安装了两次的,在 b 包的 <code>node_modules</code> 里被安装了一次,在 <code>c</code> 包的 <code>node_nodules</code> 又被重复安装了一次</li>\n<li>不同的项目里都依赖同一个依赖的时候,这个依赖在磁盘里会被重复安装。比如 <code>x</code> 项目和 <code>y</code> 项目都依赖于 <code>z</code> 包,那么 <code>z</code> 包就会在磁盘里被安装两次</li>\n</ol>\n<h2 id=\"npm3-版本之后和-yarn-对依赖的管理\"><a class=\"anchor\" href=\"#npm3-版本之后和-yarn-对依赖的管理\">#</a> npm3 版本之后和 yarn 对依赖的管理</h2>\n<p>npm3 以后的版本和 yarn 生成的 <code>node_modules</code> 文件夹是<ins>扁平结构的</ins><br />\n根据我们上面的项目例子,它的 <code>node_modules</code> 文件夹结构应该是如下的:</p>\n<pre><code>node_modules\n├── b\n├── c\n├── d\n├── f\n└── e\n\n</code></pre>\n<p>我们可以发现所有的依赖都被拍平了,是扁平化的,都被提升到了 node_modules 文件夹下面,而不是嵌套的。</p>\n<h2 id=\"npm3-版本之后和-yarn-对依赖的管理方式扁平式的-node_modules-文件结构-解决了之前的哪些问题\"><a class=\"anchor\" href=\"#npm3-版本之后和-yarn-对依赖的管理方式扁平式的-node_modules-文件结构-解决了之前的哪些问题\">#</a> npm3 版本之后和 yarn 对依赖的管理方式:扁平式的 node_modules 文件结构 解决了之前的哪些问题</h2>\n<ol>\n<li>解决了嵌套的非常深的问题<br />\n采用了扁平式的结构,完全不存在嵌套</li>\n<li>解决了同一个项目里依赖重复安装的问题<br />\n我们可以看到 <code>d包</code> 在 <code>node_modules</code> 文件夹下面是只安装了一次的。<br />\n那么 <code>b包</code> or <code>c包</code> 包要怎么找到他们依赖的 <code>d</code> 包呢,因为他们自己目录下没有 <code>node_modules</code> ,就会到上层目录里找 <code>node_modules</code> ,就可以找到项目根目录下面的 <code>node_modules</code> ,里面就有他们需要的 <code>d</code> 包<br />\n<ins> ps:依赖的查找方式是先在自己包目录下的 node_modules 目录下面找,如果不存在 or 没找到,就到上层目录的 node_modules 目录找,以此方式,不断的往上找</ins></li>\n</ol>\n<h2 id=\"npm3-版本之后-和-yarn-对依赖的管理方式扁平式的-node_modules-文件结构-带来了哪些新的问题-还存在哪些问题\"><a class=\"anchor\" href=\"#npm3-版本之后-和-yarn-对依赖的管理方式扁平式的-node_modules-文件结构-带来了哪些新的问题-还存在哪些问题\">#</a> npm3 版本之后 和 yarn 对依赖的管理方式:扁平式的 node_modules 文件结构 带来了哪些新的问题,还存在哪些问题</h2>\n<ul>\n<li>带来的新的问题\n<ol>\n<li>带了了 <code>幽灵依赖的问题</code>\n<ul>\n<li>什么是幽灵依赖<br />\n在我们上面的例子里,我们项目 <code>a</code> 只依赖于 <code>b</code> 和 <code>c</code> ,也就是说 <code>package.json</code> 里的 <code>dependencies</code> 只声明了 <code>b</code> 和 <code>c</code> ,但是因为扁平化的结构,我们可以在项目里使用 <code>package.json</code> 的 <code>dependencies</code> 里没有声明的 <code>d</code> , <code>e</code> , <code>f</code> 。 <code>d</code> , <code>e</code> , <code>f</code> 这三个依赖没有在项目目录的 <code>package.json</code> 里声明,但是却可以使用,这种依赖就被称为 <code>幽灵依赖</code></li>\n<li><code>幽灵依赖</code> 会造成什么后果<br />\n <code>d</code> 是被 <code>b</code> 依赖的,然后因为 <code>扁平化</code> 的结构,我们才能使用,那么如果有一天 <code>b</code> 不在依赖于 <code>d</code> 了,那么我们一旦 <code>npm install</code> , <code>node_modules</code> 里就不会再有 <code>d</code> 了,而我们的项目代码还在使用 <code>d</code> ,那么马上就会报错</li>\n</ul>\n</li>\n</ol>\n</li>\n<li>之前存在但是没有得到解决的问题\n<ol>\n<li>不同的项目里都依赖同一个依赖的时候,这个依赖在磁盘里会被重复安装。</li>\n</ol>\n</li>\n</ul>\n<h1 id=\"为什么选择-pnpmpnpm-的优势\"><a class=\"anchor\" href=\"#为什么选择-pnpmpnpm-的优势\">#</a> 为什么选择 pnpm(pnpm 的优势)</h1>\n<h2 id=\"pnpm-对依赖的管理\"><a class=\"anchor\" href=\"#pnpm-对依赖的管理\">#</a> pnpm 对依赖的管理</h2>\n<p>pnpm 对依赖的管理是一种扁平式和嵌套式相结合的,利用了软连接和硬链接的一种结构</p>\n<p><ins>ps: 这里简单的讲解一下什么是软连接,什么是硬链接</ins></p>\n<ul>\n<li>硬链接<br />\n在操作系统的文件系统里,磁盘的文件都会有一个编号叫索引节点号 (Inode Index), 而硬链接就是文件名直接指向这个索引号,从而找到磁盘里的文件内容。并且可以存在多个文件硬链接同一个索引节点号。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。</li>\n<li>软连接<br />\n软连接也叫符号链接,它是一个保存有其他文件位置信息的文件,指向的是其他文件的位置信息,而不是磁盘里的文件的索引节点号。所以一旦它指向的那个文件被删除,它就找不到了</li>\n<li>详细的讲解请看这篇文章<br />\n<span class=\"exturl\" data-url=\"aHR0cHM6Ly93d3cuY25ibG9ncy5jb20vaXRlY2gvYXJjaGl2ZS8yMDA5LzA0LzEwLzE0MzMwNTIuaHRtbA==\"> Linux 软连接和硬链接</span></li>\n</ul>\n<p>依旧是我们上面的例子,它的 <code>node_modules</code> 文件夹结构应该是如下的:</p>\n<pre><code>node_modules\n├── .pnpm\n └── b // 硬连接 指向的是磁盘里的b包\n └── node_modules\n └── d // 软连接 指向的是 .pnpm/d\n └── f // 软连接 指向的是 .pnpm/f\n └── c\n └── node_modules\n └── d // 软连接 指向的是 .pnpm/d\n └── e // 软连接 指向的是 .pnpm/e\n └── d // 硬连接 指向的是磁盘里的d包\n └── e // 硬连接 指向的是磁盘里的e包\n └── f // 硬连接 指向的是磁盘里的f包\n └── node_modules\n └── b // 软连接 指向的是.pnpm/b\n └── c // 软连接 指向的是.pnpm/c\n └── d // 软连接 指向的是.pnpm/d\n └── e // 软连接 指向的是.pnpm/e\n └── f // 软连接 指向的是.pnpm/f\n├── b // 软连接 指向的是 .pnpm/b\n├── c // 软连接 指向的是 .pnpm/c\n</code></pre>\n<p>看到这个文件结构的时候第一感觉肯定是,好复杂啊,一下子多了好多东西,没关系,我接下来会逐一介绍为什么会是这样的,然后你就会发现这个结构真的是十分巧妙</p>\n<ul>\n<li>\n<p>node_modules</p>\n<ol>\n<li>\n<p>我们会发现 <code>node_modules</code> 目录下的包文件和我们项目里的 <code>package.json</code> 里 <code>dependencies</code> 声明的包是一摸一样的。这样就可以有效的避免 <code>幽灵依赖的问题</code> ,项目里就不能直接使用 <code>d</code> , <code>e</code> , <code>f</code> 这些幽灵依赖了,因为 <code>node_modules</code> 里面没有。<ins>完美解决幽灵依赖的问题</ins></p>\n</li>\n<li>\n<p>好,聪明的你马上就会问, <code>b</code> , <code>c</code> 都有各自的依赖呀,可是 <code>node_modules/b</code> , <code>node_modules/c</code> 里面没有 <code>node_modules</code> 呀,那怎么找到他们的依赖呢。那么现在就告诉你真相, <code>node_modules/</code> 下面的包文件全部都是 <code>软连接</code> ,他们都指向 <code>node_modules/.pnpm/</code> 目录下 对应的包,也就是 <code>node_modules/.pnpm/b</code> , <code>node_modules/.pnpm/c</code> , 他们下面就有对应的 <code>node_modules</code> 来存储他们各自对应的依赖啦。</p>\n</li>\n</ol>\n</li>\n<li>\n<p>node_modules/.pnpm</p>\n<ol>\n<li>我们会发现 <code>node_modules/.pnpm</code> 目录下拥有着我们项目所有的依赖, <code>b</code> , <code>c</code> , <code>d</code> , <code>e</code> , <code>f</code> ,并且是扁平化的,而且他们都是 <code>硬链接</code> 。都指向磁盘里的 <code>b</code> , <code>c</code> , <code>d</code> , <code>e</code> , <code>f</code> 。这样当我们在其他项目里面也有这些依赖的时候,就不需要在磁盘里面重复安装,直接一个 <code>硬连接</code> 指向磁盘里对应的文件就可以。<ins>完美解决不同项目里同样的依赖在磁盘里重复安装的问题</ins></li>\n</ol>\n</li>\n<li>\n<p>node_modules/.pnpm/ 包文件 /node_modules</p>\n<ol>\n<li>我们会发现 <code>node_modules/.pnpm/包文件/node_modules/</code> 目录下拥有者包所需要的依赖, 而这些依赖其实都是软连接,指向 <code>node_modules/.pnpm</code> 目录下对应的包文件。在这里就是 <code>node_modules/.pnpm/b/</code> 下面有着 <code>d</code> , <code>f</code> , 但其实这个 <code>d</code> , <code>f</code> 都是软连接,指向 <code>node_modules/.pnpm/d</code> , <code>node_modules/.pnpm/f</code> 。这样虽然 <code>b</code> , <code>c</code> 都依赖于 <code>d</code> , 但是却不会重复安装,而是都指向 <code>node_modules/.pnpm/d</code> 。 <ins>完美解决同一项目里依赖重复安装的问题</ins></li>\n</ol>\n</li>\n<li>\n<p>node_modules/.pnpm/node_modules</p>\n<ol>\n<li>我们会发现 <code>node_modules/.pnpm/node_modules</code> 这个目录下存有项目的所有依赖。当然,都是软连接,指向 <code>node_modules/.pnpm</code> 下面的包,那么这个文件夹到底是什么作用呢。</li>\n<li>我们都知道 <code>幽灵依赖</code> 是不安全的,是很容易导致问题的,但是现实是,依旧很多第三方包使用了幽灵依赖,而我们的 pnpm 也对幽灵依赖做了兼容,在特定的情况下是允许幽灵依赖的,那么幽灵依赖在哪找呢,就是这个目录下面,这个目录是扁平化的,拥有项目所有的包。 <ins>实现了对幽灵依赖的支持 但是最好不要这样 因为幽灵依赖并不安全</ins></li>\n</ol>\n</li>\n</ul>\n<h2 id=\"pnpm-的优势解决了哪些问题\"><a class=\"anchor\" href=\"#pnpm-的优势解决了哪些问题\">#</a> pnpm 的优势,解决了哪些问题</h2>\n<ol>\n<li>通过软连接避免了 <code>幽灵依赖</code> 的问题</li>\n<li>通过硬连接解决了 <code>不同项目的相同依赖</code> 在磁盘重复安装的问题,提升了速度</li>\n<li>通过软连接, <code>node_modules/.pnpm</code> 的 <code>扁平化</code> 结构解决了 <code>同一项目里相同依赖</code> 重复安装的问题</li>\n<li>通过软连接和 <code>node_modules/.pnpm/node_modules</code> 目录,兼容了 <code>幽灵依赖</code></li>\n</ol>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"pnpm",
"包管理器"
]
},
{
"id": "https://zimu-66ccff.github.io/plopLearn/",
"url": "https://zimu-66ccff.github.io/plopLearn/",
"title": "plop-一个基于模板的代码生成器",
"date_published": "2023-10-29T09:53:34.000Z",
"content_html": "<h1 id=\"plop-是什么为什么需要-plop\"><a class=\"anchor\" href=\"#plop-是什么为什么需要-plop\">#</a> plop 是什么,为什么需要 plop</h1>\n<p>Plop is a little tool that saves you time and helps your team build new files with consistency.<br />\n 这是官网对于 plop 的评价,实际上也确实是这样, plop 可以通过命令和用户配置的 hbs 模板文件来在指定的目录下生成对应的模板代码。想一想,我们只需要通过一个命令,就可以在我们需要的目录下生成对应的文件,里面有本来需要我们手写的结构代码,这该是一件多爽的事情,可以大大的节约我们的时间</p>\n<h1 id=\"plop-体验\"><a class=\"anchor\" href=\"#plop-体验\">#</a> plop 体验</h1>\n<h2 id=\"下载-plop推荐全局下载\"><a class=\"anchor\" href=\"#下载-plop推荐全局下载\">#</a> 下载 plop (推荐全局下载)</h2>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">pnpm</span> <span class=\"token function\">install</span> plop <span class=\"token parameter variable\">-g</span></pre></td></tr></table></figure><h2 id=\"编写模板代码\"><a class=\"anchor\" href=\"#编写模板代码\">#</a> 编写模板代码</h2>\n<pre><code><!-- templates/sfc/index.vue.hbs -->\n\n<script setup lang="ts">\n{{> importVueRef}}\n</script>\n\n<template>\n <div class="{{componentName}}"></div>\n</template>\n\n<style scoped lang="less">\n.{{componentName}}\n{}\n</style>\n</code></pre>\n<p>在根目录下新建一个文件夹存放我们对应的模板代码,plop 后面会根据这些模板代码来生成我们需要的代码</p>\n<p>你可能已经发现了出现了 <code>{{componentName}}</code> 这样的代码 <code>{{}}</code> 这个叫模板语法,你可能会说这不是和 vue 的模板语法是一样的嘛 是的 是一样的 因为 vue 的模板语法就是借鉴(抄)的这个 那么你应该会好奇 componentName 的值是什么呢 这个将会在命令里传递 请继续往下看</p>\n<h3 id=\"在项目根目录创建我们的-plopfilejs-文件\"><a class=\"anchor\" href=\"#在项目根目录创建我们的-plopfilejs-文件\">#</a> 在项目根目录创建我们的 plopfile.js 文件</h3>\n<pre><code>export default function (plop) {\n plop.setGenerator('createSFC', {\n description: 'create one SFC',\n prompts: [{ type: 'input', name: 'componentName', message: 'input componentName' }],\n actions: (data) => {\n return [\n {\n type: 'add',\n path: './src/{{camelCase componentName}}/index.vue',\n templateFile: './templates/sfc/index.vue.hbs',\n },\n ];\n },\n });\n plop.setPartial('importVueRef', `import {Ref} from 'vue' `);\n}\n</code></pre>\n<p>简单讲解一下,我们用 <code>plop</code> 这个对象身上的 <code>setGenerator</code> 命令,配置了一个命令, <code>createSFC</code> 是这个命令的名字(自己取),然后通过终端输入 <code>plop createSFC</code> 这个命令来使用。<br />\n <code>description</code> 是对这个命令功能的描述,当我们输入 <code>plop</code> 命令的时候,终端会列出所有的 plop 命令和它的描述(就是我们这里 description 写的).<br />\n <code>prompts</code> 是一个数组,数组里面的元素是一个对象(用来描述终端提示语的)</p>\n<ul>\n<li>type<br />\n 这个提示的类型,这里是 'input',</li>\n<li>name<br />\n 定义变量名 (这里的变量名是 componentName),用来存储用户将从终端输入的值 (因为是 input 类型,所以是用户输入一个值)。</li>\n<li>message<br />\n 提示信息</li>\n</ul>\n<p><code>action</code> 是这个命令具体将执行的操作,是一个数组,因为一个命令是可以执行多个操作的。</p>\n<ul>\n<li>type<br />\n 操作的类型,这里是 'add', 也就是在指定目录下生成一个文件</li>\n<li>path<br />\n 生成的文件的路径, <code>'./src/{{camelCase componentName}}/index.vue'</code> , 这里又出现了插值语法, <code>componentName</code> 是我们在 <code>prompts</code> 里面配置的用户输入的,我们假设输入的是 'button-success', 你可能注意到了前面还有一个 <code>camelCase</code> ,这个是一个 <code>helper</code> ,它的作用是把 componentName 的值变成驼峰形式,也就是说用户输入的 'button-success' 会变成 'buttonSuccess'。也就是说实际上生成的文件路径会是 <code>./src/buttonSuccess/index.vue</code> 。</li>\n<li>templateFile<br />\n 我们写的模板代码,也就是 hbs 文件的路径,在这里就是生成的 <code>index.vue</code> 文件的代码将会是这个 <code>'./templates/sfc/index.vue.hbs'</code> 文件里的代码</li>\n</ul>\n<h2 id=\"在-packagejson-文件的-script-里面配置脚本\"><a class=\"anchor\" href=\"#在-packagejson-文件的-script-里面配置脚本\">#</a> 在 package.json 文件的 script 里面配置脚本</h2>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"scripts\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"plop\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"plop\"</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><h2 id=\"执行命令\"><a class=\"anchor\" href=\"#执行命令\">#</a> 执行命令</h2>\n<ol>\n<li>执行 <code>pnpm plop</code> 命令<br />\n<img data-src=\"https://i0.imgs.ovh/2023/10/29/AVTPm.png\" alt=\"plopLearn01.png\" /></li>\n<li>输入 <code>componentName</code> <br />\n<img data-src=\"https://i0.imgs.ovh/2023/10/29/AVq6N.png\" alt=\"plopLearn02.png\" /></li>\n<li>src/buttonSuccess 目录下就生成了 index.vue 代码了</li>\n<li>查看 src/buttonSuccess/index.vue 的代码<br />\n<img data-src=\"https://i0.imgs.ovh/2023/10/29/AVGGp.png\" alt=\"plop03.png\" /><br />\n 我们可以发现和我们的模板代码 hbs 文件几乎是一样的,并且 <code>{{componentName}}</code> 这种插值语法也已经被正确的替换为了用户输入的 <code>buttonSucess</code> (用户输入的 button-success, 但是被我们设置的 camelCase 给转化成了驼峰形式)</li>\n</ol>\n<h1 id=\"plop-的-api-讲解\"><a class=\"anchor\" href=\"#plop-的-api-讲解\">#</a> plop 的 api 讲解</h1>\n<h2 id=\"sethelper\"><a class=\"anchor\" href=\"#sethelper\">#</a> setHelper</h2>\n<p>用来自定义 <code>helper</code> , <code>helper</code> 用来对值做转换,例如:</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">plop</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> plop<span class=\"token punctuation\">.</span><span class=\"token function\">setHelper</span><span class=\"token punctuation\">(</span><span class=\"token string\">'upperCase'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">text</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token keyword\">return</span> text<span class=\"token punctuation\">.</span><span class=\"token function\">toUpperCase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>第一个参数为 helper 的名字,这里是 "upperCase", 第二个参数为处理函数,这里是将值转换为大写</p>\n<ul>\n<li>\n<p>使用方式:</p>\n<pre><code>{{upperCase componentName}}\n</code></pre>\n</li>\n<li>\n<p>效果:<br />\n假设 componentName 本来的值是 "button", 那么它最终会被转换成 'BUTTON'</p>\n</li>\n<li>\n<p>自带的 helper(这些 helper 为 plop 自带的,可以直接使用):</p>\n<ul>\n<li>camelCase: changeFormatToThis</li>\n<li>snakeCase: change_format_to_this</li>\n<li>dashCase/kebabCase: change-format-to-this</li>\n<li>dotCase: change.format.to.this</li>\n<li>pathCase: change/format/to/this</li>\n<li>properCase/pascalCase: ChangeFormatToThis</li>\n<li>lowerCase: change format to this</li>\n<li>sentenceCase: Change format to this,</li>\n<li>constantCase: CHANGE_FORMAT_TO_THIS</li>\n<li>titleCase: Change Format To This</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"setpartial\"><a class=\"anchor\" href=\"#setpartial\">#</a> setPartial</h2>\n<p>用来自定义局部的模板,例如:</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token comment\">/** @type {import('plop').NodePlopAPI} */</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> plop</pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> plop<span class=\"token punctuation\">.</span><span class=\"token function\">setPartial</span><span class=\"token punctuation\">(</span><span class=\"token string\">'importVueRef'</span><span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">import {Ref} from 'vue' </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>第一个参数为局部模板的名字,这里是 'importVueRef', 第二个人参数为模板,这里是 'import {Ref} from 'vue'</p>\n<ul>\n<li>使用方式:</li>\n</ul>\n<pre><code>{{> importVueRef}}\n</code></pre>\n<ul>\n<li>效果:<br />\n <code>{{> importVueRef}}</code> 会变成 <code>import {Ref} from 'vue</code></li>\n</ul>\n<h1 id=\"内置的-actions-type\"><a class=\"anchor\" href=\"#内置的-actions-type\">#</a> 内置的 actions type</h1>\n<h2 id=\"add\"><a class=\"anchor\" href=\"#add\">#</a> add</h2>\n<p>用来在指定的路径生成文件</p>\n<ul>\n<li>常用属性(其他属性请查官网)\n<ul>\n<li>path<br />\nstring 类型,生成的文件的路径</li>\n<li>template<br />\nstring 类型,模板,以这个模板来生成文件(说白点,就是生成的文件的代码会和这个模板一摸一样)</li>\n<li>templateFile<br />\nstring 类型,模板代码文件的路径,会以这个路径的模板文件来生成文件</li>\n<li>force<br />\nboolean 类型,当该文件已经存在的时候,是否覆盖</li>\n<li>data<br />\n 对象或者函数类型(函数要返回一个对象),为模板提供额外的数据(就是为那些插值语法提供额外的数据)</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"addmany\"><a class=\"anchor\" href=\"#addmany\">#</a> addMany</h2>\n<p>将多个目录和文件添加到指定目录</p>\n<ul>\n<li>常用属性(其他属性请查官网)\n<ul>\n<li>destination<br />\nstring 类型,在该路径下添加文件</li>\n<li>base<br />\nstring 类型, 在该路径下匹配目录和文件,匹配到的目录和文件将会被添加到对应路径下面</li>\n<li>templateFiles<br />\nglob 类型, 以该模式匹配目录和文件的模式, 比如 templates/components/*, 就是匹配 templates 目录下的 components 目录下的所有文件</li>\n<li>stripExtensions<br />\n 添加到指定目录时自动删掉对应的后缀名,默认值为 ['hbs'], 也就是说添加文件的时候.hbs 后缀会被默认删掉。比如说文件名为 index.vue.hbs, 添加的时候就会变成 index.vue</li>\n<li>force<br />\nboolean 类型,当该文件已经存在的时候,是否覆盖</li>\n<li>data<br />\n 对象或者函数类型(函数要返回一个对象),为模板提供额外的数据(就是为那些插值语法提供额外的数据)</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"modify\"><a class=\"anchor\" href=\"#modify\">#</a> modify</h2>\n<p>用于替换指定文件中的匹配到的文本</p>\n<ul>\n<li>常用属性(其他属性请查官网)\n<ul>\n<li>path<br />\n 同上</li>\n<li>pattern<br />\n 正则表达式,用于匹配文本</li>\n<li>template<br />\nstring 类型,用于将匹配到的文本替换成这个模板</li>\n<li>templateFile<br />\nstring 类型, 模板的路径,以该路径的模板来替换匹配到的文本</li>\n<li>transform<br />\n 函数类型,用来转换文件内容</li>\n<li>data<br />\n 同上</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"append\"><a class=\"anchor\" href=\"#append\">#</a> append</h2>\n<p>用于在指定文件中匹配到的文本后面添加内容</p>\n<ul>\n<li>常用属性(其他属性请查官网)\n<ul>\n<li>path<br />\n 同上</li>\n<li>pattern<br />\n 正则表达式,用于匹配文本</li>\n<li>template<br />\nstring 类型,用于在匹配到的文本后面添加这个模板</li>\n<li>templateFile<br />\nstring 类型, 模板的路径,将该路径的模板添加到匹配到的文本后面</li>\n<li>transform<br />\n 函数类型,用来转换文件内容</li>\n<li>data<br />\n 同上</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"内置的-promps-type\"><a class=\"anchor\" href=\"#内置的-promps-type\">#</a> 内置的 promps type</h2>\n<p>和 inquire 的一样 详细的可以查看 inquire 的官网<br />\n<span class=\"exturl\" data-url=\"aHR0cHM6Ly9naXRodWIuY29tL1NCb3Vkcmlhcy9JbnF1aXJlci5qcw==\"> https://github.com/SBoudrias/Inquirer.js</span></p>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"plop",
"脚手架"
]
},
{
"id": "https://zimu-66ccff.github.io/packageJsonLearn/",
"url": "https://zimu-66ccff.github.io/packageJsonLearn/",
"title": "package.json文件详解",
"date_published": "2023-10-28T06:56:50.000Z",
"content_html": "<h1 id=\"packagejson-是什么\"><a class=\"anchor\" href=\"#packagejson-是什么\">#</a> package.json 是什么</h1>\n<p><code>package.json</code> 文件会描述我们项目的所有配置信息(名称,版本,使用协议),所有 npm 包的信息(版本,是否是开发环境依赖)</p>\n<h1 id=\"怎么创建-packagejson-文件\"><a class=\"anchor\" href=\"#怎么创建-packagejson-文件\">#</a> 怎么创建 package.json 文件</h1>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># npm</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">npm</span> init</pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\"># pnpm</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token function\">pnpm</span> init</pre></td></tr></table></figure><h1 id=\"属性介绍\"><a class=\"anchor\" href=\"#属性介绍\">#</a> 属性介绍</h1>\n<h2 id=\"name\"><a class=\"anchor\" href=\"#name\">#</a> name</h2>\n<p>包的名字, 不能以 <code>.</code> , <code>_</code> , <code>大写字母</code> 开头</p>\n<ul>\n<li>\n<p>npm 域级包</p>\n<ul>\n<li>\n<p>介绍及其作用<br />\n在 npm 的包管理系统中,有一种 <code>scoped packages</code> 机制,用于将一些 npm 包以 <code>@scope/package</code> 的命名形式集中在一个命名空间下面,实现域级的包管理。域级包不仅不用担心会和别人的包名重复,同时也能对功能类似的包进行统一的划分和管理;比如我们用 vue 脚手架搭建的项目,里面就有 <code>@vue/cli-plugin-babel</code> 、 <code>@vue/cli-plugin-eslint</code> 等等域级包。相同域级范围内的包会被安装在相同的文件路径下,比如 <code>node_modules/@username/</code> ,可以包含任意数量的作用域包;安装域级包也需要指明其作用域范围:</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">npm</span> <span class=\"token function\">install</span> @username/package</pre></td></tr></table></figure></li>\n<li>\n<p>我们在初始化项目时可以使用命令行来添加 <code>scope</code> :</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token function\">npm</span> init <span class=\"token parameter variable\">--scope</span><span class=\"token operator\">=</span>username</pre></td></tr></table></figure></li>\n</ul>\n</li>\n</ul>\n<h2 id=\"version\"><a class=\"anchor\" href=\"#version\">#</a> version</h2>\n<p>包的版本号,npm 包的版本号也是有规范要求的,通用的就是遵循 <code>semver</code> 语义化版本规范,版本格式为: <code>major.minor.patch</code> ,每个字母代表的含义如下:</p>\n<ul>\n<li>\n<p>主版本号 (major):当你做了不兼容的 API 修改</p>\n</li>\n<li>\n<p>次版本号 (minor):当你做了向下兼容的功能性新增</p>\n</li>\n<li>\n<p>修订号 (patch):当你做了向下兼容的问题修正</p>\n</li>\n<li>\n<p>先行版本号:先行版本号是加到修订号的后面,作为版本号的延伸;当要发行大版本或核心功能时,但不能保证这个版本完全正常,就要先发一个先行版本。</p>\n<ul>\n<li>\n<p>格式<br />\n先行版本号的格式是在修订版本号后面加上一个连接号(-),再加上一连串以点(.)分割的标识符,标识符可以由英文、数字和连接号([0-9A-Za-z-])组成。例如:</p>\n<pre><code>1.0.0-alpha\n1.0.0-alpha.1\n1.0.0-0.3.7\n</code></pre>\n</li>\n<li>\n<p>常见先行版本号</p>\n<ul>\n<li>alpha:不稳定版本,一般而言,该版本的 Bug 较多,需要继续修改,是测试版本</li>\n<li>beta:基本稳定,相对于 Alpha 版已经有了很大的进步,消除了严重错误</li>\n<li>rc:和正式版基本相同,基本上不存在导致错误的 Bug</li>\n<li>release:最终版本</li>\n</ul>\n<div class=\"note info\">\n<p>当主版本号升级后,次版本号和修订号需要重置为 0,次版本号进行升级后,修订版本需要重置为 0。</p>\n</div>\n</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"description-keywords\"><a class=\"anchor\" href=\"#description-keywords\">#</a> description, keywords</h2>\n<ul>\n<li>description<br />\n <code>String</code> 类型,描述项目的信息, 可以显示在 <code>npm search</code> 命令的返回结果中</li>\n<li>keywords<br />\nArray <code>类型, 描述项目的信息, 可以显示在</code> npm search` 命令的返回结果中</li>\n</ul>\n<h2 id=\"homepage\"><a class=\"anchor\" href=\"#homepage\">#</a> homepage</h2>\n<p>用来指定项目的主页 or 部署网站的根目录。</p>\n<ul>\n<li>\n<p>开发环境的作用</p>\n<ul>\n<li>\n<p>避免路径问题</p>\n<p>一些前端框架和构建工具在路由和资源加载时依赖于 <code>homepage</code> 属性。如果你不在开发环境中设置 <code>homepage</code> ,可能会在构建应用时遇到问题,尤其是当你使用前端路由(如 <code>React Router</code> )时。</p>\n</li>\n<li>\n<p>测试相对路径:</p>\n<p>开发环境中的开发服务器通常使用相对路径来加载资源,而不需要指定完整的 URL。设置 <code>homepage</code> 属性可以帮助你测试应用在不同路径上的行为,以确保它在生产环境中正常工作。</p>\n</li>\n</ul>\n</li>\n<li>\n<p>生产环境的作用<br />\n指定应用程序的根 URL,确保所有资源(例如 CSS、JavaScript 文件等)的加载路径正确。这是非常关键的,因为在生产环境中,你的应用可能托管在不同的域名、子目录或路径上,而 <code>homepage</code> 可以确保资源正确加载。</p>\n</li>\n</ul>\n<h2 id=\"author-contributors-maintainers\"><a class=\"anchor\" href=\"#author-contributors-maintainers\">#</a> author, contributors, maintainers</h2>\n<ul>\n<li>author<br />\n 作者, <code>string | {name: string, url?: sting, email?: string}</code> 类型</li>\n<li>contributors<br />\n 贡献者列表, <code>Array<string | {name: string, url?: sting, email?: string}></code> 类型</li>\n<li>maintainers<br />\n 维护者列表, <code>Array<string | {name: string, url?: sting, email?: string}></code> 类型</li>\n</ul>\n<h2 id=\"bugs\"><a class=\"anchor\" href=\"#bugs\">#</a> bugs</h2>\n<p>提供地址来让用户反馈存在的问题, <code>{url: string, email: string}</code> 类型</p>\n<h2 id=\"license-license\"><a class=\"anchor\" href=\"#license-license\">#</a> license, license</h2>\n<ul>\n<li>license<br />\n 开源协议名称, <code>string</code> 类型</li>\n<li>licenses<br />\n 多个包的开源协议名称, <code>Array<{type: string, url: string}></code> 类型<br />\n<img data-src=\"https://i0.imgs.ovh/2023/10/28/FDPvK.png\" alt=\"license.png\" /></li>\n</ul>\n<h2 id=\"main-module-browser\"><a class=\"anchor\" href=\"#main-module-browser\">#</a> main, module, browser</h2>\n<ul>\n<li>main<br />\n 指定加载时的入口文件, <code>cmd</code> 模块规范导入的时候就会加载这个文件,默认为根目录下的 <code>index.js</code> 文件, <code>browser</code> 和 <code>node</code> 环境下均可使用, <code>string</code> 类型</li>\n<li>module<br />\n 指定 <code>esm</code> 模块规范时的入口文件, <code>browser</code> 和 <code>node</code> 环境下均可使用, <code>string</code> 类型</li>\n<li>browser<br />\n 指定 <code>browser</code> 环境下的入口文件</li>\n</ul>\n<h2 id=\"dependencies-devdependencies\"><a class=\"anchor\" href=\"#dependencies-devdependencies\">#</a> dependencies, devDependencies</h2>\n<ul>\n<li>\n<p>dependencies<br />\n 项目 <code>运行</code> 所需的依赖, <code>开发</code> 和 <code>生产</code> 环境都需要的依赖,命令如下:</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 不缩写</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">npm</span> <span class=\"token function\">install</span> xxx <span class=\"token parameter variable\">--save</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 缩写</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token function\">npm</span> <span class=\"token function\">install</span> xxx <span class=\"token parameter variable\">-S</span></pre></td></tr></table></figure></li>\n<li>\n<p>devDependencies<br />\n 项目 <code>开发</code> 所需的依赖,只会在 <code>开发</code> 环境被安装,命令如下:</p>\n<figure class=\"highlight bash\"><figcaption data-lang=\"bash\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\"># 不缩写</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token function\">npm</span> <span class=\"token function\">install</span> xxx --save-dev</pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token comment\"># 缩写</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token function\">npm</span> <span class=\"token function\">install</span> xxx <span class=\"token parameter variable\">-D</span></pre></td></tr></table></figure><ul>\n<li>\n<p>版本号规则:</p>\n<ul>\n<li>没有任何符号:完全百分百匹配,必须使用当前版本号</li>\n<li>对比符号类的:>(大于) >=(大于等于) <(小于) <=(小于等于)</li>\n<li>波浪符号<sub>:固定主版本号和次版本号,修订号可以随意更改,例如</sub> 2.0.0,可以使 用 2.0.0、2.0.2 、2.0.9 的版本。</li>\n<li>插入符号<sup>:固定主版本号,次版本号和修订号可以随意更改,例如</sup> 2.0.0,可以使 用 2.0.1、2.2.2 、2.9.9 的版本。</li>\n<li>任意版本 *:对版本没有限制,一般不用</li>\n<li>或符号:|| 可以用来设置多个版本号限制规则,例如 >= 3.0.0 || <= 1.0.0</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"peerdependencies-bundleddependencies-optionaldependencies\"><a class=\"anchor\" href=\"#peerdependencies-bundleddependencies-optionaldependencies\">#</a> peerDependencies, bundledDependencies, optionalDependencies</h2>\n<ul>\n<li>\n<p>peerDependencies<br />\n 用来告诉别人当使用这个依赖的时候,需要使用那些特定版本的依赖,比如 <code>依赖 A</code> 的 <code>package.json</code> 中声明了 <code>peerDependencies</code> , <code>xxx6.0</code> 吗,那么如果安装了 <code>依赖 A</code> 就也应该安装 <code>xxx6.0</code></p>\n<div class=\"note info\">\n<p>但是请注意, <code>peerDependencies</code> 下的依赖并不会被强行安装,它只是告诉你,应该安装 对应版本的这些依赖,因为该依赖依赖于这些依赖,如果不安装,可能会出现问题</p>\n</div>\n</li>\n<li>\n<p>bundledDependencies</p>\n<p>依赖默认时不会被打包的,但是 <code>bundledDependencies</code> 下的依赖也会被一起打包</p>\n</li>\n<li>\n<p>optionalDependencies</p>\n<p>指定一些可选的依赖,这些依赖也会被 <code>npm install</code> 安装,但是安装失败了,不会报错,不会导致整个 <code>npm install</code> 失败</p>\n</li>\n</ul>\n<h2 id=\"files\"><a class=\"anchor\" href=\"#files\">#</a> files</h2>\n<p>用来指定 npm 发包时应该包括哪些目录和文件, <code>string | Array<string></code> 类型</p>\n<h2 id=\"bin\"><a class=\"anchor\" href=\"#bin\">#</a> bin</h2>\n<p>用来指定命令和对应的可执行文件,例如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"my-cli-tool\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1.0.0\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token property\">\"bin\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token property\">\"my-command\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"bin/my-command.js\"</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p><code>bin</code> 中的键(例如 <code>"my-command"</code> )是用户在命令行中执行的命令名称。 <code>bin</code> 中的值是指向模块中实际可执行文件的相对路径。当全局安装 <code>my-cli-tool</code> 的时候,系统会创建一个符号链接,将 <code>bin</code> 中指定的命令名称与相应的可执行文件关联,然后这个符号连接会被添加到系统的 <code>PATH</code> 变量中。当我们执行 <code>my-command</code> 命令的时候,系统就会通过 <code>PATH</code> 的符号连接找到对应的 <code>bin/my-command</code> 文件并执行其中的代码。如果我们的包以 <code>依赖</code> 的方式被安装时,如果有 <code>bin</code> ,就会在 <code>node_modules/.bin/</code> 生成对应的文件,然后建立符号链接,所有 <code>node_modules/.bin/</code> 目录下的命令都可以使用 <code>npm run [命令]</code> 的格式下运行。</p>\n<h2 id=\"directories\"><a class=\"anchor\" href=\"#directories\">#</a> directories</h2>\n<p>展示项目的目录结构信息,用来告诉用户每个目录在什么位置, 比如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"my-module\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1.0.0\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token property\">\"directories\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token property\">\"bin\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"bin\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token property\">\"lib\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"src\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token property\">\"doc\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"docs\"</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>用来告诉用户 or 其他开发者 可执行文件请放到 <code>bin</code> 目录,库的核心代码请放到 <code>lib</code> 目录,文档代码请放到 <code>doc</code> 目录。</p>\n<h2 id=\"repository\"><a class=\"anchor\" href=\"#repository\">#</a> repository</h2>\n<p>用来告诉想要加入我们,对我们的代码做贡献的人,我们的代码仓库在哪里, <code>{type: string, url: string, directory: string}</code> 类型。比如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token property\">\"repository\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"git\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://github.com/DomeSy\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token property\">\"directory\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"描述话语\"</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><h2 id=\"script\"><a class=\"anchor\" href=\"#script\">#</a> script</h2>\n<p>指定对应命令的脚本(缩写), 比如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token property\">\"scripts\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"start\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"cross-env UMI_ENV=dev umi dev\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>当执行 <code>npm run script</code> 的时候就相当于执行了 <code>cross-env UMI_ENV=dev umi dev</code></p>\n<h2 id=\"config\"><a class=\"anchor\" href=\"#config\">#</a> config</h2>\n<p>用来添加命令行的环境变量, 比如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"domesy\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"config\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token property\">\"port\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"8088\"</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token property\">\"script\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token property\">\"start\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"node server.js\"</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>当我们在 node 环境中打印 <code>process.npm_package_config_port</code> 的时候就会打印出 8080</p>\n<h2 id=\"engines\"><a class=\"anchor\" href=\"#engines\">#</a> engines</h2>\n<p>用来指定本库的运行条件, 比如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"engines\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"node\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\">=0.10.3 <0.12\"</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>这里就限制了,如果想要运行本库,node 的版本必须大于等于 0.10.3 小于 0.12</p>\n<h2 id=\"os\"><a class=\"anchor\" href=\"#os\">#</a> os</h2>\n<p>用来指定可以在哪些操作系统上运行,比如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"os\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"linux\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"win64\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>就说明可以在 <code>linux</code> 和 <code>64位的windows</code> 操作系统上运行</p>\n<h2 id=\"cpu\"><a class=\"anchor\" href=\"#cpu\">#</a> cpu</h2>\n<p>用来指定可以在哪些架构下的 <code>cpu</code> 上运行, 比如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"cpu\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"x64\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"ia32\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><h2 id=\"private\"><a class=\"anchor\" href=\"#private\">#</a> private</h2>\n<p>用来指定这是否是一个私人的库,如果是,那么就不能在 npm 上面发布公开, <code>boolean</code> 类型</p>\n<h2 id=\"publishconfig\"><a class=\"anchor\" href=\"#publishconfig\">#</a> publishConfig</h2>\n<p>用来指定发包时候的一些配置,比如发到哪个包管理服务器上面,是发布哪个版本,访问级别(哪些用户可以访问)比如:</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"publishConfig\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"tag\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1.0.0\"</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 发布 1.0.0 版本</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token property\">\"registry\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://www.npmjs.com/package/domesy-cli\"</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 发布到这个包管理服务器上面</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token property\">\"access\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"public\"</span> <span class=\"token comment\">// 所有用户都可以访问</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><h2 id=\"preferglobal\"><a class=\"anchor\" href=\"#preferglobal\">#</a> preferGlobal</h2>\n<p>用来指定当用户不全局下载该库的时候是否发出警告, <code>boolean</code> 类型</p>\n<h2 id=\"browserslist\"><a class=\"anchor\" href=\"#browserslist\">#</a> browserslist</h2>\n<p>指定该库支持的浏览器类型, 比如</p>\n<figure class=\"highlight json\"><figcaption data-lang=\"JSON\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token property\">\"browserslist\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token property\">\"production\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\">0.2%\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"not dead\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"not op_mini all\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token property\">\"development\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"last 1 chrome version\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"last 1 firefox version\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"last 1 safari version\"</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure>",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"package.json文件"
]
},
{
"id": "https://zimu-66ccff.github.io/esbuildPlugin/",
"url": "https://zimu-66ccff.github.io/esbuildPlugin/",
"title": "怎么写一个esbuild插件",
"date_published": "2023-07-27T08:07:33.000Z",
"content_html": "<h1 id=\"esbuild-api\"><a class=\"anchor\" href=\"#esbuild-api\">#</a> esbuild API</h1>\n<h3 id=\"项目打包-build-api\"><a class=\"anchor\" href=\"#项目打包-build-api\">#</a> 项目打包 build API</h3>\n<ul>\n<li>\n<p>普通 api</p>\n<ol>\n<li>\n<p>build API</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> esbuild <span class=\"token keyword\">from</span> <span class=\"token string\">'esbuild'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">runBuild</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token comment\">// 异步方法,返回一个 Promise</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token keyword\">const</span> result <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> esbuild<span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token comment\">//---- 如下是一些常见的配置 ---</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token comment\">// 当前项目根目录</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> absWorkingDir<span class=\"token operator\">:</span> process<span class=\"token punctuation\">.</span><span class=\"token function\">cwd</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token comment\">// 入口文件列表,为一个数组</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> entryPoints<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'./src/index.jsx'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token comment\">// 打包产物目录</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> outdir<span class=\"token operator\">:</span> <span class=\"token string\">'dist'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token comment\">// 是否需要打包,一般设为 true</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> bundle<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> <span class=\"token comment\">// 模块格式,包括 `esm`、`commonjs` 和 `iife`</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> format<span class=\"token operator\">:</span> <span class=\"token string\">'esm'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> <span class=\"token comment\">// 需要排除打包的依赖列表</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> external<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> <span class=\"token comment\">// 是否开启自动拆包</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre> splitting<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> <span class=\"token comment\">// 是否生成 SourceMap 文件</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> sourcemap<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> <span class=\"token comment\">// 是否生成打包的元信息文件</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> metafile<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre> <span class=\"token comment\">// 是否进行代码压缩</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre> minify<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre> <span class=\"token comment\">// 是否将产物写入磁盘</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre> write<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre> <span class=\"token comment\">// Esbuild 内置了一系列的 loader,包括 base64、binary、 css、dataurl、file、js (x)、ts (x)、text、json</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre> <span class=\"token comment\">// 针对一些特殊的文件,调用不同的 loader 进行加载</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre> loader<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre> <span class=\"token string-property property\">'.png'</span><span class=\"token operator\">:</span> <span class=\"token string\">'base64'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"36\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"37\"></td><td><pre></pre></td></tr><tr><td data-num=\"38\"></td><td><pre><span class=\"token function\">runBuild</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure><p><code>result</code> 为 esbuild 打包的原信息<br />\n<a href=\"https://imgse.com/i/pP938ud\"><img data-src=\"https://s1.ax1x.com/2023/07/31/pP938ud.md.png\" alt=\"esbuild打包原信息\" /></a></p>\n</li>\n</ol>\n</li>\n<li>\n<p>高级 api(依赖于构建上下文)</p>\n<ol>\n<li>\n<p>watch API<br />\n 开启 <code>watch mode</code> ,一旦有文件发生改变,直接自动重新打包</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">let</span> ctx <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> esbuild<span class=\"token punctuation\">.</span><span class=\"token function\">context</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> entryPoints<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'app.ts'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> bundle<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> outdir<span class=\"token operator\">:</span> <span class=\"token string\">'dist'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token keyword\">await</span> ctx<span class=\"token punctuation\">.</span><span class=\"token function\">watch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n<li>\n<p>serve API<br />\n 开启 <code>serve mode</code> ,启动本地开发服务器 ,不是将打包后的代码写进磁盘,而是通过请求来获取,当每次请求到来时,都会 <code>rebuild</code> ,返回最新的产物</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// build.js</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> build<span class=\"token punctuation\">,</span> buildSync<span class=\"token punctuation\">,</span> serve <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'esbuild'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token keyword\">function</span> <span class=\"token function\">runBuild</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token function\">serve</span><span class=\"token punctuation\">(</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> port<span class=\"token operator\">:</span> <span class=\"token number\">8000</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token comment\">// 静态资源目录</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> servedir<span class=\"token operator\">:</span> <span class=\"token string\">'./dist'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> absWorkingDir<span class=\"token operator\">:</span> process<span class=\"token punctuation\">.</span><span class=\"token function\">cwd</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> entryPoints<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'./src/index.jsx'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> bundle<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> format<span class=\"token operator\">:</span> <span class=\"token string\">'esm'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> splitting<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> sourcemap<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> ignoreAnnotations<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> metafile<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>server<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'HTTP Server starts at port'</span><span class=\"token punctuation\">,</span> server<span class=\"token punctuation\">.</span>port<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre></pre></td></tr><tr><td data-num=\"26\"></td><td><pre><span class=\"token function\">runBuild</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n</ol>\n</li>\n</ul>\n<h3 id=\"单文件转译-transform-api\"><a class=\"anchor\" href=\"#单文件转译-transform-api\">#</a> 单文件转译 transform API</h3>\n<ul>\n<li>transform Api</li>\n</ul>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// transform.js</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> transform<span class=\"token punctuation\">,</span> transformSync <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'esbuild'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">runTransform</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token comment\">// 第一个参数是代码字符串,第二个参数为编译配置</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">transform</span><span class=\"token punctuation\">(</span><span class=\"token string\">'const isNull = (str: string): boolean => str.length > 0;'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> sourcemap<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> loader<span class=\"token operator\">:</span> <span class=\"token string\">'tsx'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token function\">runTransform</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure><h1 id=\"esbuild-插件开发\"><a class=\"anchor\" href=\"#esbuild-插件开发\">#</a> esbuild 插件开发</h1>\n<h3 id=\"插件基本结构\"><a class=\"anchor\" href=\"#插件基本结构\">#</a> 插件基本结构</h3>\n<p><code>esbuild</code> 插件的结构为一个有 <code>name</code> , <code>setup</code> 属性的 obj。<br />\n <code>name</code> 属性为插件的名称<br />\n <code>setup</code> 属性为一个函数,有一个参数为 <code>build</code> 对象,这个 <code>build</code> 对象身上有我们需要的一些钩子函数</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">let</span> envPlugin <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> name<span class=\"token operator\">:</span> <span class=\"token string\">'env'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token function\">setup</span><span class=\"token punctuation\">(</span>build<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> build<span class=\"token punctuation\">.</span><span class=\"token function\">onResolve</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> filter<span class=\"token operator\">:</span> <span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">^env$</span><span class=\"token regex-delimiter\">/</span></span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> path<span class=\"token operator\">:</span> args<span class=\"token punctuation\">.</span>path<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> namespace<span class=\"token operator\">:</span> <span class=\"token string\">'env-ns'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> build<span class=\"token punctuation\">.</span><span class=\"token function\">onLoad</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> filter<span class=\"token operator\">:</span> <span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">.*</span><span class=\"token regex-delimiter\">/</span></span><span class=\"token punctuation\">,</span> namespace<span class=\"token operator\">:</span> <span class=\"token string\">'env-ns'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> contents<span class=\"token operator\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> loader<span class=\"token operator\">:</span> <span class=\"token string\">'json'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token keyword\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'esbuild'</span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> entryPoints<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'src/index.jsx'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> bundle<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre> outfile<span class=\"token operator\">:</span> <span class=\"token string\">'out.js'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> <span class=\"token comment\">// 应用插件</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> plugins<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>envPlugin<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> <span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> process<span class=\"token punctuation\">.</span><span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure><h3 id=\"插件钩子函数\"><a class=\"anchor\" href=\"#插件钩子函数\">#</a> 插件钩子函数</h3>\n<ol>\n<li>\n<p><code>onStart</code> <br />\n 执行时机是每次 build 的时候,包括 <code>watch mode</code> 和 <code>serve mode</code> 模式下的重新构建</p>\n</li>\n<li>\n<p><code>onResolve</code> <br />\n 用来控制路径解析,具有两个参数 <code>options</code> , <code>callback</code></p>\n<ul>\n<li>\n<p><code>options</code> 的类型</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">interface</span> <span class=\"token class-name\">Options</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> filter<span class=\"token operator\">:</span> RegExp<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> namespace<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p><code>filter</code> 为必传参数,为一个正则表达式,用来过滤出需要处理的文件<br />\n <code>namespace</code> 为选填参数, 为我们过滤出来的需要处理的文件进行一个标记,在 <code>callback</code> 里面返回,从而在 <code>onLoad</code> 钩子函数中找到并处理</p>\n</li>\n<li>\n<p><code>callback</code> 常见参数及其返回值</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>build<span class=\"token punctuation\">.</span><span class=\"token function\">onResolve</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> filter<span class=\"token operator\">:</span> <span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">^env$</span><span class=\"token regex-delimiter\">/</span></span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span>args<span class=\"token operator\">:</span> onResolveArgs<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> onResolveResult <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token comment\">// 模块路径</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>path<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token comment\">// 父模块路径</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>importer<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token comment\">//namespace 标识</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>namespace<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token comment\">// 基准路径</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>resolveDir<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token comment\">// 导入方式,如 import、require</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>kind<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token comment\">// 额外绑定的插件数据</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>pluginData<span class=\"token punctuation\">)</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> <span class=\"token comment\">// 错误信息</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> errors<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> <span class=\"token comment\">// 是否需要 external</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> external<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre> <span class=\"token comment\">//namespace 标识</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> namespace<span class=\"token operator\">:</span> <span class=\"token string\">'env-ns'</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> <span class=\"token comment\">// 模块路径</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> path<span class=\"token operator\">:</span> args<span class=\"token punctuation\">.</span>path<span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> <span class=\"token comment\">// 额外绑定的插件数据</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre> pluginData<span class=\"token operator\">:</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre> <span class=\"token comment\">// 插件名称</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre> pluginName<span class=\"token operator\">:</span> <span class=\"token string\">'xxx'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre> <span class=\"token comment\">// 设置为 false,如果模块没有被用到,模块代码将会在产物 中 会删除。否则不会这么做</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre> sideEffects<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre> <span class=\"token comment\">// 添加一些路径后缀,如 `?xxx`</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre> suffix<span class=\"token operator\">:</span> <span class=\"token string\">'?xxx'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre> <span class=\"token comment\">// 警告信息</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre> warnings<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre> <span class=\"token comment\">// 仅仅在 Esbuild 开启 watch 模式下生效</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre> <span class=\"token comment\">// 告诉 Esbuild 需要额外监听哪些文件 / 目录的变化</span></pre></td></tr><tr><td data-num=\"36\"></td><td><pre> watchDirs<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"37\"></td><td><pre> watchFiles<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"38\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"39\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr></table></figure></li>\n</ul>\n</li>\n<li>\n<p><code>onLoad</code> <br />\n 控制模块内容加载的过程, 具有两个参数 <code>options</code> , <code>callback</code></p>\n<ul>\n<li>\n<p><code>options</code> 的类型</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">interface</span> <span class=\"token class-name\">Options</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> filter<span class=\"token operator\">:</span> RegExp<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> namespace<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p><code>filter</code> 为必传参数,为一个正则表达式,用来过滤出需要处理的文件<br />\n <code>namespace</code> 为选填参数, 通过 <code>namespace</code> 来将需要处理的模块的过滤出来</p>\n</li>\n<li>\n<p><code>callback</code> 常见参数及其返回值</p>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre>build<span class=\"token punctuation\">.</span><span class=\"token function\">onLoad</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> filter<span class=\"token operator\">:</span> <span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">.*</span><span class=\"token regex-delimiter\">/</span></span><span class=\"token punctuation\">,</span> namespace<span class=\"token operator\">:</span> <span class=\"token string\">'env-ns'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span>args<span class=\"token operator\">:</span> OnLoadArgs<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> OnLoadResult <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> <span class=\"token comment\">// 模块路径</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>path<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token comment\">//namespace 标识</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>namespace<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token comment\">// 后缀信息</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>suffix<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token comment\">// 额外的插件数据</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>args<span class=\"token punctuation\">.</span>pluginData<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token comment\">// 模块具体内容</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> contents<span class=\"token operator\">:</span> <span class=\"token string\">'省略内容'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> <span class=\"token comment\">// 错误信息</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> errors<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> <span class=\"token comment\">// 指定 loader,如 `js`、`ts`、`jsx`、`tsx`、`json` 等 等</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> loader<span class=\"token operator\">:</span> <span class=\"token string\">'json'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> <span class=\"token comment\">// 额外的插件数据</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> pluginData<span class=\"token operator\">:</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre> <span class=\"token comment\">// 插件名称</span></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> pluginName<span class=\"token operator\">:</span> <span class=\"token string\">'xxx'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> <span class=\"token comment\">// 基准路径</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> resolveDir<span class=\"token operator\">:</span> <span class=\"token string\">'./dir'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> <span class=\"token comment\">// 警告信息</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre> warnings<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre> <span class=\"token comment\">// 同上</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre> watchDirs<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre> watchFiles<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n</ul>\n</li>\n<li>\n<p><code>onEnd</code> <br />\n 在打包结束时做一些事情,比如拿到打包的原信息 <code>matafile</code> 来做一些事情,但是想要拿到 <code>metafile</code> ,必须将 <code>metafile</code> 属性设置为 <code>true</code></p>\n</li>\n</ol>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">let</span> examplePlugin <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre> name<span class=\"token operator\">:</span> <span class=\"token string\">'example'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token function\">setup</span><span class=\"token punctuation\">(</span>build<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> build<span class=\"token punctuation\">.</span><span class=\"token function\">onStart</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'build started'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> build<span class=\"token punctuation\">.</span><span class=\"token function\">onEnd</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>buildResult<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>buildResult<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token comment\">// 构建元信息</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token comment\">// 获取元信息后做一些自定义的事情,比如生成 HTML</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>buildResult<span class=\"token punctuation\">.</span>metafile<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure><h1 id=\"esbuild-插件示例\"><a class=\"anchor\" href=\"#esbuild-插件示例\">#</a> esbuild 插件示例</h1>\n<h3 id=\"html-pluginjs\"><a class=\"anchor\" href=\"#html-pluginjs\">#</a> html-plugin.js</h3>\n<figure class=\"highlight typescript\"><figcaption data-lang=\"typescript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">const</span> fs <span class=\"token operator\">=</span> <span class=\"token keyword\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fs/promises'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre><span class=\"token keyword\">const</span> path <span class=\"token operator\">=</span> <span class=\"token keyword\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createScript<span class=\"token punctuation\">,</span> createLink<span class=\"token punctuation\">,</span> generateHTML <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./util'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre></pre></td></tr><tr><td data-num=\"5\"></td><td><pre>module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> name<span class=\"token operator\">:</span> <span class=\"token string\">'esbuild:html'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token function\">setup</span><span class=\"token punctuation\">(</span>build<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> build<span class=\"token punctuation\">.</span><span class=\"token function\">onEnd</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span>buildResult<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>buildResult<span class=\"token punctuation\">.</span>errors<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> metafile <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> buildResult<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"14\"></td><td><pre> <span class=\"token comment\">// 1. 拿到 metafile 后获取所有的 js 和 css 产物路径</span></pre></td></tr><tr><td data-num=\"15\"></td><td><pre> <span class=\"token keyword\">const</span> scripts <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"16\"></td><td><pre> <span class=\"token keyword\">const</span> links <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"17\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>metafile<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"18\"></td><td><pre> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> outputs <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> metafile<span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"19\"></td><td><pre> <span class=\"token keyword\">const</span> assets <span class=\"token operator\">=</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">keys</span><span class=\"token punctuation\">(</span>outputs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"20\"></td><td><pre></pre></td></tr><tr><td data-num=\"21\"></td><td><pre> assets<span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>asset<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"22\"></td><td><pre> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>asset<span class=\"token punctuation\">.</span><span class=\"token function\">endsWith</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.js'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"23\"></td><td><pre> scripts<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token function\">createScript</span><span class=\"token punctuation\">(</span>asset<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"24\"></td><td><pre> <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>asset<span class=\"token punctuation\">.</span><span class=\"token function\">endsWith</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.css'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"25\"></td><td><pre> links<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token function\">createLink</span><span class=\"token punctuation\">(</span>asset<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"26\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"27\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"28\"></td><td><pre> <span class=\"token punctuation\">}</span></pre></td></tr><tr><td data-num=\"29\"></td><td><pre> <span class=\"token comment\">// 2. 拼接 HTML 内容</span></pre></td></tr><tr><td data-num=\"30\"></td><td><pre> <span class=\"token keyword\">const</span> templateContent <span class=\"token operator\">=</span> <span class=\"token function\">generateHTML</span><span class=\"token punctuation\">(</span>scripts<span class=\"token punctuation\">,</span> links<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"31\"></td><td><pre> <span class=\"token comment\">// 3. HTML 写入磁盘</span></pre></td></tr><tr><td data-num=\"32\"></td><td><pre> <span class=\"token keyword\">const</span> templatePath <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span>process<span class=\"token punctuation\">.</span><span class=\"token function\">cwd</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'index.html'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"33\"></td><td><pre> <span class=\"token keyword\">await</span> fs<span class=\"token punctuation\">.</span><span class=\"token function\">writeFile</span><span class=\"token punctuation\">(</span>templatePath<span class=\"token punctuation\">,</span> templateContent<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"34\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"35\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"36\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"37\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"38\"></td><td><pre></pre></td></tr><tr><td data-num=\"39\"></td><td><pre><span class=\"token comment\">// util.js</span></pre></td></tr><tr><td data-num=\"40\"></td><td><pre><span class=\"token comment\">// 一些工具函数的实现</span></pre></td></tr><tr><td data-num=\"41\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">createScript</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>src<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"><script type=\"module\" src=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>src<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\"></script></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"42\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">createLink</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>src<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"><link rel=\"stylesheet\" href=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>src<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\"></link></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"43\"></td><td><pre><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">generateHTML</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>scripts<span class=\"token punctuation\">,</span> links<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"></pre></td></tr><tr><td data-num=\"44\"></td><td><pre><!DOCTYPE html></pre></td></tr><tr><td data-num=\"45\"></td><td><pre><html lang=\"en\"></pre></td></tr><tr><td data-num=\"46\"></td><td><pre></pre></td></tr><tr><td data-num=\"47\"></td><td><pre><head></pre></td></tr><tr><td data-num=\"48\"></td><td><pre> <meta charset=\"UTF-8\" /></pre></td></tr><tr><td data-num=\"49\"></td><td><pre> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /></pre></td></tr><tr><td data-num=\"50\"></td><td><pre> <title>Esbuild App</title></pre></td></tr><tr><td data-num=\"51\"></td><td><pre> </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>links<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">'\\n'</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"></pre></td></tr><tr><td data-num=\"52\"></td><td><pre></head></pre></td></tr><tr><td data-num=\"53\"></td><td><pre></pre></td></tr><tr><td data-num=\"54\"></td><td><pre><body></pre></td></tr><tr><td data-num=\"55\"></td><td><pre> <div id=\"root\"></div></pre></td></tr><tr><td data-num=\"56\"></td><td><pre> </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>scripts<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">'\\n'</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"></pre></td></tr><tr><td data-num=\"57\"></td><td><pre></body></pre></td></tr><tr><td data-num=\"58\"></td><td><pre></pre></td></tr><tr><td data-num=\"59\"></td><td><pre></html></pre></td></tr><tr><td data-num=\"60\"></td><td><pre></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span></pre></td></tr><tr><td data-num=\"61\"></td><td><pre></pre></td></tr><tr><td data-num=\"62\"></td><td><pre>module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> createLink<span class=\"token punctuation\">,</span> createScript<span class=\"token punctuation\">,</span> generateHTML <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure>",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"深入浅出vite"
]
},
{
"id": "https://zimu-66ccff.github.io/vite%E7%9A%84%E4%B8%A4%E4%B8%AA%E5%BE%97%E5%8A%9B%E5%8A%A9%E6%89%8B-esbuild-rollup/",
"url": "https://zimu-66ccff.github.io/vite%E7%9A%84%E4%B8%A4%E4%B8%AA%E5%BE%97%E5%8A%9B%E5%8A%A9%E6%89%8B-esbuild-rollup/",
"title": "vite的两个得力助手-esbuild-rollup",
"date_published": "2023-07-26T09:47:06.000Z",
"content_html": "<h1 id=\"esbuild\"><a class=\"anchor\" href=\"#esbuild\">#</a> esbuild</h1>\n<h3 id=\"esubuild-为什么快vite-选择-esbuild-在开发环境打包第三方依赖的原因\"><a class=\"anchor\" href=\"#esubuild-为什么快vite-选择-esbuild-在开发环境打包第三方依赖的原因\">#</a> esubuild 为什么快 (vite 选择 esbuild 在开发环境打包第三方依赖的原因)</h3>\n<ul>\n<li>使用 Go 开发<br />\n Go 的代码会被直接编译成原生机器码,而不需要像 JS 一样先解析为字节码,然后再转换成字节码,大大的节省了程序运行的时间、</li>\n<li>多核并行<br />\n因为 Go 中多线程共享内存的优势,内部打包算法充分的利用了多核 CPU 的多核优势,使得所有步骤尽可能的并行</li>\n<li>从零造轮子<br />\n几乎没有使用第三方库,全部是自己编写的逻辑,保证了代码的极致性能</li>\n<li>高效的内存利用<br />\n Esbuild 中从头到尾尽可能地复用一份 AST 节点数据,而不用像 JS 打包工具中频繁地解析和传递 AST 数据(如 string -> TS -> JS -> string),造成内存的大量浪费。</li>\n</ul>\n<h3 id=\"esbuild-的不足vite-为什么在生产环境不选择-esbuild-而选择了-rollup-来进行打包\"><a class=\"anchor\" href=\"#esbuild-的不足vite-为什么在生产环境不选择-esbuild-而选择了-rollup-来进行打包\">#</a> esbuild 的不足(vite 为什么在生产环境不选择 esbuild 而选择了 rollup 来进行打包)</h3>\n<ul>\n<li>无法兼容低端浏览器<br />\n不支持把语法降级到 <code>es5</code> ,不支持 <code>const enum</code> 等高级语法</li>\n<li>无法灵活处理打包产物,无法自定义拆包<br />\n没有提供操作打包产物的接口,没有提供子定义拆包策略的 api</li>\n</ul>\n<h3 id=\"vite-用-esbuild-做了什么\"><a class=\"anchor\" href=\"#vite-用-esbuild-做了什么\">#</a> vite 用 esbuild 做了什么</h3>\n<ul>\n<li>bunder\n<ol>\n<li>在开发环境,为了顺利的实现 <code>no-bunder</code> ,在<strong>预构建</strong>使用 esuild 来将其他的模块化规范转换成了 <code>esm</code> (因为 <code>no-bundler</code> 本质上是利用了浏览器原生支持 esm,让浏览器来请求对应模块)</li>\n<li>使用 esbuild 来对第三方依赖进行打包(避免出现请求瀑布流,浏览器发起过多请求,导致首屏时间过长)</li>\n</ol>\n</li>\n<li>transformer<br />\n 进行单文件编译,作为 TS, JSX, TSX 的编译工具,并且在<strong>生产环境</strong>也是用的 esbuild 来进行编译。但是无法进行 ts 的类型检查,所以还是需要利用 <code>tsc</code> 来进行类型检查</li>\n<li>minifier<br />\n 对 css, js 文件进行压缩</li>\n</ul>\n<h1 id=\"rollup\"><a class=\"anchor\" href=\"#rollup\">#</a> rollup</h1>\n<h3 id=\"vite-用-rollup-做了什么\"><a class=\"anchor\" href=\"#vite-用-rollup-做了什么\">#</a> vite 用 rollup 做了什么</h3>\n<ol>\n<li>\n<p>生产环境利用 <code>rollup</code> 进行打包,并对其进行扩展和优化</p>\n<ul>\n<li>CSS 代码分割<br />\n如果某个异步模块中引入了一些 CSS 代码,Vite 就会自动将这些 CSS 抽取出来生成单独的文件,提高线上产物的缓存复用率。</li>\n<li>自动预加载<br />\n Vite 会自动为入口 chunk 的依赖自动生成预加载标签 <code><link rel="modulepreload"></code></li>\n<li>异步 Chunk 加载优化<br />\n在异步引入的 Chunk 中,通常会有一些公用的模块,如现有两个 异 步引入的 Chunk: A 和 B,而且两者有一个公共依赖 C,一般 情况 下,Rollup 打包之后,会先请求 A,然后浏览器在加载 A 的过程 中才决定请求和加载 C,但 Vite 进行优化之后,请求 A 的同时会 自动预加载 C,通过优化 Rollup 产物依赖加载方式节省 了不必要 的网络开销。</li>\n</ul>\n</li>\n<li>\n<p>兼容了 <code>rollup</code> 的插件机制<br />\n vite 插件可以直接传入 rollup 作为插件使用,但是 rollup 的插件不一定能直接传入 vite 作为 vite 插件使用</p>\n</li>\n</ol>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"深入浅出vite"
]
},
{
"id": "https://zimu-66ccff.github.io/engineeringProblems-viteLearning/",
"url": "https://zimu-66ccff.github.io/engineeringProblems-viteLearning/",
"title": "前端工程化痛点-vite的解决方案-深入浅出vite学习",
"date_published": "2023-07-26T07:04:39.000Z",
"content_html": "<h1 id=\"前端工程化的痛点及-vite-的解决方案\"><a class=\"anchor\" href=\"#前端工程化的痛点及-vite-的解决方案\">#</a> 前端工程化的痛点及 vite 的解决方案</h1>\n<h3 id=\"痛点一模块化规范太多需要一个支持和兼容\"><a class=\"anchor\" href=\"#痛点一模块化规范太多需要一个支持和兼容\">#</a> 痛点一:模块化规范太多,需要一个支持和兼容</h3>\n<ul>\n<li>vite 的解决方案\n<ul>\n<li>支持 ESM 模块化方案(支持异步,浏览器原生支持),由于浏览器原生支持 ESM,所以可以基于 ESM 实现 <code>no-bunder</code></li>\n<li>兼容其他的模块化方案,通过在 <code>预构建</code> 过程中来使用 <code>esbuild</code> 来将其他模块化方案转换成 ESM</li>\n</ul>\n</li>\n<li>模块化方案面对的问题\n<ul>\n<li>模块的拆分</li>\n<li>模块的依赖关系导致的加载顺序(a 模块依赖 b 模块,那就需要先引入 b 模块再引入 a 模块)</li>\n<li>变量命名冲突</li>\n<li>浏览器是否兼容</li>\n</ul>\n</li>\n<li>模块化方案发展历史\n<ul>\n<li>第一阶段:通过 <code><script></code> 来做模块化,但是存在变量命名冲突,模块加载顺序的问题</li>\n<li>第二阶段:通过 <code>命名空间(window.moduleA, window,moduleB)</code> 来做模块化,解决了变量命名冲突,但是 没有解决模块加载顺序的问题</li>\n<li>第三阶段:通过 <code>IIFE(立即执行函数)</code> 来做模块化,解决了变量命名冲突,但是没有解决模块加载顺序的问题</li>\n<li>第四阶段:通过 <code>CommonJS</code> 规范来做模块化,解决了变量冲突,模块加载顺序的问题,但是存在一个加载是同 步的问题(这在浏览器是个大问题,当加载的模块过大时,会阻塞后续代码的执行,会造成界面白屏时间过长),并且 浏览器并不支持这个模块化方案</li>\n<li>第五阶段:通过 <code>AMD</code> 来做模块化,也就是异步模块定义方案,解决了上述的问题,但是写起来太麻烦,并且也 没有得到浏览器的支持</li>\n<li>最终阶段:通过 <code>ESM</code> 来做模块化,完美解决了上述问题所有问题(变量命名冲突,模块加载顺序),并且加载是 异步的,不会阻塞页面渲染,并且是浏览器原生支持</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"痛点二需要对-tstsx-等高级语法做一个转译对静态资源做处理使其能作为一个正常模块加载能够对语法做一个降级并注入一些高级语法以支持低级浏览器\"><a class=\"anchor\" href=\"#痛点二需要对-tstsx-等高级语法做一个转译对静态资源做处理使其能作为一个正常模块加载能够对语法做一个降级并注入一些高级语法以支持低级浏览器\">#</a> 痛点二:需要对 ts,tsx 等高级语法做一个转译,对静态资源做处理,使其能作为一个正常模块加载,能够对语法做一个降级,并注入一些高级语法,以支持低级浏览器</h3>\n<ul>\n<li>vite 的解决方案\n<ul>\n<li>通过 <code>esbuild</code> 来对 ts,tsx 等语法来进行一个转译(但是 ts 的语法检查还是需要 <code>tsc</code> )</li>\n<li>vite 内置对 JSON 模块的加载(底层使用 @rollup/pluginutils 的 dataToEsm 方法将 JSON 对象转换为一 个包含各种具名导出的 ES 模块)</li>\n<li>通过 <code>bable</code> 来将高级语法编译成低级语法(比如把箭头函数变成普通函数),通过 <code>corejs</code> 来注入一些高级 API (比如 promise),从而兼容低版本的浏览器</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"痛点三提高产物质量要能给对代码进行压缩和-treeshaking\"><a class=\"anchor\" href=\"#痛点三提高产物质量要能给对代码进行压缩和-treeshaking\">#</a> 痛点三:提高产物质量,要能给对代码进行压缩和 Treeshaking</h3>\n<ul>\n<li>vite 的解决方案\n<ul>\n<li>通过 <code>esbuild</code> 来对代码进行一个压缩</li>\n<li>treeShaking (待更新)</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"痛点四开发效率低下开发启动时间很长热更新很慢\"><a class=\"anchor\" href=\"#痛点四开发效率低下开发启动时间很长热更新很慢\">#</a> 痛点四:开发效率低下,开发启动时间很长,热更新很慢</h3>\n<ul>\n<li>vite 的解决方案\n<ul>\n<li>开发阶段直接 <code>no-bunder</code> 不打包直接启动,利用浏览器原生支持 ESM 的这一点,让浏览器来加载源代码对应的模块(在预构建过程中,利用 <code>esbuild</code> 来将其他模块化方案转换成 ESM,并打包第三方依赖,避免请求瀑布的出现,导致白屏时间过长)</li>\n<li>热更新(待更新)</li>\n</ul>\n</li>\n</ul>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"深入浅出vite"
]
},
{
"id": "https://zimu-66ccff.github.io/download/",
"url": "https://zimu-66ccff.github.io/download/",
"title": "前端实现文件下载的几种方式",
"date_published": "2023-07-18T02:13:12.000Z",
"content_html": "<h1 id=\"后端提供的下载文件的方式\"><a class=\"anchor\" href=\"#后端提供的下载文件的方式\">#</a> 后端提供的下载文件的方式</h1>\n<ol>\n<li>直接返回文件的网络地址(一般用在静态文件上,比如图片以及各种音视频资源等)</li>\n<li>返回文件流(一般用在动态文件上,比如根据前端选择,导出不同的统计结果 excel 等)</li>\n</ol>\n<h1 id=\"不同方式前端的处理方案\"><a class=\"anchor\" href=\"#不同方式前端的处理方案\">#</a> 不同方式,前端的处理方案</h1>\n<h4 id=\"第一种\"><a class=\"anchor\" href=\"#第一种\">#</a> 第一种</h4>\n<ul>\n<li>\n<p>通过 a 标签的 <code>download</code> 属性和 <code>click</code> 函数</p>\n<figure class=\"highlight html\"><figcaption data-lang=\"HTML\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"><</span>a</span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://www.baidu.top.pdf<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">download</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>附件.pdf<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>下载文件<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\"></</span>a</span><span class=\"token punctuation\">></span></span></pre></td></tr></table></figure></li>\n<li>\n<p><code>window.location.href</code> (推荐)</p>\n<pre><code class=\"language-javaScript\"><script>\nfunction Download() {\n window.location.href = 'www.baidu.pdf'\n}\n</script>\n</code></pre>\n</li>\n<li>\n<p><code>window.open</code> (推荐)</p>\n<pre><code class=\"language-javaScript\"><script>\n function Download() {\n window.open('www.baidu.pdf')\n }\n</script>\n</code></pre>\n</li>\n</ul>\n<h4 id=\"第二种-使用-blob-文件流下载\"><a class=\"anchor\" href=\"#第二种-使用-blob-文件流下载\">#</a> 第二种 使用 blob 文件流下载</h4>\n<pre><code class=\"language-javaScript\"> <script>\n function Download() {\n axios({\n url: "www.baidu.pdf",\n method: 'GET',\n responseType: 'blob', // 这里就是转化为blob文件流\n headers: {\n token: 'sss' // 可以携带token\n }\n }).then(res => {\n const href = URL.createObjectURL(res.data)\n const box = document.createElement('a')\n box.download = '附件.pdf'\n box.href = href\n box.click()\n })\n }\n </script>\n</code></pre>\n",
"tags": [
"笔记",
"项目",
"项目",
"文件下载"
]
},
{
"id": "https://zimu-66ccff.github.io/omi/",
"url": "https://zimu-66ccff.github.io/omi/",
"title": "腾讯犀牛鸟开源活动-OMI开源申请书",
"date_published": "2023-07-17T01:40:03.000Z",
"content_html": "<h1 id=\"omi-开源申请书\"><a class=\"anchor\" href=\"#omi-开源申请书\">#</a> OMI 开源申请书</h1>\n<h2 id=\"技术方案\"><a class=\"anchor\" href=\"#技术方案\">#</a> 技术方案</h2>\n<h4 id=\"omi-编程任务分解\"><a class=\"anchor\" href=\"#omi-编程任务分解\">#</a> OMI 编程任务分解</h4>\n<ol>\n<li>开发脚手架搭建</li>\n<li>组件开发</li>\n<li>组件设计器开发</li>\n</ol>\n<h4 id=\"任务-1开发-omi-组件库脚手架以自动生成-omi-组件模板辅助后续组件开发并集成-tdesign-common-提供的-tdesign-样式文件和工具函数保持组件的样式风格一致\"><a class=\"anchor\" href=\"#任务-1开发-omi-组件库脚手架以自动生成-omi-组件模板辅助后续组件开发并集成-tdesign-common-提供的-tdesign-样式文件和工具函数保持组件的样式风格一致\">#</a> 任务 1:开发 OMI 组件库脚手架,以自动生成 OMI 组件模板辅助后续组件开发,并集成 Tdesign-common 提供的 Tdesign 样式文件和工具函数,保持组件的样式风格一致</h4>\n<p>实战周期 2--3 周</p>\n<p>目标一:借鉴生态成熟的组件库脚手架 比如 valet-cli 抽离出 OMI 的 webComponents 的公共模板 以自动生成组件模板辅助开发<br />\n预计耗时: 一周</p>\n<p>目标二:在脚手架里集成 Tdesign-common 提供的样式文件和工具函数,以实现通过命令生成对应组件模板的时候可以根据配置选择是否自动导入类似组件的样式文件<br />\n预计耗时:一周</p>\n<p>本人优势:</p>\n<ol>\n<li>研究过 varlet-cli 源码,有脚手架开发经验</li>\n<li>开发过简易脚手架,来自动化实现相关配置和集成<br />\n链接:<span class=\"exturl\" data-url=\"aHR0cHM6Ly9naXRodWIuY29tL3ppTXUtNjZjY2ZmL3ppTXUtY2xp\">https://github.com/ziMu-66ccff/ziMu-cli</span></li>\n<li>可以熟练使用 inquirer,figlet,fs-extra,chalk, commander 等工具库</li>\n<li>有比较好的审美</li>\n</ol>\n<h4 id=\"任务-2利用上一步提供的脚手架来辅助开发基于-omi-和-tdesign-common-的相关组件\"><a class=\"anchor\" href=\"#任务-2利用上一步提供的脚手架来辅助开发基于-omi-和-tdesign-common-的相关组件\">#</a> 任务 2:利用上一步提供的脚手架来辅助开发基于 OMI 和 Tdesign-common 的相关组件</h4>\n<p>实战周期:2-3 周</p>\n<p>目标一:通过对组件的复杂程度排个序,来从简到难的逐步开发相关的组件,可以借鉴主流的生态完善的组件库 比如 ant-design<br />\n 预计耗时 2.5 周</p>\n<p>本人优势:</p>\n<ol>\n<li>在合合信息实习时 参与过部门的高度定制化的组件库的开发,有一定的组件库开发能力</li>\n<li>参加字节青训营时,和小伙伴们一起开发过 lucky-Componets 组件库<br />\n链接:<span class=\"exturl\" data-url=\"aHR0cHM6Ly9naXRodWIuY29tL0xpdVNlbjY4OC9sdWNreUNvbXBvbmVudHM=\">https://github.com/LiuSen688/luckyComponents</span></li>\n</ol>\n<h4 id=\"任务-3开发基于-omi-的组件设计器\"><a class=\"anchor\" href=\"#任务-3开发基于-omi-的组件设计器\">#</a> 任务 3:开发基于 OMI 的组件设计器</h4>\n<p>实战周期: 3 周以上</p>\n<p>目标:在相关导师的指导下,完善自己低代码开发的能力,努力再努力,热情再热情的完成这个组件设计器的开发</p>\n<h4 id=\"申请人项目经历\"><a class=\"anchor\" href=\"#申请人项目经历\">#</a> 申请人项目经历</h4>\n<p>github:<span class=\"exturl\" data-url=\"aHR0cHM6Ly9naXRodWIuY29tL3ppTXUtNjZjY2Zm\">https://github.com/ziMu-66ccff</span></p>\n<ol>\n<li>ziMu-cli, 一款简单的开箱即用的搭建 vue,react 项目的脚手架<br />\n项目链接:<span class=\"exturl\" data-url=\"aHR0cHM6Ly9naXRodWIuY29tL3ppTXUtNjZjY2ZmL3ppTXUtY2xp\">https://github.com/ziMu-66ccff/ziMu-cli</span></li>\n<li>lucky-components, 一款合作完成的适配 vue3 的组件库<br />\n项目链接:<span class=\"exturl\" data-url=\"aHR0cHM6Ly9naXRodWIuY29tL0xpdVNlbjY4OC9sdWNreUNvbXBvbmVudHM=\">https://github.com/LiuSen688/luckyComponents</span></li>\n<li>mini-vue3 自己学习 vue3 源码后 写的一个简单的 vue3 框架<br />\n项目链接:<span class=\"exturl\" data-url=\"aHR0cHM6Ly9naXRodWIuY29tL3ppTXUtNjZjY2ZmL21pbmktdnVlMw==\">https://github.com/ziMu-66ccff/mini-vue3</span></li>\n<li>前端全栈开发能力 熟练使用 Vue.js, OMI, Nest.js, mongoDB 等</li>\n<li>对 vite,webpack 有一定了解</li>\n<li>目前大二,在合合信息实习</li>\n</ol>\n<p>姓名:李文豪</p>\n",
"tags": [
"开源",
"开源",
"omi"
]
},
{
"id": "https://zimu-66ccff.github.io/bigProject/",
"url": "https://zimu-66ccff.github.io/bigProject/",
"title": "瑞翼工坊暑期大项目宣讲会",
"date_published": "2023-07-07T07:53:00.000Z",
"content_html": "<h1 id=\"为什么我们需要做这样的一个平台\"><a class=\"anchor\" href=\"#为什么我们需要做这样的一个平台\">#</a> 为什么我们需要做这样的一个平台?</h1>\n<ol>\n<li>工坊的很多东西 散落在各个地方 刚进来的人无法知道工坊的财富 无法得到自己需要的东西 所以我们用这样的一个平台对其做一个整合,让工坊成员都能得到自己想要的东西</li>\n<li>开发部门的新人缺少一个项目开发的经验,我们以这样的一个平台,来让新人得到锻炼,并且提供一对一的指导</li>\n<li>有新的技术,奇妙的想法,无法付诸于实践, 所以我们提供这样的一个可扩展的平台,随时对其进行扩展。</li>\n<li>开发部门的新人们简历上缺乏一个优秀的,高技术的,真正的项目(有访问量的),缺乏项目部署的经验,业务思维,而我们提供这样的一个项目</li>\n</ol>\n<h1 id=\"开发完毕后我们将得到什么\"><a class=\"anchor\" href=\"#开发完毕后我们将得到什么\">#</a> 开发完毕后,我们将得到什么</h1>\n<ol>\n<li>一个真正的项目开发经验,部署经验(这是区别于网上的项目的)</li>\n<li>获得业务思维,提升业务能力 (业务能力也是面试时很看重的一点,而这种真正的项目,不是为了做而做的项目,有背景的项目可以很好的提升业务思维)</li>\n<li>获取一定的名誉,如果可以的话,项目将向全计信推广,我们也会将开发者的名字放到项目里</li>\n</ol>\n<h1 id=\"具体开发信息\"><a class=\"anchor\" href=\"#具体开发信息\">#</a> 具体开发信息</h1>\n<h3 id=\"模块拆分\"><a class=\"anchor\" href=\"#模块拆分\">#</a> 模块拆分</h3>\n<ul>\n<li>工坊(顶部导航栏)\n<ul>\n<li>瑞翼荣耀 (小卡片)</li>\n<li>场地助手 (小卡片)</li>\n</ul>\n</li>\n<li>技术学习(顶部导航栏)\n<ul>\n<li>方向介绍 (小卡片)\n<ul>\n<li>前端 (小卡片 or 左侧导航栏)</li>\n<li>服务端 (小卡片 or 左侧导航栏)</li>\n<li>vr (小卡片 or 左侧导航栏)</li>\n<li>算法部 (小卡片 or 左侧导航栏)</li>\n</ul>\n</li>\n<li>学习路线 (小卡片)\n<ul>\n<li>前端 (小卡片 or 左侧导航栏)</li>\n<li>服务端 (小卡片 or 左侧导航栏)</li>\n<li>vr (小卡片 or 左侧导航栏)</li>\n<li>算法部 (小卡片 or 左侧导航栏)</li>\n</ul>\n</li>\n<li>每日一问 (小卡片)\n<ul>\n<li>前端 (小卡片 or 左侧导航栏)</li>\n<li>服务端 (小卡片 or 左侧导航栏)</li>\n<li>vr (小卡片 or 左侧导航栏)</li>\n<li>算法部 (小卡片 or 左侧导航栏)</li>\n</ul>\n</li>\n<li>暑期实习,秋招公司信息 (小卡片)</li>\n<li>开发平台 (小卡片)\n<ul>\n<li>jekins (小卡片 or 左侧导航栏)</li>\n<li>coding (小卡片 or 左侧导航栏)</li>\n<li>tapd (小卡片 or 左侧导航栏)</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>活动(顶部导航栏)\n<ul>\n<li>训练营 (小卡片) ps:建议支持一键组队功能</li>\n<li>开源活动 (小卡片) ps:建议支持一键组队功能</li>\n<li>比赛 (小卡片) ps: 建议支持一键组队功能</li>\n</ul>\n</li>\n<li>练习(顶部导航栏)\n<ul>\n<li>工坊 oj 平台 (小卡片)</li>\n<li>leetcode (小卡片)</li>\n<li>前端刷题网站 (小卡片)</li>\n</ul>\n</li>\n<li>学校 (顶部导航栏)\n<ul>\n<li>学校平台 (小卡片)\n<ul>\n<li>湖大 vpn (小卡片)</li>\n<li>智慧服务中心 (小卡片)</li>\n<li>教务系统 (小卡片)</li>\n<li>实践系统 (小卡片)</li>\n<li>图书管理系统 (小卡片)</li>\n<li>体测系统 (小卡片)</li>\n<li>LMS 课程平台 (小卡片)</li>\n<li>宿管系统 (小卡片)</li>\n</ul>\n</li>\n<li>课程资料 (小卡片)\n<ul>\n<li>cpp (小卡片 or 左侧一级导航栏) ps: 只是一个例子\n<ul>\n<li>知识总结 (小卡片 or 左侧二级导航栏)</li>\n<li>推荐书籍 (小卡片 or 左侧二级导航栏)</li>\n<li>课后习题答案 (小卡片 or 左侧二级导航栏)</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>友链 (顶部导航栏)</li>\n<li>小工具 (顶部导航栏)</li>\n</ul>\n",
"tags": [
"学校",
"学校",
"瑞翼工坊"
]
},
{
"id": "https://zimu-66ccff.github.io/workflowConfig/",
"url": "https://zimu-66ccff.github.io/workflowConfig/",
"title": "前端工作流配置——代码不仅是给机器看的,也是给人看的(持续更新中)",
"date_published": "2023-06-19T11:41:24.000Z",
"content_html": "<h1 id=\"eslint\"><a class=\"anchor\" href=\"#eslint\">#</a> eslint</h1>\n<h3 id=\"为什么需要-eslint\"><a class=\"anchor\" href=\"#为什么需要-eslint\">#</a> 为什么需要 eslint</h3>\n<p>因为我们写的代码有时候可能质量并不高,所以我们需要这样的一个工具来 <code>规范我们的代码</code> ,保障我们的 <code>代码质量</code> (比如我们写了一个变量 但是这个变量我们没有使用 那么这个变量就是多余的 这时候我们的 eslint 可以直接报错 让我们知道这个多余的变量应该删除)</p>\n<h3 id=\"怎么在项目中集成-eslint\"><a class=\"anchor\" href=\"#怎么在项目中集成-eslint\">#</a> 怎么在项目中集成 eslint</h3>\n<ol>\n<li>下载 eslint<br />\n 使用你的包管理工具(pnpm,yarn,npm,npx)安装 eslint 具体命令 <code>pnpm install eslint</code></li>\n<li>初始化 eslint()<br />\n具体命令 <code>pnpm eslint --init</code> , 执行该命令后会让你 <code>回答相关问题</code> ,从而选择适合你的规则来约束你的代码,目的只有一个提高你的代码质量\n<ul>\n<li>how would you like to use eslint?(你想使用 eslint 来做什么)\n<ul>\n<li>to check syntax only(只检查语法)</li>\n<li>to check syntax and find problems(检查语法并找出错误)</li>\n<li>to check syntax, find problems, and enforce code style (检查语法,找出错误,规范代码)</li>\n</ul>\n</li>\n<li>what type of modules does your project use? (你想使用什么模块化规范)\n<ul>\n<li>javascript modules (import/export)</li>\n<li>commonjs (require/exports)</li>\n<li>none of these</li>\n</ul>\n</li>\n<li>which framework does your project use? (你想使用什么框架)\n<ul>\n<li>React</li>\n<li>Vue</li>\n<li>none of these</li>\n</ul>\n</li>\n<li>Does your project use Typescript No/Yes (是否要使用 ts)</li>\n<li>Where does your code run? (代码运行在什么环境,一般两个都选)\n<ul>\n<li>Browser</li>\n<li>Node</li>\n</ul>\n</li>\n<li>How would you like to define a style for your project? (你想怎么来定义 eslint 的规则, 推荐直接使用流行的规范)\n<ul>\n<li>use a popular style guide (使用流行的规范)</li>\n<li>answer questions about your style (通过询问问题 得到你想要的规范吧)</li>\n<li>inspect your javascript files (根据配置文件 生成规范)</li>\n</ul>\n</li>\n<li>Which style guide do you want to to follow? (你想使用哪个流行的规范)\n<ul>\n<li>Standard</li>\n<li>XO</li>\n</ul>\n</li>\n<li>What format do you want your config file to be in ? (配置文件的格式 建议直接选择 JavaScript)\n<ul>\n<li>javascript</li>\n<li>yaml</li>\n<li>json</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>vscode 安装 eslint 插件</li>\n</ol>\n<h3 id=\"eslintcjs-配置文件的相关配置项解析\"><a class=\"anchor\" href=\"#eslintcjs-配置文件的相关配置项解析\">#</a> .eslint.cjs 配置文件的相关配置项解析</h3>\n<ol>\n<li>\n<p>parser - 解析器<br />\n ESLint 底层默认使用 Espree 来进行 AST 解析,这个解析器目前已经基于 Acron 来实现,虽然说 Acron 目前能够解析绝大多数的 ECMAScript 规范的语法,但还是不支持 TypeScript ,因此需要引入其他的解析器完成 TS 的解析。</p>\n<p>社区提供了 @typescript-eslint/parser 这个解决方案,专门为了 TypeScript 的解析而诞生,将 TS 代码转换为 Espree 能够识别的格式 (即 Estree 格式),然后在 Eslint 下通过 Espree 进行格式检查, 以此兼容了 TypeScript 语法。</p>\n</li>\n<li>\n<p>parserOptions - 解析器选项<br />\n这个配置可以对上述的解析器进行能力定制,默认情况下 ESLint 支持 ES5 语法,你可以配置这个选项,具体内容如下:</p>\n<p>ecmaVersion: 这个配置和 Acron 的 ecmaVersion 是兼容的,可以配置 ES + 数字 (如 ES6) 或者 ES + 年份 (如 ES2015),也可以直接配置为 latest,启用最新的 ES 语法。<br />\nsourceType: 默认为 script,如果使用 ES Module 则应设置为 module<br />\necmaFeatures: 为一个对象,表示想使用的额外语言特性,如开启 jsx。</p>\n</li>\n<li>\n<p>rules - 具体代码规则<br />\n rules 配置即代表在 ESLint 中手动调整哪些代码规则,比如禁止在 if 语句中使用赋值语句这条规则可以像如下的方式配置:</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// .eslintrc.js</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token comment\">// 其它配置省略</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token literal-property property\">rules</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token comment\">//key 为规则名,value 配置内容</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token string-property property\">'no-cond-assign'</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'error'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'always'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure><p>在 rules 对象中,key 一般为规则名,value 为具体的配置内容,在上述的例子中我们设置为一个数组,数组第一项为规则的 ID,第二项为规则的配置。</p>\n<p>这里重点说一说规则的 ID,它的语法对所有规则都适用,你可以设置以下的值:</p>\n<p>off 或 0: 表示关闭规则。</p>\n<p>warn 或 1: 表示开启规则,不过违背规则后只抛出 warning,而不会导致程序退出。<br />\nerror 或 2: 表示开启规则,不过违背规则后抛出 error,程序会退出。<br />\n具体的规则配置可能会不一样,有的是一个字符串,有的可以配置一个对象,你可以参考 ESLint 官方文档。</p>\n<p>当然,你也能直接将 rules 对象的 value 配置成 ID,如: "no-cond-assign": "error"。</p>\n</li>\n<li>\n<p>plugins<br />\n 上面提到过 ESLint 的 parser 基于 Acorn 实现,不能直接解析 TypeScript,需要我们指定 parser 选项为 @typescript-eslint/parser 才能兼容 TS 的解析。同理,ESLint 本身也没有内置 TypeScript 的代码规则,这个时候 ESLint 的插件系统就派上用场了。我们需要通过添加 ESLint 插件来增加一些特定的规则,比如添加 @typescript-eslint/eslint-plugin 来拓展一些关于 TS 代码的规则,如下代码所示:</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// .eslintrc.js</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token comment\">// 添加 TS 规则,可省略 `eslint-plugin`</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token literal-property property\">plugins</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'@typescript-eslint'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure><p>值得注意的是,添加插件后只是拓展了 ESLint 本身的规则集,但 ESLint 默认并没有 开启这些规则的校验!如果要开启或者调整这些规则,你需要在 rules 中进行配置,如:</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// .eslintrc.js</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token comment\">// 开启一些 TS 规则</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token literal-property property\">rules</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token string-property property\">'@typescript-eslint/ban-ts-comment'</span><span class=\"token operator\">:</span> <span class=\"token string\">'error'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token string-property property\">'@typescript-eslint/no-explicit-any'</span><span class=\"token operator\">:</span> <span class=\"token string\">'warn'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n<li>\n<p>extends - 继承配置<br />\n extends 相当于继承另外一份 ESLint 配置,可以配置为一个字符串,也可以配置成一个 字符串数组。主要分如下 3 种情况:</p>\n<p>从 ESLint 本身继承;<br />\n从类似 eslint-config-xxx 的 npm 包继承;<br />\n从 ESLint 插件继承。</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// .eslintrc.js</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre><span class=\"token string-property property\">\"extends\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token comment\">// 第 1 种情况</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre><span class=\"token string\">\"eslint:recommended\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre><span class=\"token comment\">// 第 2 种情况,一般配置的时候可以省略 `eslint-config`</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token string\">\"standard\"</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre><span class=\"token comment\">// 第 3 种情况,可以省略包名中的 `eslint-plugin`</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre><span class=\"token comment\">// 格式一般为: `plugin:${pluginName}/${configName}`</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token string\">\"plugin:react/recommended\"</span></pre></td></tr><tr><td data-num=\"11\"></td><td><pre><span class=\"token string\">\"plugin:@typescript-eslint/recommended\"</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"12\"></td><td><pre><span class=\"token punctuation\">]</span></pre></td></tr><tr><td data-num=\"13\"></td><td><pre><span class=\"token punctuation\">}</span></pre></td></tr></table></figure><p>有了 extends 的配置,对于之前所说的 ESLint 插件中的繁多配置,我们就不需要手动 一一开启了,通过 extends 字段即可自动开启插件中的推荐规则:</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token keyword\">extends</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"plugin:@typescript-eslint/recommended\"</span><span class=\"token punctuation\">]</span></pre></td></tr></table></figure></li>\n<li>\n<p>env 和 globals<br />\n 这两个配置分别表示运行环境和全局变量,在指定的运行环境中会预设一些全局变量,比如:</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// .eslint.js</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>module<span class=\"token punctuation\">.</span>export <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token literal-property property\">env</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token literal-property property\">browser</span><span class=\"token operator\">:</span> <span class=\"token string\">'true'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token literal-property property\">node</span><span class=\"token operator\">:</span> <span class=\"token string\">'true'</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure><p>指定上述的 env 配置后便会启用浏览器和 Node.js 环境,这两个环境中的一些全局变量 (如 window、global 等) 会同时启用。</p>\n<p>有些全局变量是业务代码引入的第三方库所声明,这里就需要在 globals 配置中声明全局变 量了。每个全局变量的配置值有 3 种情况:</p>\n<p>"writable" 或者 true,表示变量可重写;<br />\n"readonly" 或者 false,表示变量不可重写;<br />\n"off",表示禁用该全局变量。</p>\n</li>\n</ol>\n<h1 id=\"prettier\"><a class=\"anchor\" href=\"#prettier\">#</a> prettier</h1>\n<h3 id=\"为啥需要-prettier\"><a class=\"anchor\" href=\"#为啥需要-prettier\">#</a> 为啥需要 prettier</h3>\n<p>因为我们写的代码有时候需要可以的控制格式 比如:换行 缩进之类的 当代码量多起来 这就显得非常麻烦 所以我们需要一个工具 来自动帮我们格式化代码(让代码格式变正确)</p>\n<h3 id=\"怎么在项目中集成-prettier\"><a class=\"anchor\" href=\"#怎么在项目中集成-prettier\">#</a> 怎么在项目中集成 prettier</h3>\n<ol>\n<li>\n<p>下载 prettier 命令: <code>pnpm install prettier</code></p>\n</li>\n<li>\n<p>和 eslint 适配</p>\n<ul>\n<li>下载 eslint-config-prettier (用于用 prettier 的规则来覆盖部分 eslint 的规则) eslint-plugin-prettier(用来让 prettier 来接管 eslint 修复代码的功能)</li>\n<li>在.eslintrc.cjs 文件里面的 <code>extend</code> 属性里面添加 <code>"prettier"</code> 来解决 eslint 和 prettier 的冲突,让 prerrier 适配 eslint</li>\n</ul>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// .eslintrc.cjs</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>module<span class=\"token punctuation\">.</span>export <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token keyword\">extends</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'prettier'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n<li>\n<p>添加.prettierrc 文件来配置 prettier 相关规则</p>\n<figure class=\"highlight javascript\"><figcaption data-lang=\"javascript\"></figcaption><table><tr><td data-num=\"1\"></td><td><pre><span class=\"token comment\">// .prettierrc.js</span></pre></td></tr><tr><td data-num=\"2\"></td><td><pre>module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></pre></td></tr><tr><td data-num=\"3\"></td><td><pre> <span class=\"token literal-property property\">printWidth</span><span class=\"token operator\">:</span> <span class=\"token number\">80</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 一行的字符数,如果超过会进行换行,默认为 80</span></pre></td></tr><tr><td data-num=\"4\"></td><td><pre> <span class=\"token literal-property property\">tabWidth</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 一个 tab 代表几个空格数,默认为 2 个</span></pre></td></tr><tr><td data-num=\"5\"></td><td><pre> <span class=\"token literal-property property\">useTabs</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 是否使用 tab 进行缩进,默认为 false,表示用空格进行缩减</span></pre></td></tr><tr><td data-num=\"6\"></td><td><pre> <span class=\"token literal-property property\">singleQuote</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 字符串是否使用单引号,默认为 false,使用双引号</span></pre></td></tr><tr><td data-num=\"7\"></td><td><pre> <span class=\"token literal-property property\">semi</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 行尾是否使用分号,默认为 true</span></pre></td></tr><tr><td data-num=\"8\"></td><td><pre> <span class=\"token literal-property property\">trailingComma</span><span class=\"token operator\">:</span> <span class=\"token string\">'none'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 是否使用尾逗号</span></pre></td></tr><tr><td data-num=\"9\"></td><td><pre> <span class=\"token literal-property property\">bracketSpacing</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 对象大括号直接是否有空格,默认为 true,效果:{a: 1}</span></pre></td></tr><tr><td data-num=\"10\"></td><td><pre><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></pre></td></tr></table></figure></li>\n<li>\n<p>vscode 下载 prettier 插件<br />\n vscode 下载了 prettier 插件后 在 vscode 的设置里面将 Format on Save 开启。这样当你 ctrl + s 保存的时候代码就会自动被 prettier 格式化<br />\n<img data-src=\"https://i.imgloc.com/2023/06/19/Vj92oU.png\" alt=\"Vj92oU.png\" /></p>\n</li>\n</ol>\n",
"tags": [
"笔记",
"前端",
"前端工程化",
"前端",
"前端工程化",
"工作流配置"
]
}
]
}