-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
617 lines (296 loc) · 388 KB
/
search.xml
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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>用ts重构基于rollup的npm包踩坑记录</title>
<link href="/posts/f1c4.html"/>
<url>/posts/f1c4.html</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在之前实现了一个npm包 <a href="https://juejin.cn/post/7282692942720204858#heading-16">我的第一个npm包:plugin-zip-pack - 掘金 (juejin.cn)</a></p><p>但源码是<code>js</code>编写的,最近想的使用<code>ts</code>进行重构一下。 最开始直接将源码中原来文件都修改为 <code>.ts</code>后缀后遇到了一系列报错问题、以及打包后出现的报错问题,经过一步步踩坑,最终都成功解决。谨以此篇记录自己的学习的过程,也希望能帮助到其他同学。</p><p>npm包地址:<br><a href="https://www.npmjs.com/package/plugin-zip-pack?activeTab=readme">plugin-zip-pack - npm (npmjs.com)</a></p><p>文档地址:<br><a href="https://silin001.github.io/docs/blogs/utils/pluginZipPack.html">https://silin001.github.io/docs/blogs/utils/pluginZipPack.html</a></p><h2 id="一、ts文件在vscode编辑器中报错问题"><a href="#一、ts文件在vscode编辑器中报错问题" class="headerlink" title="一、ts文件在vscode编辑器中报错问题"></a>一、ts文件在vscode编辑器中报错问题</h2><h3 id="编辑器提示找不到-require"><a href="#编辑器提示找不到-require" class="headerlink" title="编辑器提示找不到 require"></a>编辑器提示找不到 require</h3><p> <img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3bd2712322204916bd0a05d98c22877f~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1053&h=153&s=79994&e=png&b=262628" alt="image.png"></p><p>根据提示,安装 <code>@types/node</code> 可解决:<code>pnpm i @types/node -D</code></p><h3 id="ts文件中提示无法重新声明块范围变量"><a href="#ts文件中提示无法重新声明块范围变量" class="headerlink" title=".ts文件中提示无法重新声明块范围变量"></a>.ts文件中提示无法重新声明块范围变量</h3><p>由于之前js版本都是使用的<strong>CommonJS</strong>语法, 在 <code>util/index.ts</code> 中声明一个变量使用 <code>module.exports</code> 导出变量:</p><pre class="line-numbers language-js"><code class="language-js"><span class="token keyword">const</span> sucess <span class="token operator">=</span> chalk<span class="token punctuation">.</span>green<span class="token punctuation">;</span>module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> sucess<span class="token punctuation">,</span><span class="token comment" spellcheck="true">// ...</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>在 <code>index.ts</code> 中 使用<code>require</code> 引入</p><pre class="line-numbers language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> sucess <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./src/util/index'</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">// ...</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p> <img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/db95b222edf3467a8803960bbb5dda08~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1573&h=546&s=311683&e=png&b=262235" alt="image.png"></p><p><strong>原因:</strong><br>因为直接修改了文件为 <code>.ts</code> , 当在 <code>TypeScript</code> 中遇到变量重新声明的问题时,通常是因为在不同的文件中重复定义了同一个变量名。</p><p><strong>解决:</strong> 需要使用 <code>TypeScript</code> 的模块系统,也就是 <code>import、export</code> 的方式来导入导出ts文件中的模块,并避免在不同的文件中重复声明相同的变量名。使用 es6 规范导入导出后问题解决。</p><h3 id="Did-you-mean-to-set-the-‘moduleResolution’-option-to-‘nodenext’-or-to-add-aliases-to-the-‘paths’-option"><a href="#Did-you-mean-to-set-the-‘moduleResolution’-option-to-‘nodenext’-or-to-add-aliases-to-the-‘paths’-option" class="headerlink" title="Did you mean to set the ‘moduleResolution’ option to ‘nodenext’, or to add aliases to the ‘paths’ option?"></a>Did you mean to set the ‘moduleResolution’ option to ‘nodenext’, or to add aliases to the ‘paths’ option?</h3><p>引入第三方依赖时报错:<br><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/53930d28d8af4a6a83e29470cd47473b~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=802&h=297&s=98594&e=png&b=1d1a26" alt="image.png"></p><p>根据提示在 <code>tsconfig.json</code> 中 <code>compilerOptions</code> 字段加入此配置后解决: <code>"moduleResolution": "nodenext"</code></p><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f74bd7bea76e4172ae8ccbb52ba671d1~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=604&h=547&s=107236&e=png&b=272336" alt="image.png"></p><h3 id="找不到模块“-package-json”。请考虑使用-“–resolveJsonModule”-导入带-“-json”-扩展的模块"><a href="#找不到模块“-package-json”。请考虑使用-“–resolveJsonModule”-导入带-“-json”-扩展的模块" class="headerlink" title="找不到模块“../package.json”。请考虑使用 “–resolveJsonModule” 导入带 “.json” 扩展的模块"></a>找不到模块“../package.json”。请考虑使用 “–resolveJsonModule” 导入带 “.json” 扩展的模块</h3><p>在.ts文件中引入json文件,vscode报错:</p><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/abf7613cb9b54e4c8a14b51a313f6ec2~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=904&h=291&s=96945&e=png&b=1d1a26" alt="image.png"><br><strong>解决:</strong><br><code>tsconfig.json</code> 中 <code>compilerOptions</code> 字段加入如下配置后解决:</p><pre class="line-numbers language-js"><code class="language-js"><span class="token string">"esModuleInterop"</span><span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><span class="token string">"resolveJsonModule"</span><span class="token punctuation">:</span> <span class="token boolean">true</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h2 id="二、rollup-打包遇到的报错"><a href="#二、rollup-打包遇到的报错" class="headerlink" title="二、rollup 打包遇到的报错"></a>二、rollup 打包遇到的报错</h2><h3 id="Error-Cannot-find-module-‘typescript’"><a href="#Error-Cannot-find-module-‘typescript’" class="headerlink" title="Error: Cannot find module ‘typescript’"></a>Error: Cannot find module ‘typescript’</h3><blockquote><p>ps: 找不到模块“typescript”</p></blockquote><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c2280b84711f4fffa9c529f7db5deade~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1051&h=289&s=48355&e=png&b=262335" alt="image.png"></p><p><strong>报错原因:</strong> 源码工程中没有安装 ts</p><p><strong>解决:</strong><br>安装ts: <code>pnpm i typescript -D</code></p><p>安装完ts还是不行,打包发现提示:</p><p> <code>(plugin typescript) Error: @rollup/plugin-typescript: Could not find module 'tslib', which is required by this plugin. Is it installed?</code></p><p> 然后根据提示安装 <code>tslib</code> :<code>pnpm i tslib -D</code></p><p> 重新使用 <code>rollup</code> 打包成功解决:</p><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f4208d778344a1080dcac3cde1b7c2a~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=649&h=153&s=12312&e=png&b=262335" alt="image.png"></p><h3 id="Uncaught-ReferenceError-require-is-not-defined"><a href="#Uncaught-ReferenceError-require-is-not-defined" class="headerlink" title="Uncaught ReferenceError: require is not defined"></a>Uncaught ReferenceError: require is not defined</h3><p><code>Rollup</code> 打包代码时,在代码中使用了<code>CommonJS语法</code>(如:使用了<code>require</code>),但 <code>Rollup</code> 默认使用ES6模块语法(如:<code>import、export</code>)</p><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d97c0c84669d4befaa1e802cd8638e3e~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=885&h=76&s=7959&e=png&b=fceded" alt="image.png"></p><p><strong>报错原因:</strong></p><p>而我这里是因为我的源码中用 <code>require</code> 引入了node环境的一些api,如:fs等。 然后用 <code>Rollup</code>工具打包后生成.js 在浏览器环境(html中script引入)中使用时,此时浏览器就会报这个错: <code>require is not defined</code></p><p><strong><code>require</code> 是 <code>CommonJS</code> 规范中用于导入模块的关键字,而浏览器环境下是不认识 <code>require</code>的!</strong></p><p><strong>解决方案:</strong></p><ul><li><p>在代码中使用ES6模块语法替换CommonJS语法</p></li><li><p>在Rollup的配置文件中使用插件解决(例如 <code>@rollup/plugin-commonjs</code>),以便 <code>Rollup</code> 能够识别并正确处理<code>CommonJS</code>语法。</p></li></ul><h3 id="SyntaxError-Cannot-use-import-statement-outside-a-module"><a href="#SyntaxError-Cannot-use-import-statement-outside-a-module" class="headerlink" title="SyntaxError: Cannot use import statement outside a module"></a>SyntaxError: Cannot use import statement outside a module</h3><blockquote><p>ps: SyntaxError:不能在模块外使用 import 语句</p></blockquote><p><strong>报错原因:</strong> 在js文件中是无法直接使用 <code>import/export</code> es6语法</p><p><strong>解决方案:</strong></p><ul><li><p>在 <code>package.json</code> 中设置type字段 <code>“type”:“module”</code></p></li><li><p>使用 <code>.mjs</code> 的扩展名(从 Node.js v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持。Node.js 要求 ES6 模块采用 <code>.mjs</code> 的后缀文件名)</p></li></ul><h3 id="Error-ERR-REQUIRE-ESM-require-of-ES-Module"><a href="#Error-ERR-REQUIRE-ESM-require-of-ES-Module" class="headerlink" title="Error [ERR_REQUIRE_ESM]: require() of ES Module"></a>Error [ERR_REQUIRE_ESM]: require() of ES Module</h3><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/478f5c2c4f564864aa3b03de23c93ecd~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1032&h=271&s=47379&e=png&b=262335" alt="image.png"></p><blockquote><p>ps: 试图在 <code>index.umd.js</code> 文件中使用了 <code>require()</code> 引入了一个 ES 模块(ES Module),但在这种情况下是不被支持的;<br>要解决这个问题,你需要调整 <code>xxx/index.umd.js</code> 文件中的代码。</p></blockquote><p><strong>报错原因:</strong></p><p>错误 <code>[ERR_REQUIRE_ESM]</code> 表示: <code>require()</code> 函数试图引入一个 ES 模块,但在这个文件的上下文环境中不被支持。</p><p>对应到我的这个npm包的源码中是因为我使用 <code>require</code> 引入了 <code>chalk</code> 依赖</p><p><strong>解决:</strong><br>将 <code>require</code> 修改为 <code>import</code> 方式引入后解决</p><h4 id="chalk-依赖库"><a href="#chalk-依赖库" class="headerlink" title="chalk 依赖库"></a>chalk 依赖库</h4><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fe13c7c573264510bb7c75b8a0afdf90~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=973&h=244&s=96386&e=png&b=262134" alt="image.png"></p><p>查看 <code>chalk</code> 源码发现是使用 <code>cjs</code> 规范导出的。</p><p>在 <code>Rollup</code> 打包后的项目中,即使 <code>chalk</code> 包只导出了 <code>CommonJS</code> 规范(CJS),仍然需要使用动态 <code>import</code> 引入的主要原因是为了<strong>确保代码的兼容性和可靠性</strong>。</p><h3 id="Error-Cannot-find-module-‘-package-json’"><a href="#Error-Cannot-find-module-‘-package-json’" class="headerlink" title="Error: Cannot find module ‘../package.json’"></a>Error: Cannot find module ‘../package.json’</h3><p>源码中使用 require 引入package.json 文件后打包后报错<br><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f395f8fed6fb4c4cb24040fe1bb12bcf~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1005&h=634&s=120338&e=png&b=272336" alt="image.png"></p><p><strong>报错原因:</strong> 默认情况下<code>rollup.js</code> 不支持导入 json 模块, 无论是 <code>require</code> 还是 <code>import</code> 方式</p><p><strong>解决方案:</strong></p><ul><li><p>安装@rollup/plugin-json插件支持使用 import 导入json文件<br><code>pnpm i -D @rollup/plugin-json</code></p></li><li><p>使用 node的 fs.readFileSync 读取文件</p></li></ul><p>使用node模块的 <code>resolve</code> 获取真实的json文件的路径,然后使用fs模块的<code>readFileSync</code>方法读取文件内容,从而获取到json中name、version等内容。</p><pre class="line-numbers language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> version <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">getPackJson</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">function</span> getPackJson <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> pkg <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span> version<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 使用 resolve 获取真实的json文件 path路径</span> <span class="token keyword">const</span> packageJsonPath <span class="token operator">=</span> <span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">"package.json"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// 读取文件内容</span> <span class="token keyword">const</span> packageJsonString <span class="token operator">=</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>packageJsonPath<span class="token punctuation">,</span> <span class="token string">"utf8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> version <span class="token punctuation">}</span> <span class="token operator">=</span> JSON<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>packageJsonString<span class="token punctuation">)</span><span class="token punctuation">;</span> pkg<span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span> pkg<span class="token punctuation">.</span>version <span class="token operator">=</span> version<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">err</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"无法读取npm包的 package.json 文件:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"pkg--"</span><span class="token punctuation">,</span> pkg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> pkg<span class="token punctuation">;</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="三、其他"><a href="#三、其他" class="headerlink" title="三、其他"></a>三、其他</h2><h3 id="rollup打包ts类型文件"><a href="#rollup打包ts类型文件" class="headerlink" title="rollup打包ts类型文件"></a>rollup打包ts类型文件</h3><p>使用<code>pnpm i -D rollup-plugin-dts</code>插件来生成ts类型文件</p><pre class="line-numbers language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> dts <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"rollup-plugin-dts"</span><span class="token punctuation">;</span><span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token comment" spellcheck="true">// …</span> <span class="token punctuation">{</span> input<span class="token punctuation">:</span> <span class="token string">"./src/index.ts"</span><span class="token punctuation">,</span> output<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> file<span class="token punctuation">:</span> <span class="token string">"build/index.d.ts"</span><span class="token punctuation">,</span> format<span class="token punctuation">:</span> <span class="token string">"es"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">dts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">export</span> <span class="token keyword">default</span> config<span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>配置完成后 当执行 <code>rollup -c</code> 时会根据配置文件自动打包到 <code>build/index.d.ts</code><br><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/51d9813677a3460fbb23601904fab053~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=822&h=643&s=287957&e=png&b=282336" alt="image.png"></p><p>此时,使用es语法导入时就有了智能提示:<br><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/188c2daca87245b2b7ad5d71b2f08933~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1132&h=174&s=59933&e=png&b=211f2b" alt="image.png"></p><p>当错误使用导出的方法时也会有ts类型提示:</p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/09818d945d6646438c783d2c5a3bdd38~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=696&h=229&s=52339&e=png&b=1b1924" alt="image.png"></p><h3 id="重构前-npm插件在vite中使用警告"><a href="#重构前-npm插件在vite中使用警告" class="headerlink" title="重构前 npm插件在vite中使用警告"></a>重构前 npm插件在vite中使用警告</h3><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e6d30718d5eb45ef8be4bd79fba9152f~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=634&h=451&s=113840&e=png&b=1c1a25" alt="image.png"></p><p>使用ts编写源码,给导出的 vite函数 添加一个 type 类型来约束:</p><pre class="line-numbers language-js"><code class="language-js"><span class="token comment" spellcheck="true">/** 支持vite插件类型 */</span><span class="token keyword">export</span> type VitePluginZipPackType <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> string<span class="token punctuation">;</span> apply<span class="token punctuation">:</span> <span class="token string">"build"</span><span class="token punctuation">;</span> closeBundle<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token keyword">void</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="四、npm包发布相关"><a href="#四、npm包发布相关" class="headerlink" title="四、npm包发布相关"></a>四、npm包发布相关</h2><h3 id="npm-发布时使用-opt码进行二次验证"><a href="#npm-发布时使用-opt码进行二次验证" class="headerlink" title="npm 发布时使用 opt码进行二次验证"></a>npm 发布时使用 opt码进行二次验证</h3><p>由于我设置了npm二次验证,发布时需要输入在手机 <code>Authenticator App</code> 上输入 <code>opt</code> 验证码即可:</p><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d5a698dd5a524694b4f0f273351f4d19~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1098&h=321&s=36343&e=png&b=262335" alt="image.png"></p><p>发布成功会有邮件通知:<br><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07a08ff5920a495388a67ca9f5359bd4~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=621&h=187&s=9412&e=png&b=fdfdfd" alt="image.png"></p><h3 id="npm-login报错"><a href="#npm-login报错" class="headerlink" title="npm login报错"></a>npm login报错</h3><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/45a54873c3b149c087abdedaebf49123~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1291&h=286&s=56308&e=png&b=262335" alt="image.png"></p><p><strong>原因:</strong> 使用了代理软件网络环境有问题、设置的proxy代理环境有问题,可能会有缓存</p><p><strong>解决:</strong> 关闭代理软件后重新login尝试(可能需要多次尝试)、清除npm缓存</p><h3 id="npm-unpublish-删除已发布包的指定版本"><a href="#npm-unpublish-删除已发布包的指定版本" class="headerlink" title="npm unpublish 删除已发布包的指定版本"></a>npm unpublish 删除已发布包的指定版本</h3><p>npm login 登录后直接删除指定版本: <code>npm unpublish 包名称@版本号</code></p><p><strong>注意:</strong></p><ul><li>不允许撤销发布已经超过 24 小时的包,撤销发布 24 小时内的包需要加 <code>--force</code> 参数</li><li>撤销之前发布的包,再次发布的时候不能与之前被撤销的<code>包的名称/版本</code>其中之一相同,因为这两者构成的唯一性已经被占用,官方并没有随着撤销而删除</li></ul><h3 id="npm-deprecate-弃用发布的包"><a href="#npm-deprecate-弃用发布的包" class="headerlink" title="npm deprecate 弃用发布的包"></a>npm deprecate 弃用发布的包</h3><p><code>npm unpublish</code> 官方推荐的替代命令 <code>npm deprecate</code></p><p><code>npm deprecate 包名称@版本号</code></p><p><code>npm deprecate</code> 命令不会在 <code>npm</code>官网上撤销对应的包,而是会在使用安装该包时给出下面的提示信息:</p><blockquote><p>If you no longer wish to maintain a package, or if you would like to encourage users to update to a new or different version, you can <a href="https://npm.nodejs.cn/deprecating-and-undeprecating-packages-or-package-versions#">deprecate</a> it. Deprecating a package or version will print a message to the terminal when a user installs it.</p></blockquote><h3 id="npm-发布新版本后使用时版本号不更新"><a href="#npm-发布新版本后使用时版本号不更新" class="headerlink" title="npm 发布新版本后使用时版本号不更新"></a>npm 发布新版本后使用时版本号不更新</h3><p>npm包发布新的版本号后,在项目里直接 <code>pnpm install</code> 进行安装时可能暂时还是旧版本号,但是npm官网已经显示有了新版本号,这是因为刚发布的包可能还没更新好,需要等待一段时间(我是当天发布了新版本npm包,次日安装时版本号才自动更新最新的)重新安装查看</p><h2 id="五、最终npm包使用"><a href="#五、最终npm包使用" class="headerlink" title="五、最终npm包使用"></a>五、最终npm包使用</h2><h3 id="webpack-config-js"><a href="#webpack-config-js" class="headerlink" title="webpack.config.js"></a>webpack.config.js</h3><p>在.js配置文件中使用 es模块 <code>import</code> 时会报错: <code>SyntaxError: Cannot use import statement outside a module</code></p><p>所以需要使用cjs模块导入: <code>const { test, pluginZipPackVite } = require('plugin-zip-pack')</code></p><h3 id="vite-config-ts"><a href="#vite-config-ts" class="headerlink" title="vite.config.ts"></a>vite.config.ts</h3><p>在.ts配置文件中可以使用时 es、cjs模块引入都支持:</p><p><code>import { test, pluginZipPackVite } from 'test-plugin-zip-pack'</code><br>or<br><code>const { test, pluginZipPackVite } = require('plugin-zip-pack')</code></p><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7d01360086e9446d8a2f50589bcfbbd1~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1015&h=286&s=40523&e=png&b=262335" alt="image.png"></p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<tags>
<tag> rollup </tag>
<tag> typescript </tag>
</tags>
</entry>
<entry>
<title>vuepress@2.x 报错问题分享</title>
<link href="/posts/930f.html"/>
<url>/posts/930f.html</url>
<content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>在使用<code>vuepress@2.x</code> 搭建博客项目时,使用 <code>github actions</code>部署时失败了很多次,踩过的坑汇总记录一下自己的学习过程,也希望可以帮助到其他同学。</p><h2 id="打包时出现的错误"><a href="#打包时出现的错误" class="headerlink" title="打包时出现的错误"></a>打包时出现的错误</h2><h3 id="config-js配置遇到的问题"><a href="#config-js配置遇到的问题" class="headerlink" title="config.js配置遇到的问题"></a>config.js配置遇到的问题</h3><p>配置文件使用<code>config.js</code>正常配置后报错:<br><code>SyntaxError: Cannot use import statement outside a module</code><br><strong>不能在模块外使用import语句</strong></p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4a1504cc6ad344e79df5851930454035~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>对于这个错误网上大多数解决方案都是这两种:</p><ul><li>package.json 中设置字段 “type”:“module”</li><li>使用 .mjs 的扩展名</li></ul><p>于是我尝试解决…</p><h4 id="在-package-json-中设置字段-报错"><a href="#在-package-json-中设置字段-报错" class="headerlink" title="在 package.json 中设置字段 报错"></a>在 package.json 中设置字段 报错</h4><p>Error [ERR_REQUIRE_ESM]: require() of ES Module</p><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/795d2d971ef14ba89ea27173ff069cbd~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>意思是不支持require,如果你想用这个,那么变成import的写法,但是我的配置文件里用的就是 import 啊,于是删除 <code>“type”:“module”</code></p><h4 id="修改为-mjs-问题"><a href="#修改为-mjs-问题" class="headerlink" title="修改为 .mjs 问题"></a>修改为 .mjs 问题</h4><blockquote><p>从 Node.js v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持。Node.js 要求 ES6 模块采用 .mjs 后缀文件名。<br>JavaScript 的两种模块:ES6 模块(ESM)、 CommonJS 模块(CJS)<br>CommonJS 模块使用 require() 和 module.exports<br>ES6 模块使用 import 和 export</p></blockquote><p>直接修改 .js 为 .mjs 此时打包竟然没问题成功了,但是发现部署后的文件 404</p><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4493740cf203458784299f8294a21e30~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3209e9d3687444f2b9b285679a1a8528~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>可以看出来是路径问题,少一层 <code>/docs/</code>,但是我 config 配置文件里已经配置了 <code>base: "/docs/"</code></p><p>我猜测是打包后(本地这么配置启动是没什么问题的)无法读取 .mjs 的文件,所以配置的 docs没生效。只能暂时放弃这个方案了。</p><h4 id="todo…"><a href="#todo…" class="headerlink" title="todo…"></a>todo…</h4><p>在下面更换为.ts配置实践时,发现注释 yml文件中对 install缓存后,.mjs格式也可以正常打包,只不过源码报错 <code>TypeError: Cannot read properties of undefined (reading 'replace')</code>,导致不能继续测试部署后404问题。</p><p>等后续 <code>vuepress-theme-reco@2.x</code><strong>作者更新版本后</strong>,再回来CICD测试这里修改为 <code>.mjs</code>部署后是否可行。</p><p> 版本已更新:<br> <code>vuepress-theme-reco@2.0.0-beta.68</code>,使用该版本跑 cicd也成功了。</p><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0aa5c02f4b3741a6b40a5599abedabdd~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1487&h=893&s=119502&e=png&b=ffffff" alt="image.png"></p><h3 id="node版本过高问题"><a href="#node版本过高问题" class="headerlink" title="node版本过高问题"></a>node版本过高问题</h3><p><code>error:0308010C:digital envelope routines::unsupported</code></p><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/00e4cd5a0d2f4a0e97e54e662d50a912~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>解决:<br>降低 node版本 18.X 改为 16.x后成功</p><h2 id="修改为config-ts问题"><a href="#修改为config-ts问题" class="headerlink" title="修改为config.ts问题"></a>修改为config.ts问题</h2><p>配置文件修改为 <code>config.ts</code>尝试结果还是报错:<br><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/945405b4d83645c6910637c244a79753~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>找不到从 xxx.mjs 导入的包 vuepress-theme-reco 主题</p><p>这个问题我也卡了很久,由于我一直是使用githun actions测试的,于是我关注到了yml文件,注意到了其中配置的 <code>node_modules</code> 和 <code>install</code> 的缓存。 果断注释,重新提交测试。</p><p>已经不报上图这个错误了,但是会报下面错误,别急继续往下看。</p><h2 id="vuepress-theme-reco-2-x相关报错"><a href="#vuepress-theme-reco-2-x相关报错" class="headerlink" title="vuepress-theme-reco@2.x相关报错"></a><a href="mailto:vuepress-theme-reco@2.x">vuepress-theme-reco@2.x</a>相关报错</h2><h3 id="TypeError-Cannot-read-properties-of-undefined-reading-‘replace’"><a href="#TypeError-Cannot-read-properties-of-undefined-reading-‘replace’" class="headerlink" title="TypeError: Cannot read properties of undefined (reading ‘replace’)"></a>TypeError: Cannot read properties of undefined (reading ‘replace’)</h3><p>依赖信息:</p><pre class="line-numbers language-js"><code class="language-js"> <span class="token string">"vuepress"</span><span class="token punctuation">:</span> <span class="token string">"2.0.0-beta.66"</span><span class="token punctuation">,</span> <span class="token string">"vuepress-theme-reco"</span><span class="token punctuation">:</span> <span class="token string">"^2.0.0-beta.67"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/73fa1a0f8f6648c1b9a4f5071e48eb46~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>这里我使用最新 <code>vuepress-theme-reco</code>的<code>2.0.0-beta.67</code> 版本打包时报错,由于先开始没有仔细看错误信息,一直认为是版本问题导致,所以就频繁切换版本尝试未果,浪费了大把时间。</p><p>仔细阅读报错信息 <code>TypeError: formatISODate(...).split is not a function</code> 最后在 node_modules下找到对于源码位置,发现是源码中这个方法在一个 <code>timeline</code>文件中调用时传参 <code>undefined</code> 导致了这个错误(已提 <code>issues</code>)</p><p>所以只能本地修改源码后打包测试成功:</p><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8556e11f87184dd29a753be01d1c3b93~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>而想使用 github actions 自动部署,只能等该主题作者后续更新版本后测试了。</p><p>后续更新…</p><h2 id="后续更新"><a href="#后续更新" class="headerlink" title="后续更新"></a>后续更新</h2><p>经过提交 issues, <code>vuepress-theme-reco</code>目前已经更新版本到 <code>2.0.0-beta.68</code> 版本,本文中问题已解决。</p><p>目前使用以下依赖正常:</p><pre class="line-numbers language-js"><code class="language-js"> <span class="token string">"devDependencies"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"vuepress"</span><span class="token punctuation">:</span> <span class="token string">"2.0.0-beta.67"</span><span class="token punctuation">,</span> <span class="token string">"vuepress-theme-reco"</span><span class="token punctuation">:</span> <span class="token string">"^2.0.0-beta.68"</span> <span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> vuepress </category>
</categories>
<tags>
<tag> vuepress </tag>
</tags>
</entry>
<entry>
<title>GitHub Actions 体验CICD</title>
<link href="/posts/2c5.html"/>
<url>/posts/2c5.html</url>
<content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>工作后,经常听闻同行提到自动化部署、CICD等关键词。出于好奇也去网上看了一些相关资料得以了解。由于我还没接触到有相关配置的项目,但自己也一直想尝试体验一下这个东西。但奈何自己相关知识匮乏,水平有限,之前尝试过几次最终以失败告终。</p><p>再加上工作忙自己懒,慢慢的也就搁置了,但我一直没忘,哈哈哈</p><p>今天打算重新拾起来,虽然网上教程一大堆,但我还是想自己亲手记录一下这个过程,毕竟对我来说一路坎坷。也希望能帮助到初次探险的你。</p><h2 id="学到什么?"><a href="#学到什么?" class="headerlink" title="学到什么?"></a>学到什么?</h2><p>阅读本文将学习到:</p><ul><li>理解cicd</li><li>使用 github actions体验cicd</li><li>多项目部署github pages</li></ul><h2 id="CI-CD是什么?"><a href="#CI-CD是什么?" class="headerlink" title="CI/CD是什么?"></a>CI/CD是什么?</h2><blockquote><p>CI - 持续集成(Continuous Integration)<br>CD - 持续交付 (Continuous Delivery)<br>CD - 持续部署 (Continuous Deployment)</p></blockquote><p> 这里先不具体纠结这些关键字的含义,往下看你就大致明白了</p><h3 id="手动部署"><a href="#手动部署" class="headerlink" title="手动部署"></a>手动部署</h3><p>没有配置CICD前,你可能需要这样部署前端项目:</p><ol><li>打包代码 (如:npm run build)</li><li>打开 FTP 工具 (如:FileZilla),</li><li>登录到服务器</li><li>找到对应的服务器前端静态目录以及本地目录</li><li>上传文件</li></ol><p>没有配置<strong>自动化部署</strong>的项目,部署流程往往复杂繁琐,成本较高。那你可能会想能不能实现类似一键部署,简化上述操作过程呢?</p><p>答案是:必须当然可以!</p><p>通过一个万能的<code>shell</code> 脚本自动执行以上所有操作,也就是你可能听过的自动化部署。有没有很兴奋?</p><h3 id="自动化部署"><a href="#自动化部署" class="headerlink" title="自动化部署"></a>自动化部署</h3><ol><li>提交代码<br>没错,自动化部署你只需要做<strong>一件事</strong>就是提交代码,过几分钟就可以刷新生产环境站点查看最新部署的内容了(前提是配置好CICD)</li></ol><h3 id="CICD工具"><a href="#CICD工具" class="headerlink" title="CICD工具"></a>CICD工具</h3><p>市面上有很多优秀的 CICD 工具,场景也会更复杂。</p><ul><li><p>Jenkins:基于 Java、跨平台、开源、独立的 CI/CD 工具,有大量的插件帮助完成软件开发过程的自动化构建、测试和部署。</p></li><li><p>Travis CI:基于云平台的、开源的 CICD 工具,可用于构建托管在 Github、Bitbucket、GitLab上的项目。</p></li><li><p>Circle CI:与 Travis CI 同样是云平台构建,支持 Github、Bitbucket、GitLab。</p></li></ul><ul><li>Github Actions:使用云平台构建托管在 Github 之上的项目。</li></ul><p>对于 Jenkins,需要先准备一台服务器安装好环境。而后三者全部是基于<strong>云平台的工具</strong>,我们只需要将代码托管到对应的平台,在让它们介入即可,使用起来会更加简单。</p><p>本文使用 Github Actions 进行演示,不需要跑ci的服务器。用最简单的配置实现github中提交代码,自动编译,自动部署到 <code>github pages</code>(或自己的服务器)</p><h2 id="Github-Actions-部署"><a href="#Github-Actions-部署" class="headerlink" title="Github Actions 部署"></a>Github Actions 部署</h2><blockquote><p>什么是 Github Actions? 它是一个持续集成和持续交付(CI/CD)平台。<br>那么它是怎么实现自动化呢?<br>在 Github Actions 中会提供一些钩子,检测到仓库某个特定活动触发,就会执行这些脚本,<code>GitHub</code> 把这些触发钩子称为<code>事件</code>,这些脚本称为 <code>actions</code>。<br>同时,官方也提供了一个类似 npm.cn 这样的<a href="https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fmarketplace%3Ftype%3Dactions" title="https://github.com/marketplace?type=actions">公共市场</a>,在这里面你可以搜到别人写好提交的 <code>actions</code>,这样你就可以很方便复用别人造的脚本轮子了。</p></blockquote><h3 id="Github-Actions-CICD流程图(摘自网络)"><a href="#Github-Actions-CICD流程图(摘自网络)" class="headerlink" title="Github Actions CICD流程图(摘自网络)"></a>Github Actions CICD流程图(摘自网络)</h3><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/40a25a8572c04c7eb0bd92483e9407d3~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h2 id="多个项目部署github-pages上"><a href="#多个项目部署github-pages上" class="headerlink" title="多个项目部署github pages上"></a>多个项目部署github pages上</h2><p>由于github的所有项目只能有一个 <code>GitHub Pages</code> 域名那就是 :<code>https://username.github.io</code> 这里我就默认你已经完成这一步了。</p><p>比如我的域名地址: <a href="https://silin001.github.io/">silin001.github.io</a></p><p>其他开启<code>github pages</code> 的项目都是<strong>这个域名的子目录</strong></p><p>如果想将一个小demo(或者文档)也部署到<code>GitHub Pages</code>中供外界进行访问,那具体应该如何实现呢?</p><p>首先在需要部署的github项目中来到<code>Settings</code>中 <code>GitHub Pages</code>标签中,指定分支和目录,也就是开启该项目的 <code>GitHub Pages</code>功能。 这样系统会自动<strong>按项目名称</strong>分配<strong>域名子路径</strong>。</p><p>例如此时的域名访问路径变成了:<code>https://username.github.io/xxxproject</code></p><p>接下来我们就在项目中开始实践吧。</p><h3 id="package-json中添加homepage"><a href="#package-json中添加homepage" class="headerlink" title="package.json中添加homepage"></a>package.json中添加homepage</h3><p><code>"homepage": "https://username.github.io/project"</code></p><h3 id="项目中添加github-workflow"><a href="#项目中添加github-workflow" class="headerlink" title="项目中添加github workflow"></a>项目中添加github workflow</h3><p>github workflow,可以实现<strong>自动化流水线</strong>。</p><p>拉取我们远程仓库项目到本地后,根目录下创建 <code>.github/workflows</code>目录,创建 <code>cicd.yml</code>(名字自定义) 文件,添加如下内容:</p><pre class="line-numbers language-yml"><code class="language-yml">name: todoList 自动部署on: push: branches: - mainjobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: pnpm/action-setup@v2 with: version: 8.6.2 - uses: actions/setup-node@v3 with: node-version: 16.X - run: npm install - run: npm run build - name: action-Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.DEPLOY_SECRET }} BRANCH: gh-pages publish_dir: ./dist<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>使用社区的各种<code>actions</code>可以帮我们实现重复的自动化需求。</p><p>比如我们这里需要部署<code>gh-pages</code>,我们可以设置触发时机为push到主分支的时候触发,这样我们每次合并到主分支,就会自动触发部署了。</p><h4 id="配置-secrets"><a href="#配置-secrets" class="headerlink" title="配置 secrets"></a>配置 secrets</h4><p>因为yml文件中需要用到 <code>github token</code>,首先要生成一个 Github 密钥,完成之后记得复制一下(刷新页面后就不可查看了)然后去自己的项目仓库中操作:</p><ul><li>点击 <code>settings</code></li><li>点击左侧 <code>Secrets</code></li><li>点击右侧按钮 <code>new repository secret</code></li><li>创建的名字和 <code>.yml</code> 中的 <code>secret.xxx</code> 要对应,值就写刚刚生成的 Github 密钥。</li></ul><h4 id="CICD部署到服务器"><a href="#CICD部署到服务器" class="headerlink" title="CICD部署到服务器"></a>CICD部署到服务器</h4><p>如果自己有服务器的话,可以尝试部署到服务器,这一步我未验证。</p><pre class="line-numbers language-yml"><code class="language-yml">name: 自动部署到服务器测试on: push: branches: - mainjobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 16.X - run: npm install - run: npm run build # 部署到服务器(此步骤待测试) - name: 部署到服务器 uses: easingthemes/ssh-deploy@v2.0.7 # 注入环境变量供ssh-deploy使用 env: # secrets中配置的私钥,用于免密连接服务器 SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} # 服务器地址 REMOTE_HOST: ${{ secrets.REMOTE_HOST }} # 用户名 REMOTE_USER: ${{ secrets.REMOTE_USER }} # 部署路径 TARGET: ${{ secrets.TARGET }} # 打包文件来源 SOURCE: "dist/" # 删除服务器上TARGET目录里所有文件 ARGS: "-avz --delete"<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="测试CICD"><a href="#测试CICD" class="headerlink" title="测试CICD"></a>测试CICD</h3><p>完成上述配置后,就可以提交代码到远程main分支,然后就可以在 Github 仓库的 <code>Actions</code> 选项中看到你的 <code>actions</code> 记录:</p><ul><li><p>进行中<br><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ddb77536244d4ac0a0557ee95c39be8b~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p></li><li><p>结果</p></li></ul><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d945a74d08424bc48e5eb196ad83fe33~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>点击可查看具体过程,失败时可以查看原因,修改后重新提交测试</p><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3cf823fb10054cafa52446c6b22ee3ca~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e0fa6f8debc94ed3bdbcd514fb90a9f6~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h3 id="我的错误过程"><a href="#我的错误过程" class="headerlink" title="我的错误过程"></a>我的错误过程</h3><p>可能刚开始会因为各种问题导致失败(不要放弃),我也是经历了数次失败(决战到凌晨),然后不断学习相关知识,检查修改配置文件,最终成功。</p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c9e8bd5689f7460f8063d2906ca3f475~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/09e6b7dad27f452b840647dad808c2c4~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h3 id="部署-Github-Pages"><a href="#部署-Github-Pages" class="headerlink" title="部署 Github Pages"></a>部署 Github Pages</h3><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ed05411eb15e4205b0a4f2889047d2d0~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>需要注意的是我们源码是推送到了 <code>main</code> 分支,而我们CICD打包后的产物是部署到了 <code>gh-pages</code> 分支,所以你远程仓库必须有这个分支。<br>且开启 <code>github pages</code>服务,选择部署到该分支(这个操作只需要做一次,如果你的工作流没问题下次提交完代码执行完cicd会自动部署)</p><p>此时,如果不出意外的话,然后点击该链接就可以访问到了:<a href="https://silin001.github.io/todolist_v3vite">https://silin001.github.io/todolist_v3vite</a></p><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0189259a4a714742a555147e54ca34be~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p> 尝试新事物的过程往往不会一帆风顺,但是只要坚持去做总是不会错的,要相信最终总会有收获。当你学会使用一个工具、学会一个技巧、学会一项技能时,那种成功的喜悦真的非常奇妙。</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> cicd </category>
</categories>
<tags>
<tag> cicd </tag>
</tags>
</entry>
<entry>
<title>开源之旅:初次贡献与PR提交流程</title>
<link href="/posts/6690.html"/>
<url>/posts/6690.html</url>
<content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>作为一名程序员,一直在公司项目上写代码,却从来没有参与过开源项目。虽然早之前了解过开源项目是什么?如何参加?但由于开源项目的规范要求严格和一些代码检查工具只是耳闻目睹,促使我望而却步。加上自己工作项目较忙、休息的时候也犯懒(主要是因为懒) 这件事就变成了只是想想,然后就搁置了。</p><p>最近看到了 <a href="https://juejin.cn/post/7256599901593124921">我们正在开发一套组件库,欢迎你的加入~ </a><br>这篇文章后,我下决心打算真正的参与进来。</p><p>俗话说万事开头难,但只要有了开始的心就算迈出一大步了。</p><p>由于第一次参加开源项目加上平常<code>git</code>用的较少(公司一直在用 svn),一些具体流程让我很迷 😭,于是我很多问题请教了项目中的 <a href="https://juejin.cn/user/3523264471898008">大飞同学</a>,真的很棒,帮我解惑。还有些问题也有询问过作者、以及群里的部分同学,大家也积极帮助解决,十分感谢!这种氛围真的很不错!</p><p>于是我打算梳理下开源流程,记录自己第一次开源经历,也希望能帮助到其他同学。</p><h2 id="项目地址"><a href="#项目地址" class="headerlink" title="项目地址"></a>项目地址</h2><p><a href="https://github.com/ecaps1038/yike-design-dev">yike-design-dev: Vue3+Ts+Less 开发的前端 UI 框架 (github.com)</a><br>欢迎大家积极参与</p><h2 id="fork-项目到自己仓库"><a href="#fork-项目到自己仓库" class="headerlink" title="fork 项目到自己仓库"></a>fork 项目到自己仓库</h2><p>第一步的话就是找到你要参与的开源项目 <code>github</code>仓库地址(我们叫它<strong>上游仓库</strong>)然后点击 <code>fork</code> 后,就会在自己仓库下看到一个与<strong>上游仓库</strong>一样的仓库,之后我们就要基于这个仓库去写代码。</p><ul><li><p>克隆 fork 的仓库到本地<br> <code>git clone xxx</code></p></li><li><p>查看关联的远程仓库</p><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">git</span> remote -v<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li><li><p>添加主仓库为远程仓库之一(只需操作一次)</p><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">git</span> remote add upstream xxx上游仓库地址<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li></ul><h2 id="创建需求分支规范"><a href="#创建需求分支规范" class="headerlink" title="创建需求分支规范"></a>创建需求分支规范</h2><p>建议一个分支处理一个需求。</p><p>格式: <code>${type}/${component}/${feat}</code><br>例子:</p><ul><li><code>feature/base/add-markdown-pure</code></li><li><code>feature/button/add-style</code></li><li><code>fix/icon/alignment-issue</code></li><li><code>docs/upload/add-picture-demo</code></li><li><code>refactor/base/refactor-router</code></li></ul><p>git 创建并切换分支:<br><code>git checkout -b feature/progress/init</code></p><h2 id="commit-提交规范"><a href="#commit-提交规范" class="headerlink" title="commit 提交规范"></a>commit 提交规范</h2><p>commmit 包含三部分内容 与分支规范类似: <code>${type}(${component}): ${commit-word}</code></p><p>例子:</p><ul><li><p><code>feat(button): add styles for button component</code></p></li><li><p><code>fix(icon): resolve alignment issue in icon component</code></p></li><li><p><code>docs(upload): update README file</code></p></li><li><p><code>refactor(base): refactor router module</code></p></li><li><p><code>feat(merge code): merge the upstream to update code</code></p></li></ul><p>git 操作:<br><code>git commit -m 'feat(merge): 合并上游仓库代码'</code></p><p>ps:其中符号都是英文格式,冒号后面必须有空格,因为项目有 <code>commit</code> 校验,不符合规范提交时是校验失败、提交失败的。</p><h3 id="我遇到的-commit-失败问题"><a href="#我遇到的-commit-失败问题" class="headerlink" title="我遇到的 commit 失败问题"></a>我遇到的 commit 失败问题</h3><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d9c0667a616f46218da56fef758d2b75~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><code>commit</code> 时直接报错: <code>npm ERR! Unexpected token '.'</code><br>打开日志文件也看不到啥有价值的信息,这个报错是在 win10 机器上出现的,然而在另外一台机器上就很正常。</p><p>请教大飞同学得知是因为执行 <code>husky</code> 脚本失败了、感觉 <code>npx</code> 有问题。但是切换了不同版本 <code>node</code>也没能解决。很是头疼,我是使用 <code>nvm</code> 管理的 <code>node</code> 环境,最后我卸载了 <code>nvm</code>,重装了较新版本后问题解决。有遇到这个问题的同学可以试试。</p><h2 id="写代码"><a href="#写代码" class="headerlink" title="写代码"></a>写代码</h2><p>当你认领好你想开发的任务,或者想解决的问题,创建好需求分支后,这一步没什么好说的就是写代码了。但需要注意的开源项目一般都有代码规范,使用了一些代码检查工具,如:<code>eslint</code>、<code>stylelint</code>等,写的时候需要注意下。</p><h2 id="与上游仓库同步(重点)"><a href="#与上游仓库同步(重点)" class="headerlink" title="与上游仓库同步(重点)"></a>与上游仓库同步(重点)</h2><p>因为当你 fork 完项目后此时你的代码和上游仓库是同步的,但是当你再进行自己的需求开发时,会有其他同学陆续提交 pr,更新上游仓库。此时你就需要让你的代码和上游仓库保持同步。</p><h3 id="1、更新上游仓库代码"><a href="#1、更新上游仓库代码" class="headerlink" title="1、更新上游仓库代码"></a>1、更新上游仓库代码</h3><p><code>git fetch upstream</code></p><p>upstream 就代表上游仓库,开始新需求开发时先更新。</p><h3 id="2、合并上游仓库代码"><a href="#2、合并上游仓库代码" class="headerlink" title="2、合并上游仓库代码"></a>2、合并上游仓库代码</h3><p><code>git merge upstream/monorepo-dev</code></p><p>此步骤将更新到的上游代码合并到你当前本地仓库<code>monorepo-dev</code>主分支上(其他分支是不会一起合并的!)如果此时更新到的上游仓库代码和你本地代码有冲突就需要先在编辑器中手动<strong>解决冲突、合并代码后</strong>再提交(见步骤 3)</p><h5 id="更新遇到冲突暂存代码"><a href="#更新遇到冲突暂存代码" class="headerlink" title="更新遇到冲突暂存代码"></a>更新遇到冲突暂存代码</h5><p>如果文件冲突可以一一解决,如果没有冲突可以选择暂存你本地的代码,再合并,合并完后再取出暂存代码继续开发。</p><ul><li><p>暂存代码<br><code>git stash</code></p></li><li><p>查看暂存<br><code>git stash list</code></p></li><li><p>取出暂存的代码<br><code>git stash pop</code></p></li></ul><h3 id="3、更新同步自己-fork-后的仓库"><a href="#3、更新同步自己-fork-后的仓库" class="headerlink" title="3、更新同步自己 fork 后的仓库"></a>3、更新同步自己 fork 后的仓库</h3><p>当完成第 1、2 步时,此时只是你本地代码和上游仓库保持了一致,但<strong>你 fork 后的远程仓库还没有同步</strong>,需要将本地代码提交(如果有冲突需要先解决才能提交)</p><p>提交本地代码到自己 fork 后到远程仓库:<br><code>git push</code></p><p>这一步操作没问题后,此时你本地代码和 fork 后的远程仓库的代码都和上游仓库代码保持同步了。</p><h3 id="4、需求分支注意"><a href="#4、需求分支注意" class="headerlink" title="4、需求分支注意"></a>4、需求分支注意</h3><p>如果在同步上游代码之前你已经创建了新的需求分支进行开发了,这时候你的需求分支代码和你主分支(monorepo-dev)<strong>是不同步的!</strong></p><p>需要先切换到需求分支<code>git checkout xxx需求分支</code> 然后把本地主分支代码再合并到需求分支保持同步:<code>git merge xxx主分支</code></p><p>这样你的主分支、需求分支代码也都同步了,可以继续你的新需求开发,然后提交更新 fork 后远程仓库的需求分支代码。</p><p><strong>ps:</strong><br>如果项目涉及到的多人修改同一文件情况较少、冲突就会少,这种情况就建议先在自己的需求分支开发,等完全开发完毕了再一次性的去拉取更新上游仓库代码、然后合并(有冲突解决)同步自己本地仓库、然后提交同步自己 fork 的远程仓库。</p><h2 id="提交-pr"><a href="#提交-pr" class="headerlink" title="提交 pr"></a>提交 pr</h2><p>当你负责的一个需求开发完毕后,此时就可以去 <code>github</code> 中提交 <code>PR(pull request)</code></p><p>PR 将由具备权限的贡献者 <code>CR(Code Review)</code> 后进行 <code>merge</code>,如果有问题也会给你提意见,然后你可以修改好再提交。</p><p>如果没问题,恭喜你,你的 <strong>PR</strong> 就会被合并到上游仓库,此刻就完成了开源项目的一次贡献流程。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这个项目对于没参加过开源的同学很友好,虽然刚开始完成的都是一些基础组件,且这些基础组件已经在业界内有实现 如:<code>element-ui</code>、<code>ant design</code> 等。</p><p>但等你真正的参与到项目中去开发实现的时候就会发现一个看上去简单的组件是需要考虑到很多细节问题的。</p><p>项目计划后期也会从基础组件出发,开始封装功能性组件、封装前后端组件。是一个很好的循序渐进的过程。</p><p>我相信如果能坚持开源这件事,日积月累编码和阅读源码的能力都会有很大的提升。</p><p><strong>如果文章对你有帮助,可以点击链接关注我的<a href="https://juejin.cn/user/2041110775208184/posts">掘金社区账号</a> 更多技术分享请移步我的掘金哦~</strong> 😀😀😀</p><p>点击链接 <a href="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群) - 掘金 (juejin.cn)</a> 加 vx 拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧 😎😎😎</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> pr </category>
</categories>
<tags>
<tag> github </tag>
<tag> pr </tag>
</tags>
</entry>
<entry>
<title>vue2应用性能优化:首屏FCP指标提升约80%</title>
<link href="/posts/9a81.html"/>
<url>/posts/9a81.html</url>
<content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>一个vue2的项目,打包部署后,发现首屏加载速度慢,FCP白屏时间大约需要8s左右,从输入系统地址按下回车后,就一直转啊转啊转,加载缓慢,导致用户的体验非常不好!所以今天针对这个问题来做一些性能优化。</p><p>期望的结果就是首屏加载速度快一点,白屏时间缩短,从而<strong>提升用户体验</strong>。</p><p>项目优化的方式、方向有很多。本文记录了我自己在项目中实践的一些优化操作,各项关键指标得到明显提升。</p><p><strong>往期推荐:</strong> <a href="https://juejin.cn/post/7218763788605440056">vue2项目dist瘦身——打包体积压缩73%、速度提升90%</a></p><h2 id="性能优化的重要性"><a href="#性能优化的重要性" class="headerlink" title="性能优化的重要性"></a>性能优化的重要性</h2><p>无论是在开发 Web 应用还是移动应用,优化项目和性能优化都是至关重要的。 </p><ul><li>优化项目<br>可以使我们更高效地组织和管理代码,<strong>提高代码质量</strong>和可读性,并确保应用程序的<strong>稳定性和可维护性</strong>。 </li><li>性能优化<br>针对性的性能优化,可以提高应用程序的<strong>响应速度</strong>、提高页面加载速度和用户体验,从而吸引更多用户并提高用户留存率。</li></ul><h2 id="【优化前】性能表现"><a href="#【优化前】性能表现" class="headerlink" title="【优化前】性能表现"></a>【优化前】性能表现</h2><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/78c5bbe8a676403cb56ec32d355055e1~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h2 id="优化前入口文件体积"><a href="#优化前入口文件体积" class="headerlink" title="优化前入口文件体积"></a>优化前入口文件体积</h2><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e977f6c1d950455f8db2c0557649e99b~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><ul><li>所有chunks总大小为 <strong>11.9 MB</strong> </li><li>首屏使用文件大小<br>chunk-vendors: <strong>3.79 MB</strong><br>index.js:<strong>2.37 MB</strong></li></ul><h3 id="图片相关"><a href="#图片相关" class="headerlink" title="图片相关"></a>图片相关</h3><p>项目使用了<code>url-loader</code>处理图片,压缩指定大小图片,减少http请求。但是这一步处理完后发现我们的js文件体积变大了,这是因为部分图片被打包到了js中,不着急,我们接着优化。</p><p><strong>all(12.59mb)<br>chunk-vendors:3.79mb<br>index.xxx.js: 大小 2.91mb</strong><br><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2942c1353c91459b9cae75aafb517de4~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h3 id="第三方插件优化"><a href="#第三方插件优化" class="headerlink" title="第三方插件优化"></a>第三方插件优化</h3><ul><li>剔除pafmake、xlsx</li></ul><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/65008cafe77147cb8d32862d3c579e73~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c9c62428476e40fa8b6edd3b25b44a99~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"><br> 仔细观察我发现上面打包出的chunk里有一个<code>pafmake</code>、<code>xlsx</code> 文件、我的项目是没有安装这个依赖的,仔细排查后发现是项目中使用了 <code>amecharts</code>库、而它就是其子依赖,其中还包含了 <code>xlsx</code>,我们是用不到这两个依赖的,所以要干掉他们!通过 <code>webpack</code> 的 <code>externals</code> 进行判断后剔除。</p><ul><li><p>moment 优化</p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5f417035ee74586baaf1db3debc11c4~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>我的项目中只用到了moment的中文包、但是它默认会把所有语言都打包进来了,所以我们要剔除其他的语言包减少依赖</p><pre class="line-numbers language-js"><code class="language-js"> plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token comment" spellcheck="true">// 剔除moment的其他语言包</span> <span class="token keyword">new</span> <span class="token class-name">webpack<span class="token punctuation">.</span>ContextReplacementPlugin</span><span class="token punctuation">(</span> <span class="token regex">/moment[/\\]locale$/</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 替换的模块名称正则表达式</span> <span class="token operator">/</span>zh<span class="token operator">-</span>cn<span class="token operator">/</span> <span class="token comment" spellcheck="true">// 替换模块的上下文路径</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p> 这一步优化后打包:<br> <strong>all(9.89mb)<br> chunk-vendors:3.56mb<br> index.xxx.js: 大小 2.91mb</strong> </p><p> <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/baaa5b2cb78b444fa196e39521151533~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p></li></ul><h2 id="【优化中】的性能表现"><a href="#【优化中】的性能表现" class="headerlink" title="【优化中】的性能表现"></a>【优化中】的性能表现</h2><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5a5abf6196044ffe90d72127035e7344~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h3 id="大体积无用文件处理"><a href="#大体积无用文件处理" class="headerlink" title="大体积无用文件处理"></a>大体积无用文件处理</h3><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ac128cfa6fc242aa9d37ff75153addef~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f522ac092f8b4c4cbe1f3ffdb80edda2~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><blockquote><p>仔细观察项目后发现有一个不小的json文件、还有一个文件夹下注册了很多的弹出组件,且经过排查发现这些组件在项目中是没有用到的!这里不清楚之前这里要做什么,所以这里我就先直接注释掉。</p></blockquote><h2 id="路由懒加载(关键)"><a href="#路由懒加载(关键)" class="headerlink" title="路由懒加载(关键)"></a>路由懒加载(关键)</h2><blockquote><p>仔细观察index.xxx.js文件发现很多文件是首页没有用到的页面,但是也被打包了进来,导致体积高达2.91mb<br>因为项目页面比较多,我对路由进行了重构,全部采用路由赖加载处理。</p></blockquote><h3 id="路由懒加载中遇到的问题"><a href="#路由懒加载中遇到的问题" class="headerlink" title="路由懒加载中遇到的问题"></a>路由懒加载中遇到的问题</h3><ul><li><p>使用魔法注释方式</p><pre class="line-numbers language-js"><code class="language-js"> component<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token comment" spellcheck="true">/* webpackChunkName: "[request]" */</span> <span class="token template-string"><span class="token string">`@/views/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>path<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.vue`</span></span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>最先开始我使用这种方式,通过魔法注释加载路由。由于路由页面比较多,写了一个方法动态去生成上面这段代码,但是项目中报错提示如下:</p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3bee640ef6c542299a373c22851d8c8b~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p> 项目打包后也直接报错提示找不到对应文件,反复确认过这个<strong>动态路由</strong>的路径是对的。</p></li><li><p>import动态引入<br> 尝试直接import动态引入也是不行的</p><pre class="line-numbers language-js"><code class="language-js"> component<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`@/views/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>path<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.vue`</span></span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p> 网上也有说使用<code>@babel/plugin-syntax-dynamic-import</code>插件可以支持解析动态语法,我尝试后还是会报错。 如果有朋友有好的解决方法欢迎评论区指点!<br>查询资料也有说 webpack4 不支持<strong>路由动态变量</strong>引入的方式。</p><p>此时,在想要是vue3环境就好了,有专门的异步api很方便。所以这里我只好乖乖的一个一个静态去引入路由了。</p></li></ul><p>所有路由赖加载方式引入改造后,此时我们打包再来看:</p><p><strong>all(8.3mb)<br>chunk-vendors:3.33mb</strong></p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/75625fdbee3c4658acf6ef920a7ac8a3~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><strong>index.xxx.js: 大小 26kb</strong><br><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/25b8999cac5147fb9d7db010fba1b474~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h2 id="优化后入口文件体积"><a href="#优化后入口文件体积" class="headerlink" title="优化后入口文件体积"></a>优化后入口文件体积</h2><ul><li>所有chunks总大小为 <strong>8.3 MB</strong> </li><li>首屏使用文件大小<br>chunk-vendors: <strong>3.33 MB</strong><br>index.js:<strong>25.93 KB</strong></li></ul><p><strong>总chunks 大小减少了 30%,首屏使用文件大小减少了 12%</strong></p><h2 id="【优化后】性能表现"><a href="#【优化后】性能表现" class="headerlink" title="【优化后】性能表现"></a>【优化后】性能表现</h2><ul><li>不开启gzip</li></ul><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/52c2ecd85a20452287a5df28cf116bb2~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8e7560f0fc594dfc8e5e6ac9d5431215~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><ul><li>开启gzip</li></ul><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2a2ccdf1903d4f3eba05f0309db73262~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/54c66a84c6a04673a664a03fa5bff60c~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>我们发现不开启gzip时,性能相比优化前也是有提升的。开启的话提升会更明显,效果更佳,具体怎么配置开启,在之前文章中也实践过,这里就略过了。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>经过上述操作配置后,主要指标提升结果:</p><ul><li>FCP: 从 <strong>8s</strong> 提升到最快—> <strong>1.6s,提升约80%</strong></li><li>SI: 从 <strong>8s</strong> 提升到最快—> <strong>3.7s,提升约54%</strong></li><li>LCP: 从 <strong>18.3s</strong> 提升到最快—> <strong>13.6s,提升约26%</strong></li><li>TTI:从 <strong>25.9s</strong> 提升到最快—> <strong>15.2s,提升约41%</strong></li><li>TBT:从 <strong>300ms</strong> 提升到最快—> <strong>120ms,提升约60%</strong></li></ul><p>总的来说通过上述一系列操作后,各方面指标还是有提升的。虽然都是一些基础的优化操作,可能你也听过,也见过,但关键的是你得在项目中运用起来。往往普通简单的东西在细节操作中稍加注意,才会在大的项目或事情中体现出细节的至关重要的作用!</p><p>本次优化之旅就先到这里,我相信肯定还有优化的空间和方向、欢迎大家评论区指点、讨论,一起学习、进步。</p><p><strong>如果文章对你有帮助,可以点赞、评论、收藏、转发互动支持哈</strong>😀😀😀<br>点击链接 <a href="https://juejin.cn/post/7146908831438602254" title="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群)</a> 加vx拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧😎😎😎</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> vue2性能优化 </category>
</categories>
<tags>
<tag> vue2 </tag>
<tag> vue2项目性能优化 </tag>
</tags>
</entry>
<entry>
<title>vue2项目dist瘦身——打包体积压缩73%、速度提升90%</title>
<link href="/posts/40eb.html"/>
<url>/posts/40eb.html</url>
<content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>随着前端技术的不断发展,网页应用程序变得越来越复杂,并且需要更多的资源来加载和运行。在使用 Vue2 构建的项目中,打包后的文件大小可能会非常大。</p><p>我的一个可视化系统项目,文件约<strong>1302个</strong>、有效代码行数约 <strong>257217行</strong>、项目整体资源算是比较多。</p><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/325f88c31be84bd0a29dd757ba2c44d5~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>主要技术栈:vue-cli3、vue2、vuex、axios、webpack4、echarts、less等</p><p>这么多内容就会导致在打包时出现 <strong>构建速度慢</strong>、构建<strong>产物体积庞大</strong>的问题</p><p>遇到紧急情况需要最快速度发版时,项目打包时间高达4-5分钟,同时如果使用ftp工具上传源码时,由于打包产物体积过大,也会影响上传速度! </p><p>打包速度慢、体积庞大成了项目的痛点。<br>本文介绍了一些针对 Vue2 项目的打包瘦身策略,在瘦身的这个过程中我也在网上学习了很多资料,谨以此篇记录我的一次项目优化学习、实践的过程。</p><p><strong>如果文章对你有帮助,可以点赞、评论、收藏、转发互动支持哈</strong>😀😀😀<br>点击链接 <a href="https://juejin.cn/post/7146908831438602254" title="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群)</a> 加vx拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧😎😎😎</p><h2 id="打包体积优化"><a href="#打包体积优化" class="headerlink" title="打包体积优化"></a>打包体积优化</h2><p><strong>优化前:dist包大小为207.8mb,相当大!</strong></p><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cd357cdc15264e53a2834136b233261c~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h3 id="字体文件大小优化"><a href="#字体文件大小优化" class="headerlink" title="字体文件大小优化"></a>字体文件大小优化</h3><p>常见字体格式<br><strong>不推荐:</strong> </p><ul><li>eot:IE系列专属字体方案</li><li>ttf:兼容性好,但是字体文件较大</li><li>svg:不是真的字体,存在很多兼容问题(IE古老浏览器)</li></ul><p><strong>推荐:</strong></p><ul><li>woff:W3C标准,兼容性好</li><li>woff2:W3C标准,但是不兼容IE</li></ul><blockquote><p>关于字体大小优化,网上看到的方案大部分都是使用字蛛、Fontmin、或者放cdn处理。<br>我没有尝试,我这里直接使用了在线转换工具先将大文件转换为woff格式(以后直接找ui给我们woff格式的字体文件,会小很多)<br><a href="https://convertio.co/zh/">Convertio — 文件转换器</a></p></blockquote><p>如果大家有什么更优雅处理字体文件过大的方案欢迎评论区讨论!</p><p>初始字体大小 29.5mb:<br><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/24bfb86b880c4939859e1b99381f3335~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>转换三个比较大的字体为woff格式后18.1mb:<br><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/231d4d349be94b7d8496c9e60d1734cd~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h3 id="图片优化"><a href="#图片优化" class="headerlink" title="图片优化"></a>图片优化</h3><p>由于项目中图片用的比较多、打包后图片文件很大导致dist包体积很大,这时候想通过webpack插件去处理图片资源、从而瘦身dist包体积。</p><ul><li><p>url-loader </p><blockquote><p>这里踩过坑,详情请移步:<a href="https://juejin.cn/post/7209934991043412023">url-loader图片不显示、不报错踩坑 - 掘金 (juejin.cn)</a></p><p>用url-loader转换图片为base64(图片打包成字符串,放到js中),减少文件请求次数。</p></blockquote><p><strong>问题:</strong><br>这种方式仅适合于比较小的图片资源,如果一个图片文件很大这样又会导致构建出的 <code>.js</code> 文件变大,导致加载缓慢。所以需要配合 <code>image-webpack-loader</code> 使用</p></li><li><p>image-webpack-loader </p><blockquote><p>使用url-loader的 <code>limit</code> 字段控制指定大小图片才转base64(我这里也使用url-loader处理了字体文件)<br>然后使用 <code>image-webpack-loader</code> 来压缩超过limit阈值的大图片。这样就是小图片转base64、大图片压缩完还打包到指定路径中。</p></blockquote><p><code>yarn add -D url-loader image-webpack-loader</code></p><p>ps:<code>image-webpack-loader</code>下载失败可以尝试用cnpm</p><pre class="line-numbers language-js"><code class="language-js"> configureWebpack<span class="token punctuation">:</span> <span class="token punctuation">{</span> module<span class="token punctuation">:</span> <span class="token punctuation">{</span> rules<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> test<span class="token punctuation">:</span> <span class="token regex">/\.(png|jpe?g|gif|webp)(\?.*)?$/i</span><span class="token punctuation">,</span> exclude<span class="token punctuation">:</span> <span class="token regex">/node_modules/</span><span class="token punctuation">,</span> include<span class="token punctuation">:</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'src'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> use<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'url-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{</span> esModule<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 不转换esm规范</span> name<span class="token punctuation">:</span> <span class="token string">'img/[name].[hash:2].[ext]'</span><span class="token punctuation">,</span> limit<span class="token punctuation">:</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">12</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'image-webpack-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{</span> mozjpeg<span class="token punctuation">:</span> <span class="token punctuation">{</span> progressive<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> quality<span class="token punctuation">:</span> <span class="token number">50</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 压缩JPEG图像</span> optipng<span class="token punctuation">:</span> <span class="token punctuation">{</span> enabled<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 压缩PNG图像</span> pngquant<span class="token punctuation">:</span> <span class="token punctuation">{</span> quality<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.65</span><span class="token punctuation">]</span><span class="token punctuation">,</span> speed<span class="token punctuation">:</span> <span class="token number">4</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 压缩PNG图像</span> <span class="token comment" spellcheck="true">// gifsicle: { interlaced: false }, // 压缩GIF图像</span> <span class="token comment" spellcheck="true">// webp: { quality: 75 } // 压缩webp</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>字体+图片处理后此时的dist包体积:<strong>80.5mb</strong>, <strong>dist包体积压缩提升60%</strong></p><p> <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ebd8f0839bc94a9aa80b111a97168f03~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"><br> 此时打包速度为:289s</p><p> <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d45176b447aa45c59343e7c890c94b0a~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p></li></ul><h3 id="前端开启Gzip压缩"><a href="#前端开启Gzip压缩" class="headerlink" title="前端开启Gzip压缩"></a>前端开启Gzip压缩</h3><ul><li><p>compression-webpack-plugin (Gzip压缩)</p><blockquote><p>nginx可以启动静态和动态压缩,如果能在Vue打包过程就压缩好,就可以<strong>缓解一些服务器CPU的压力</strong>。该插件可以打包文件压缩为.gz格式(最终发布生产环境时需要nginx配置开启gzip才能生效)</p></blockquote><p>ps: 插件版本需要和webpack匹配对应<br><code>yarn add -D compression-webpack-plugin</code> </p><pre class="line-numbers language-js"><code class="language-js"> configureWebpack<span class="token punctuation">:</span> <span class="token punctuation">{</span> plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token comment" spellcheck="true">// gizp压缩</span> <span class="token keyword">new</span> <span class="token class-name">CompressionWebpackPlugin</span><span class="token punctuation">(</span><span class="token punctuation">{</span> test<span class="token punctuation">:</span> <span class="token regex">/\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i</span><span class="token punctuation">,</span> threshold<span class="token punctuation">:</span> <span class="token number">10240</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 对10K以上的数据进行压缩</span> deleteOriginalAssets<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>gzip压缩后此时dist包:<strong>56.8mb</strong>,观察发现js等其他文件夹对应文件也压缩了不少(且生成了.gz文件) </p><p><strong>此时相比首次dist包体积207.8mb,我们做到了压缩提升73%</strong><br> <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1ff07e16867c42e8b0a47e5b5274ae55~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"><br> 此时打包速度:302s<br> <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8aecbcfcd47940d0b38647949a4f3ab1~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p></li></ul><h3 id="nginx配置开启gzip"><a href="#nginx配置开启gzip" class="headerlink" title="nginx配置开启gzip"></a>nginx配置开启gzip</h3><p>前端项目配置了gzip压缩、且删除原文件后部署访问404<br><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a56a42fbee86410298b56a91f2261197~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"><br>这时候就需要nginx 配置开启gzip了</p><ul><li><p>nginx配置:</p><pre class="line-numbers language-bash"><code class="language-bash"> <span class="token comment" spellcheck="true">#开启gzip功能</span> <span class="token function">gzip</span> on<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">#开启gzip静态压缩功能</span> gzip_static on<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">#gzip缓存大小</span> gzip_buffers 4 16k<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">#gzip http版本</span> gzip_http_version 1.1<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">#gzip 压缩级别 1-10 r</span> gzip_comp_level 5<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">#gzip 压缩类型</span> gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">#配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持</span> gzip_disable <span class="token string">"MSIE [1-6]\."</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>gzip_static的作用</p><blockquote><p>nginx在设置了gzip on 后就已经打开了gzip压缩功能,不过这时候nginx所使用的是<strong>动态压缩</strong>。在动态压缩的情况下nginx会自动的将文件压缩成.gz文件,这时候就算不配置vue也能达到一样的效果。<br>但是动态压缩无疑会占用服务器的资源来进行此操作。 </p></blockquote><blockquote><p>nginx也提供了<strong>静态压缩模式</strong>,也就是<strong>gzip_static</strong>,在这个模式下nginx会去寻找对应文件的.gz文件,只有.gz文件不存在的时候才会去压缩对应文件,这样就不会过度占用服务器资源。</p></blockquote><p>最后访问部署地址后查看http请求看到<strong>content-Encodeing: gzip</strong> 就代表gzip已经成功开启了</p><p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aae3a1f734504eaf9f2859e9c6b833e8~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p></li></ul><h2 id="打包速度优化"><a href="#打包速度优化" class="headerlink" title="打包速度优化"></a>打包速度优化</h2><p>处理完打包体积后,来看看此时的打包速度:<br>255s还是比较慢的,现在这个配置我这台机器打包时间基本上都在250-300s<br><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/63efc80de9a5421cbf6262d209ece77d~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h3 id="合理使用缓存cache-loader"><a href="#合理使用缓存cache-loader" class="headerlink" title="合理使用缓存cache-loader"></a>合理使用缓存cache-loader</h3><blockquote><p>Webpack4 中还可以使用 cache-loader 实现与 Webpack5 相似的通用<strong>持久化缓存</strong>功能。<strong>仅需要在一些性能开销较大的 loader 之前添加此 loader</strong><br>cache-loader 缓存的是对应loader的处理结果,将结果缓存到磁盘里,显著提升二次构建速度。</p></blockquote><p> 安装:<code>yarn add -D cache-loader</code><br> 这里我在处理图片的<code>image-webpack-loader</code>前使用。 </p><p> 刚开始在<code>url-loader</code>前使用时发现二次打包后部分<strong>图片会丢失</strong>,部署后部分图片404(<strong>尚未解决!</strong>)如果有大佬遇到过希望评论区指点!</p><pre class="line-numbers language-js"><code class="language-js"> configureWebpack<span class="token punctuation">:</span> <span class="token punctuation">{</span> module<span class="token punctuation">:</span> <span class="token punctuation">{</span> rules<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> test<span class="token punctuation">:</span> <span class="token regex">/\.(png|jpe?g|gif)(\?.*)?$/</span><span class="token punctuation">,</span> use<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'url-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">'img/[name].[hash:6].[ext]'</span><span class="token punctuation">,</span> limit<span class="token punctuation">:</span> <span class="token number">10</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'cache-loader'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'image-webpack-loader'</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这时第一次打包速度来到了23s,相比上面的的250s <strong>打包速度提升了约90%</strong><br><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/527516997f284a24ba753445257b442f~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>再次打包速度:19s<br><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/31b6082d873f47a6bf37c2c174ee01d9~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>再次打包速度:23s<br><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cdf1dcb7bfff4894ae3f996455157e0f~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>使用缓存后基本上打包速度都在20s左右,终于可以和漫长的打包时间说拜拜啦!</p><h2 id="关于启动速度"><a href="#关于启动速度" class="headerlink" title="关于启动速度"></a>关于启动速度</h2><p>开发环境不配置任何loader、plugins启动时间:<br>14s<br><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/61a80c12fb314b32a8a52ae2a68ffa55~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"><br>13s<br><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/605d8b89395f4ccaae2f486c8682e57f~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>配置后:45s<br><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c6fae6771add4740aeed46db07e0ecd6~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>这里我使用了npm 和 yarn 分别多次启动测试发现时间都不一样。拿我的win(运行内存16g、磁盘1.5g)跑的话有时候竟然高达6位数,烦躁的很!可能电脑配置不行吧,每次起这个项目风扇就起飞了、有时候还会出现卡顿😂 条件允许还是上mac吧,真挺丝滑的。</p><p>经过多次测试,我发现开发环境如果也配置一些loader、plugins 后会<strong>增加启动时间</strong>,得不偿失。 没有上vite是因为项目内容太多了,改造成本太高。新项目的话还是建议直接vite吧,不得不说还是vite开发丝滑呀! </p><blockquote><p>所以我这里开发环境直接不配置任何loader、plugins。然后区分开发环境,加载不同配置文件。</p></blockquote><p> 因为项目默认用的是vue-cli-service服务,当执行<code>npm run build</code> 和 <code>npm run dev</code>时可以在config文件中通过<code>process.env.NODE_ENV</code>获取到当前环境</p><pre><code>先在根目录创建config目录,再分别创建webpack.prod、webpack.dev配置文件,分别配置后通过module.exports暴露出来。最后根目录`vue.config.js`文件根据不同环境引入:```jsconsole.log('当前环境:', process.env.NODE_ENV)const config = process.env.NODE_ENV === 'production' ? require('./config/webpack.prod') : require('./config/webpack.dev')module.exports = { ...config}```</code></pre><p> vue2项目随着版本的迭代,资源越来越多,启动时速度就越来越慢,如果业界大佬有什么好的解决方案能够解决vue2+webpack4老项目启动速度问题,欢迎评论区指点!</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>经过上述一系列操作配置后最终结果如下:</p><ul><li><strong>打包体积由开始的207.8MB -> 优化到56.8MB,提升约 73%</strong></li><li><strong>打包速度由250s -> 优化到约20s,提升约 90%</strong></li></ul><p>本次瘦身之旅,只尝试了这部分内容,总体来说还是有效果的。很多知识仅仅停留在熟悉、了解还不够,最终还是要亲自去实践才能真正学习和掌握。 </p><p>我相信肯定还有很多优化方案、方向,学无止境,欢迎大家评论区讨论交流。</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> vue2打包 </category>
</categories>
<tags>
<tag> vue2 </tag>
<tag> vue项目打包 </tag>
</tags>
</entry>
<entry>
<title>pnpm报错:/gifsicle postinstall$ node lib/install.js</title>
<link href="/posts/f812e.html"/>
<url>/posts/f812e.html</url>
<content type="html"><![CDATA[<h2 id="遇到问题"><a href="#遇到问题" class="headerlink" title="遇到问题"></a>遇到问题</h2><p>最近在使用 pnpm 安装依赖时遇到了报错,死活都下载不下来。 <code>pnpm add xxx</code> 或者 <code>pnpm i</code></p><p>都报错如下:<br><code>.../node_modules/gifsicle postinstall$ node lib/install.js</code></p><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3ce5ef150606400d9337471649aafb0e~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>删除node-modules包、重新 <code>install</code>;<code>cnpm i</code> 也是不行!</p><p>查资料学习后发现问题原因,得以解决,谨以此篇记录自己工作中的踩坑之路。</p><p><strong>如果文章对你有帮助,可以点击链接关注我的<a href="https://juejin.cn/user/2041110775208184/posts">掘金社区账号</a> 更多技术分享请移步我的掘金哦~</strong> 😀😀😀</p><p>点击链接 <a href="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群) - 掘金 (juejin.cn)</a> 加vx拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧😎😎😎</p><h2 id="报错原因"><a href="#报错原因" class="headerlink" title="报错原因"></a>报错原因</h2><p>安装某个包时,内部需要这个依赖包,其中部分依赖包需要从GitHub上下载,而GitHub的资源库DNS有问题,导致这些依赖包无法安装而报错!</p><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><ul><li><p>命令后加参数 <code>--ignore-scripts</code> 忽略scripts相关依赖</p><p><code>pnpm i --ignore-scripts</code></p><p>成功解决:<br><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6eaf7dde33be44e7b3e4c5e4cf0268a1~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p></li><li><p>修改host文件<br>在本地host文件中添加以下内容:<br>(windows下,host文件路径:C:\Windows\System32\drivers\etc )</p><pre class="line-numbers language-bash"><code class="language-bash"> 52.74.223.119 github.com 192.30.253.119 gist.github.com 54.169.195.247 api.github.com 185.199.111.153 assets-cdn.github.com 151.101.76.133 raw.githubusercontent.com 151.101.76.133 gist.githubusercontent.com 151.101.76.133 cloud.githubusercontent.com 151.101.76.133 camo.githubusercontent.com 151.101.76.133 avatars0.githubusercontent.com 151.101.76.133 avatars1.githubusercontent.com 151.101.76.133 avatars2.githubusercontent.com 151.101.76.133 avatars3.githubusercontent.com 151.101.76.133 avatars4.githubusercontent.com 151.101.76.133 avatars5.githubusercontent.com 151.101.76.133 avatars6.githubusercontent.com 151.101.76.133 avatars7.githubusercontent.com 151.101.76.133 avatars8.githubusercontent.com<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>重新 <code>pnpm i</code> 就可以了</p></li></ul><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<tags>
<tag> webpack </tag>
<tag> npm </tag>
</tags>
</entry>
<entry>
<title>url-loader图片不显示-踩坑</title>
<link href="/posts/f82e.html"/>
<url>/posts/f82e.html</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>一次在vue-cli3、vue2、webpack4项目中使用url-loader时遇到了图片不显示、不报错问题。查了一些网上资料,也问了一些同行。一路踩坑,真的要裂开了。</p><p>项目依赖版本:<br><code>vue:2.6.12</code><br><code>webpack:4.46.0</code><br><code>url-loader:4.1.4</code></p><p><strong>如果文章对你有帮助,可以点击链接关注我的<a href="https://juejin.cn/user/2041110775208184/posts">掘金社区账号</a> 更多技术分享请移步我的掘金哦~</strong> 😀😀😀</p><p>点击链接 <a href="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群) - 掘金 (juejin.cn)</a> 加vx拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧😎😎😎</p><h2 id="安装使用"><a href="#安装使用" class="headerlink" title="安装使用"></a>安装使用</h2><p><code>npm i -D url-loader</code></p><p>vue.config.js配置:</p><pre class="line-numbers language-js"><code class="language-js"> configureWebpack<span class="token punctuation">:</span> <span class="token punctuation">{</span> module<span class="token punctuation">:</span> <span class="token punctuation">{</span> rules<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> test<span class="token punctuation">:</span> <span class="token regex">/\.(png|jpe?g|gif|svg|ttf|woff2|woff)(\?.*)?$/</span><span class="token punctuation">,</span> use<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'url-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">'img/[name].[hash:6].[ext]'</span><span class="token punctuation">,</span> limit<span class="token punctuation">:</span> <span class="token number">10</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token comment" spellcheck="true">// 小于这个值的图片进行 base64 编码,大于等于的图片则进行单独的打包</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>配置完 <code>build</code> 打包后也没有问题,图片也进行处理了,当部署后发现图片不显示,且http请求显示200,也不报错!</p><h2 id="图片不显示不报错(就显示一个小方块!)"><a href="#图片不显示不报错(就显示一个小方块!)" class="headerlink" title="图片不显示不报错(就显示一个小方块!)"></a>图片不显示不报错(就显示一个小方块!)</h2><blockquote><p>先开始以为是路径问题(可是没报错也没404啊!)仔细排查发现打包后的目录下确实也有对应未转换base64的图片,直接浏览器输入地址也是不显示!</p></blockquote><p>打包为base64的图片资源不显示<br><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a78e153deff144b4a13a96090e567e13~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>直接粘贴base64字符串到浏览器访问<strong>直接显示的是一个小方块</strong><br><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d7f3a231705e4623a2ef8d0c37e8b89a~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>作为背景图的图片也不显示<br><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c97f75bdd82341b080354e5c8edfe480~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>js、图片资源显示200加载成功<br><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/50438940a68449b99825eae48d0dbd2f~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"><br><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a1465a33a9642b384a3f35b27f3012e~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>但是点开png资源请求,发现是这样的<br><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1edbfd32a9b34c849609729f31851981~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h2 id="开始踩坑"><a href="#开始踩坑" class="headerlink" title="开始踩坑"></a>开始踩坑</h2><ul><li><p>url-loader版本问题</p><blockquote><p>有网友说可能是版本问题,我分别降级不同版本测试后都没有解决!</p></blockquote></li><li><p>网上一些关于url-loader的配置</p><pre class="line-numbers language-js"><code class="language-js"><span class="token punctuation">{</span> test<span class="token punctuation">:</span> <span class="token regex">/\.(png|jpe?g|gif|svg)$/i</span><span class="token punctuation">,</span> exclude<span class="token punctuation">:</span> <span class="token regex">/node_modules/</span><span class="token punctuation">,</span> type<span class="token punctuation">:</span> <span class="token string">'javascript/auto'</span><span class="token punctuation">,</span> use<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'url-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{</span> esModule<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'img/[name].[hash:3].[ext]'</span><span class="token punctuation">,</span> limit<span class="token punctuation">:</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">,</span> context<span class="token punctuation">:</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'./src'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> publicPath<span class="token punctuation">:</span> <span class="token string">'./'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>网上大部分说通过一些配置可解决,不过大部分针对的是 webpack5(待验证)</p></blockquote><p>我也依次尝试配置如下:</p><p><code>type: 'javascript/auto'``publicPath: './'``context: path.resolve(__dirname, './src')</code></p><p>测试后发现加上这些配置也没有解决问题。</p></li><li><p>file-loader</p><blockquote><p>有的说 url-loader 封装了 file-loader。使用url-loader时需要安装file-loader但不需要配置。我经过测试发现不安装也是可以的</p></blockquote></li><li><p>html-loader</p><blockquote><p>有人说是需要安装配置 html-loader,这样html文件的图片才能加载出来</p></blockquote><p>安装依赖、增加loader:</p><pre class="line-numbers language-js"><code class="language-js"> <span class="token punctuation">{</span> test<span class="token punctuation">:</span> <span class="token regex">/.html$/</span><span class="token punctuation">,</span> use<span class="token punctuation">:</span> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'html-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{</span> esModule<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>用了1.x以上版本打包都会报错,1.x以下版本不报错也没解决。</p></li><li><p>html-withimg-loader</p><blockquote><p>流程同上,也未解决。</p></blockquote></li></ul><h2 id="开始解决"><a href="#开始解决" class="headerlink" title="开始解决"></a>开始解决</h2><blockquote><p>我刚开始所有配置都是直接在vue.config.js 下的<strong>configureWebpack</strong>字段中配置的;后来发现是好像没生效!!!查资料学习后发现这里配置好的内容最终会被merge到脚手架的默认配置中<br>vue-cli脚手架默认的webpack配置中也配置了url-loader的!我裂开了。</p><p>需要从<strong>chainWebpack</strong>中清除默认配置、或者获取指定loader后<strong>覆盖才能生效!!!</strong></p></blockquote><p>所以我这里是在<strong>chainWebpack</strong>中获取到默认处理images的loader,然后清空默认配置,然后在 <code>configureWebpack-module-rules</code>中配置新的url-loader规则</p><ul><li><p>清除默认配置</p><pre class="line-numbers language-js"><code class="language-js">chainWebpack<span class="token punctuation">:</span> config <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> imgAllLoader <span class="token operator">=</span> config<span class="token punctuation">.</span>module<span class="token punctuation">.</span><span class="token function">rule</span><span class="token punctuation">(</span><span class="token string">'images'</span><span class="token punctuation">)</span> imgAllLoader<span class="token punctuation">.</span>uses<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>url-loader配置具体参数以loader官网为准,其余网上查到的参数都是不生效的<br>常用配置:</p><pre class="line-numbers language-js"><code class="language-js"><span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'url-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{</span> esModule<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 不转换esm规范</span> name<span class="token punctuation">:</span> <span class="token string">'img/[name].[hash:3].[ext]'</span><span class="token punctuation">,</span> limit<span class="token punctuation">:</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">,</span> fallback<span class="token punctuation">:</span> <span class="token string">'file-loader'</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 大于limit时,会使用file-loader也可以指定loader处理,默认值就是file-loader</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><p>配置完打包后大部分图片已经出来了,小部分图片又出现如下问题:</p><ul><li><p>img的src出现[object Module]问题解决</p><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/70dd4127c42d4d578ab969127afd02fc~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><code>url-loader</code>的 <code>esModule</code> 默认为 true,使用的是es6(esm)规范如:<code>import xxx from 'xxx.png'</code></p><p>而我们在vue2,data中引入图片使用的是 <code>commonjs</code> 规范如: require(‘xxx’)</p><p>所以添加: <code>esModule: false,</code> 选项解决</p><pre class="line-numbers language-js"><code class="language-js"> <span class="token punctuation">{</span> loader<span class="token punctuation">:</span> <span class="token string">'url-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{</span> esModule<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 不转为 esModule</span> limit<span class="token punctuation">:</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">'img/[name].[hash:3].[ext]'</span><span class="token punctuation">,</span> fallback<span class="token punctuation">:</span> <span class="token string">'file-loader'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>svg图片报错</p><p><code>error on line 1 at column 1: Document is empty</code></p><p>直接访问图片报错:<br><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6ca7b7fbd37440d1b6217f8516e1b419~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"><br>查资料看到这篇文章(待验证) <a href="https://www.cnblogs.com/tv151579/p/3665273.html">SVG报错error on line 39 at column 26: Namespace prefix xlink for href on script is not defined - horizon<del>~</del> - 博客园 (cnblogs.com)</a></p><p>也有文章说不建议svg格式转为base64,反而会更大。<br>我的项目中svg格式图片用的也不多,然后就直接在url-loader配置中test中去除了 svg。大家有好的解决方案欢迎评论区指点!</p></li></ul><p>到这一步我们部署后图片都加载显示出来了,终于不报错了。<br><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bf6ae3071b024802878eefcf288e9ee0~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>首先还是自己掌握的知识不够,对webpack配置不熟、不深入。一天一个坑,不过没关系,踩过就学到了,学到就是赚到。毕竟成长的道路永远不会一帆风顺的!加油!</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> url-loader </category>
</categories>
<tags>
<tag> webpack </tag>
<tag> url-loader </tag>
</tags>
</entry>
<entry>
<title>Docker初识</title>
<link href="/posts/9627.html"/>
<url>/posts/9627.html</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>进几年docker在前端领域中也有着越来越广泛的应用,本文主要介绍docker基础指令以及如何在win10、linux上安装docker服务;其中也在网上借鉴了不少资料,通过自己一步步实践最终成功,谨以此篇记录自己学习的爬坑之路。</p><p><strong>如果文章对你有帮助,可以点击链接关注我的<a href="https://juejin.cn/user/2041110775208184/posts">掘金社区账号</a> 更多技术分享请移步我的掘金哦~</strong> 😀😀😀</p><p>点击链接 <a href="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群) - 掘金 (juejin.cn)</a> 加vx拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧😎😎😎</p><h2 id="docker-是什么?"><a href="#docker-是什么?" class="headerlink" title="docker 是什么?"></a>docker 是什么?</h2><p>docker是一个用Go语言实现的开源项目,可以让我们方便的创建和使用容器,docker将程序以及程序所有的依赖都打包到docker container,这样你的程序可以在任何环境都会有一致的表现,这里程序运行的依赖也就是容器就好比集装箱;容器所处的操作系统环境就好比货船或港口,程序的表现只和集装箱有关系(容器),和集装箱放在哪个货船或者哪个港口(操作系统)没有关系。</p><p>因此我们可以看到docker可以屏蔽环境差异,也就是说,只要你的程序打包到了docker中,那么无论运行在什么环境下程序的行为都是一致的,不会再有“在我的环境上可以运行的啊!!!”</p><h2 id="docker-优点"><a href="#docker-优点" class="headerlink" title="docker 优点"></a>docker 优点</h2><p>环境隔离(‘隔离,安全’)<br>Docker 实现了资源隔离,一台机器运行多个容器互无影响。</p><p>更高效的资源利用(节约成本)<br>Docker 容器的运行不需要额外的虚拟化管理程序的支持,它是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。</p><p>更快速的交付部署(敏捷)<br>使用 Docker,开发人员可以利用镜像快速构建一套标准的研发环境,开发完成后,测试和运维人员可以直接通过使用相同的环境来部署代码。</p><p>更易迁移扩展(可移植性)<br>Docker 容器几乎可以在任意的平台上运行,包括虚拟机、公有云、私有云、个人电脑、服务器等,这种兼容性让用户可以在不同平台之间轻松的迁移应用。</p><p>更简单的更新管理(高效)<br>使用 Dockerfile,只需要很少的配置修改,就可以替代以往大量的更新工作。并且所有修改都是以增量的方式进行分发和更新,从而实现自动化和高效的容器管理。</p><h2 id="docker基础指令"><a href="#docker基础指令" class="headerlink" title="docker基础指令"></a>docker基础指令</h2><p>docker version 查看docker版本<br>docker info 查看docker详细信息<br>sudo service docker start 启动服务<br>sudo service docker stop 停止服务<br>sudo service docker restart 重启服务</p><ul><li>docker镜像命令<br>docker images 查看docker镜像<br>docker images -a列出本地所有的镜像<br>docker images -p只显示镜像ID docker rmi imageid 删除镜像<br>docker build -t xxx . 打包镜像</li><li>docker镜像导入导出<br>如果网络不好或者pull不下来镜像,只能在其它网络比较好的机器上pull下来镜像,导出成一个文件,再下载上传到网络不好的机器上,然后再从文件中导出来,这样在网络不好的机器上也能使用docker镜像了 有两种方式,但是不可混用。</li></ul><p>save/load (推荐)</p><ul><li>docker save 根据 ID 将镜像打包<br>docker save 0fdf2b4c26d3 > hangge_server.tar</li><li>同时打包多个image,如将镜像 postgres 和 mongo<br>docker save -o images.tar postgres:9.6 mongo:3.4</li><li>导入<br>docker load < images.tar</li></ul><p>复制代码<br>import/export</p><p>根据指定镜像id导出成一个文件<br>docker export eb516548c180 > coredns.tar</p><ul><li>导入<br>docker import /usr/local/coredns.tar<br>复制代码<br>两种方式应用场景及区别</li></ul><p>docker save 的应用场景:</p><blockquote><p>如果我们的应用是使用 docker-compose.yml 编排的多个镜像组合,但我们要部署的客户服务器并不能连外网。这时就可以使用 docker save 将用到的镜像打个包,然后拷贝到客户服务器上使用 docker load 载入。</p></blockquote><p>docker export 的应用场景:</p><blockquote><p>主要用来制作基础镜像,比如我们从一个 ubuntu 镜像启动一个容器,然后安装一些软件和进行一些设置后,使用 docker export 保存为一个基础镜像。然后,把这个镜像分发给其他人使用,比如作为基础的开发环境。</p></blockquote><ul><li>镜像是否重命名<br>docker import 可以为镜像指定新名称<br>docker load 不能对载入的镜像重命名</li><li>文件大小<br>export 导出的镜像文件体积小于 save 保存的镜像</li><li>是否包含镜像历史<br>export 导出(import 导入)是根据容器拿到的镜像,再导入时会丢失镜像所有的历史记录和元数据信息(即仅保存容器当时的快照状态),所以无法进行回滚操作。</li><li>save 保存(load 加载)的镜像,没有丢失镜像的历史,可以回滚到之前的层(layer)。</li></ul><h2 id="docker容器命令"><a href="#docker容器命令" class="headerlink" title="docker容器命令"></a>docker容器命令</h2><p>每一个容器其实就是一个linux系统可以执行linux命令。</p><p>使用镜像启动容器<br>新建并且启动一个容器: docker run -itd -p 5000:3000 test1:v1.0<br>OPTIONS说明:</p><p>-i: 交互式操作<br>-t: 终端<br>-d: 后台运行<br>–name:指定容器的名称<br>-p: 表示指定端口映射,(5000:3000)表示(本机端口:容器端口)<br>镜像名后面的:v1.0:表示打的tag号<br>-v: 文件映射,将主机本地的文件映射到容器中,这样我们本地修改文件内容,可以动态看到页面的变化了;windwos下需指定文件的绝对路径<br>查看容器<br>docker ps 列出当前所有正在运行的容器<br>docker ps -a列出所有的容器<br>docker logs 容器id 查看容器日志 docker ps -l列出最近创建的容器</p><p>启动退出停止容器<br>000参数:容器ID或容器名称<br>exit 退出并停止容器<br>Ctrl+p+q 只退出容器,不停止容器<br>docker start 000 启动容器<br>docker restart 000 重新启动容器<br>docker stop 000 停止容器<br>docker kill 000 强制停止容器</p><p>删除容器<br>docker rm 000删除容器<br>docker rm -f 000强制删除容器<br>docker rm -f $(docker ps -a -q)删除多个容器</p><p>docker容器文件拷贝到宿主机<br>docker cp 容器ID:容器内的文件路径 宿主机路径 从容器内拷贝文件到宿主机<br>如:docker cp f9e29e8455a5:/tmp/yum.log /root</p><p>宿主机文件拷贝到docker容器<br>docker cp 你的文件路径 容器ID:docker容器中路径<br>如(注意.tar后面的.gz):<br>docker cp D:\NDM下载\Compressed\nvm-0.39.2.tar.gz f9e29e8455a5:/home</p><p>cmd进入某个容器<br>docker exec -it 容器id /bin/bash</p><h2 id="win10-安装使用docker"><a href="#win10-安装使用docker" class="headerlink" title="win10 安装使用docker"></a>win10 安装使用docker</h2><p>windows系统直接在 官网 下载 docker desktop 客户端 安装使用。</p><p>win10家庭版安装最新版本docker,已经不再需要hyper-v虚拟机,也不用修改windows版本注册表,最新版windows docker采用了wsl容器(适用于 Linux 的 Windows 子系统)</p><p>安装完成后打开终端验证是否安装成功<br>docker -v</p><p>现在就可以打开上面安装好的docker客户端基于图形工具使用docker了,也可以在cmd终端操作docker</p><h2 id="win10-安装子系统linux"><a href="#win10-安装子系统linux" class="headerlink" title="win10 安装子系统linux"></a>win10 安装子系统linux</h2><p>因为想在linux上操作docker,但是用的是win10本,所以需要先想办法安装一个liunx(我这里安装的是ubuntu 20.04LTS)系统;<br>参考这篇文章完成安装 <a href="https://blog.csdn.net/xiaofeivip_top/article/details/98665312">Windows10下开启第二个系统:Linux!</a></p><h2 id="linux-安装使用docker"><a href="#linux-安装使用docker" class="headerlink" title="linux 安装使用docker"></a>linux 安装使用docker</h2><p>通过上面的操作我们现在可以在win10上使用linux系统了,现在需要在linux上安装 linux版的docker 打开cmd输入bash进入linux 终端,或者直接在菜单就有Ubuntu的程序,点击进入。</p><p>linux安装docker服务<br>ps:注意如下命令都需要加 sudo</p><p>查看当前linux系统是否有安装docker<br><code>sudo systemctl start docker</code></p><p> 出现 <code>System has not been booted with systemd as init system (PID 1). Can't operate. Failed to connect to bus: Host is down</code> 说明没有安装</p><p>更新源<br>sudo apt-get update</p><p>安装以下软件包 允许apt通过HTTPS使用存储库<br><code>sudo apt-get install apt-transport-https ca-certificates curl software-properties-common</code></p><p>添加Docker官方的GPG密钥</p><p>curl -fsSL <a href="https://download.docker.com/linux/ubuntu/gpg">https://download.docker.com/linux/ubuntu/gpg</a> | sudo apt-key add -</p><p>安装stable存储库<br><code>sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"</code></p><p>ps:这里需要注意网络不佳的情况会失败,多尝试几次</p><p>查看docker-ce的版本<br><code>apt-cache madison docker-ce</code></p><p>安装docker社区版 <code>sudo apt-get install docker-ce</code></p><p>查看版本<br><code>docker -v</code></p><p>启动docker<br>启动docker服务<br><code>sudo service docker start</code></p><p>查看镜像<br><code>docker images</code></p><p>至此我们完成了:<br>在windows上安装客户端docker<br>在windows上安装子系统linux -> 子系统安装docker</p><p>注意区分<br>此时我们电脑上有两个版本docker,如图所示cmd查看镜像时是基于客户端的docker,所以必须先双击启动docker程序才可操作。<br>而cmd通过bash进入子系统linux系统后操作的docker是属于子系统的</p><h2 id="遇到问题"><a href="#遇到问题" class="headerlink" title="遇到问题"></a>遇到问题</h2><p>win10的linux子系统启动docker失败<br>打开ubuntu 启动docker服务后,docker ps 报错如下:<br><code>“Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?”</code></p><p>解决:<br>先确定Docker本身已经安装, docker -v</p><ul><li>查看 docker daemon 是否在运行:ps aux | grep docker</li><li>再次查看<br><code>ps aux | grep docker</code><br>复制代码<br>先关闭docker服务<br><code>service docker stop</code></li></ul><p>再重新启动docker<br><code>service docker start</code></p><p><code>docker ps</code> 查看时发现此时正常</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> docker </category>
</categories>
<tags>
<tag> docker </tag>
</tags>
</entry>
<entry>
<title>解决image-webpack-loader打包报错</title>
<link href="/posts/f182e.html"/>
<url>/posts/f182e.html</url>
<content type="html"><![CDATA[<h2 id="报错问题"><a href="#报错问题" class="headerlink" title="报错问题"></a>报错问题</h2><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9e619af741a54c1b831dc3ea14def2f9~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p>vue项目打包时报错了,这里报错是因为使用了 <code>image-webpack-loader</code>打包图片时报错了,因为对应依赖的包没下载下来。</p><h2 id="开始解决"><a href="#开始解决" class="headerlink" title="开始解决"></a>开始解决</h2><ul><li><p>卸载后重新安装 <code>npm uninstall image-webpack-loader``npm install -D image-webpack-loader</code></p><p>重新安装还是报错:</p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dceef3c84ce74423b65869c119f357c1~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p></li><li><p>方法2<br>npm命令加参数 <code>--ignore-scripts</code> 也不好使</p></li></ul><h2 id="最终使用cnpm解决"><a href="#最终使用cnpm解决" class="headerlink" title="最终使用cnpm解决"></a>最终使用cnpm解决</h2><p><code>cnpm install -D image-webpack-loader</code> 多尝试几次后竟然成功了</p><p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/10f4a968d42241e88570cd92536dfaf0~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><p><strong>如果文章对你有帮助,可以点击链接关注我的<a href="https://juejin.cn/user/2041110775208184/posts">掘金社区账号</a> 更多技术分享请移步我的掘金哦~</strong> 😀😀😀</p><p>点击链接 <a href="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群) - 掘金 (juejin.cn)</a> 加vx拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧😎😎😎</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<tags>
<tag> image-webpack-loader </tag>
<tag> webpack </tag>
</tags>
</entry>
<entry>
<title>macOs开发环境配置</title>
<link href="/posts/ba04.html"/>
<url>/posts/ba04.html</url>
<content type="html"><![CDATA[<h2 id="记录个人使用-macOs-时配置开发环境"><a href="#记录个人使用-macOs-时配置开发环境" class="headerlink" title="记录个人使用 macOs 时配置开发环境"></a>记录个人使用 macOs 时配置开发环境</h2><h3 id="mac-环境变量相关"><a href="#mac-环境变量相关" class="headerlink" title="mac 环境变量相关"></a>mac 环境变量相关</h3><p>Mac 系统的环境变量,加载顺序为:<br>系统级别:<br>/etc/profile<br>/etc/paths<br>用户级别:<br>~/.bash_profile<br>~/.bash_login<br>~/.profile ~/.bashrc</p><p>如果没特殊说明,设置 PATH 变量 的语法都为:<br><code>export PATH=<PATH 1>:<PATH 2>:.....:<PATH N>:$PATH</code><br>推荐写法:<br><code>export PATH=${PATH}:/opt/homebrew/opt/mysql@.5.7/bin</code><br>写法 2:<br><code>export PATH="you url:$PATH"</code></p><p>修改配置文件立即生效:<br><code>source ~/.bash_profile</code><br>查看是否生效<br><code>echo $PATH</code></p><p>注意:<br>mac 默认使用的是 bash shell,<br>如果你在 Mac 上使用了 zsh 等其他 shell 工具,需要再做配置,来达到环境变量设置的永久生效。<br>bash 的配置文件是.bashrc, zsh 的配置文件是.zshrc,当你使用 zsh 作为默认的 shell 工具的时候,它启动时并不会加载 bash 的这两个配置文件.bashrc 和.bash_profile,而只会加载自己的配置文件.zshrc;我的终端设置默认为 zsh;</p><p>vim ~/.zshrc</p><h3 id="mac-用户级别的环境变量配置"><a href="#mac-用户级别的环境变量配置" class="headerlink" title="mac 用户级别的环境变量配置"></a>mac 用户级别的环境变量配置</h3><ul><li>.bash_profile 文件<br>~/.bash_profile:用户级,用来设置用户级的环境变量,可以是 PATH,也可以是自定义的环境变量,当用户登录时,会读取该文件,一般只会读取一次,如果不存在可以在~根目录下创建 .bash_profile</li><li>.zshrc 终端<br>我使用了 zsh 作为默认终端,~目录下添加配置文件</li></ul><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">touch</span> .zshrc<span class="token function">open</span> ~/.zshrc or vim ~/.zshrcshift+ : wq保存退出重载文件:<span class="token function">source</span> ~/.zshrc<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="Homebrew"><a href="#Homebrew" class="headerlink" title="Homebrew"></a>Homebrew</h3><ul><li>安装使用</li><li>常用指令<br>brew install xxx<br>brew install –cask xxx<br>brew:主要用来下载一些不带界面的命令行下的工具和第三方库来进行二次开发<br>brew –cask:主要用来下载一些<strong>带界面的应用软件</strong>,已经编译好了的应用包 (.dmg/.pkg),仅仅是下载解压,放在统一的目录中(/opt/homebrew-cask/Caskroom),省掉了自己去下载、解压、拖拽(安装)等步骤,同样,卸载相当容易与干净。这个对一般用户来说会比较方便,包含很多在 AppStore 里没有的常用软件。</li></ul><p>ps: 如果安装 mac 图形界面软件,推荐先在苹果官方商店里搜索下载,没有的话去 brew cask 试试,如果还没有,只能去这个软件的官方网站去下载了。</p><pre class="line-numbers language-bash"><code class="language-bash">brew -vbrew homebrew list 查看已安装的软件brew search xxx 搜索软件包brew uninstall xxx 卸载软件包brew services list 查看服务brew info xxx 查看包的详细信息brew update 自身更新brew outdated 查看那些包油新版本可更新brew upgrade 更新所有包brew upgrade xxx 更新指定包<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="mongodb-安装"><a href="#mongodb-安装" class="headerlink" title="mongodb 安装"></a>mongodb 安装</h3><p>MacBook M1、M2 芯片的默认配置目录如下:<br>/opt/homebrew/etc/mongod.conf<br>我的 mongodb 安装目录:<br>磁盘:/opt/homebrew/cellor/mongodb/5.0.7<br>brew 目录: opt/homebrew<br>brew 安装软件目录:opt/homebrew/cellor</p><ul><li><p>使用 brew 安装<br>MongoDB 不开源了,<code>brew install mongodb</code> 安装命令失效了,目前 brew 只能安装社区版<br>1:<code>brew tap mongodb/brew</code><br>这里直接安装 5.0 版本</p><p>2:<code>brew install mongodb-community@5.0</code></p><p>一般通过 brew 安装的文件都在 <code>/opt/homebrew/Cellar/目录下,我的在/opt/homebrew/Cellar/mongodb-community/5.0.7/bin</code></p><p>3:mongod -version (如果失败需要配置环境变量)<br>4: 打开环境变量配置文件,配置环境变量,或者</p><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">open</span> ~/.bash_profile <span class="token punctuation">(</span>根据自己用的什么 shell 决定,我使用的是zsh<span class="token punctuation">)</span>:<span class="token function">open</span> ~/.zshrc配置环境变量:<span class="token function">export</span> PATH<span class="token operator">=</span><span class="token variable">$PATH</span>:/opt/homebrew/Cellar/mongodb/5.0.7/bin重新加载配置文件:<span class="token function">source</span> ~/.zshrc配置成功后会显示刚才配置的路径<span class="token keyword">echo</span> <span class="token variable">$PATH</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>重启终端执行: <code>mongod -version</code><br>我的 mongodb 配置文件路径:<br><code>/opt/homebrew/etc/mongod.conf</code></p></li><li><p>启动方式 1</p><blockquote><p>使用 brew 将 MongoDB 作为 MacOS 的服务器运行</p></blockquote><p>这种方式启动时 start 后面的 必须和按照时对应,我这里安装完修改了目录名称对应执行命令失败<br>启动:<br><code>brew services start mongodb/brew/mongodb-community@5.0</code><br>如果修改目录为 mongodb 执行如下命令失败<br><code>brew services start mongodb/brew/mongodb</code><br>停止:</p><p><code>brew services stop mongodb/brew/mongodb-community@5.0</code></p><p>出现如下说明启动、关闭成功,但不代表可以链接成功:<br>==> <strong>Successfully started</strong> <code>mongodb-community@5.0</code> (label: <a href="mailto:homebrew.mxcl.mongodb-community@5.0">homebrew.mxcl.mongodb-community@5.0</a>)<br>==> <strong>Successfully stopped</strong> <code>mongodb-community@5.0</code> (label: <a href="mailto:homebrew.mxcl.mongodb-community@5.0">homebrew.mxcl.mongodb-community@5.0</a>)</p><p>启动成功访问:<a href="http://127.0.0.1:27017">http://127.0.0.1:27017</a><br>出现:It looks like you are trying to access MongoDB over HTTP on the native driver port. 则成功。</p></li><li><p>启动方式 2</p><blockquote><p>使用配置文件启动 mongodb 服务,将 MongoDB 作为后端程序运行(我这里没成功待处理)</p></blockquote><p>命令参数,注意这里的目录要换成自己的<br><code>mogond --dbpath $dbpath (数据库数据文件路径)</code><br>–logpath $logpath(日志文件的路径)<br>–logappend(以追加的方式打开文件)<br>–fork(将数据库服务放在后台运行)<br>如:<br><code>mongod --dbpath /opt/homebrew/var/mongodb --logpath /opt/homebrew/var/log/mongodb/mongo.log --fork</code></p><p>启动:<br><code>mongod --config /opt/homebrew/etc/mongod.conf</code><br>停止:<br><code>mongod --config /opt/homebrew/etc/mongod.conf</code></p></li><li><p>启动成功后 终端链接 <code>mongodb</code><br>链接数据库失败问题:<br>MongoDB shell version v5.0.7<br>connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb<br>Error: couldn’t connect to server 127.0.0.1:27017, connection attempt failed: SocketException: Error connecting to 127.0.0.1:27017 :: caused by :: Connection refused :<br><code>connect@src/mongo/shell/mongo.js:372:17</code><br>@(connect):2:6<br>exception: connect failed<br>exiting with code 1</p><p>出现这个问题时,关闭服务,重新启动命令前加 <code>sudo</code>,启动后 重新打开终端,如果还报错 删除文件 <code>var/mongodb/mongodb.lock</code> 重新启动试试<br><code>mongo</code> 出现一下提示代表链接成功即可操作数据库</p><pre class="line-numbers language-bash"><code class="language-bash">MongoDB shell version v5.0.7connecting to: mongodb://127.0.0.1:27017/?compressors<span class="token operator">=</span>disabled<span class="token operator">&</span>gssapiServiceName<span class="token operator">=</span>mongodbImplicit session: session <span class="token punctuation">{</span> <span class="token string">"id"</span> <span class="token keyword">:</span> UUID<span class="token punctuation">(</span><span class="token string">"470b3bca-4d34-4371-b954-16c2ea60c230"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>MongoDB server version: 5.0.7<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>输入:<code>show dbs;</code> 查看所有数据库<br>退出: <code>shell: quit();</code></p></li></ul><h3 id="mysql-安装"><a href="#mysql-安装" class="headerlink" title="mysql 安装"></a>mysql 安装</h3><p><code>brew install mysql@5.7</code><br>查看版本:<br><code>mysql -V</code></p><p>启动 mysql:可以使用命令查看提示,<br><code>brew info mysql</code> 根据提示,有两种启动方式:<br> <code>brew services start mysql</code><br> <code>mysql.server start</code><br> <code>mysql.server restart</code> // 重启<br> 关闭数据库:<br> <code>mysql.server stop</code><br> 链接数据库:<br> <code>mysql -u root</code><br> 修改密码:<br> <code>mysql_secure_installation</code></p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> macOs </category>
</categories>
<tags>
<tag> macOs </tag>
</tags>
</entry>
<entry>
<title>从0到1搭建vue3+ts项目</title>
<link href="/posts/61cb.html"/>
<url>/posts/61cb.html</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在自学 vue3 + vite + ts 项目时遇到的一些问题,都是一步一坑踩过来最终解决的,也借鉴了网上很多资料,特以此篇记录我的日常踩坑之路/(ㄒ o ㄒ)/~~</p><p><strong>如果文章对你有帮助,可以点击链接关注我的<a href="https://juejin.cn/user/2041110775208184/posts">掘金社区账号</a> 更多技术分享请移步我的掘金哦~</strong> 😀😀😀</p><p>点击链接 <a href="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群) - 掘金 (juejin.cn)</a> 加vx拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧😎😎😎</p><h2 id="从-0-到-1-搭建-vue3-ts-项目配置-eslint"><a href="#从-0-到-1-搭建-vue3-ts-项目配置-eslint" class="headerlink" title="从 0 到 1 搭建 vue3+ts 项目配置 eslint"></a>从 0 到 1 搭建 vue3+ts 项目配置 eslint</h2><ul><li><p>为什么要用 eslint?<br>目的:为了规范团队成员代码格式,以及保持统一的代码风格,此项目采用当前业界最火的 Airbnb 规范,并引入代码风格管理工具 Prettier。</p></li><li><p>为什么 ts 项目不用 tslint 而用于 eslint ?<br>因为 tslint 已经不维护了!!!</p></li><li><p>我的电脑本地环境版本:</p><pre class="line-numbers language-bash"><code class="language-bash">vscode: 1.68.1node: 16.13.2pnpm: 6.32.2vue-cli: 5.0.0-bate.3yarn: 1.22.10<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>node 版本下载链接: <a href="https://nodejs.org/en/download/releases/">https://nodejs.org/en/download/releases/</a></p></li><li><p>项目开始:<br><code>pnpm create vite</code> 我这种创建项目方式一些配置文件需要手动创建配置如.eslintrc.js<br>输入项目名称<br>选择项目模板 <code>vue -> vue-ts</code><br>cd project 下载依赖 <code>pnpm i</code></p></li></ul><h3 id="配置-eslint-以及相关依赖"><a href="#配置-eslint-以及相关依赖" class="headerlink" title="配置 eslint 以及相关依赖"></a>配置 eslint 以及相关依赖</h3><p>eslint 只有开发阶段需要,因此添加到开发阶段的依赖中即可;根目录创建 .eslintrc.js 文件</p><p>eslint: eslint 的核心代码<br>eslint-plugin-vue :vue 官方 ESLint 插件,检查 .vue 文件中 template、script 中的语法错误、指令等<br>安装:<code>pnpm i eslint eslint-plugin-vue -D</code></p><ul><li><p>配置 eslint 对.ts 文件的支持</p><p><code>@typescript-eslint/eslint-plugin</code>:这是一个 ESLint 插件,包含了各类定义好的检测 Typescript 代码的规范<br><code>@typescript-eslint/parser</code> eslint 解析器用于支持解析 typescript,从而检查和规范 Typescript 代码<br>安装:<br><code>pnpm i @typescript-eslint/eslint-plugin @typescript-eslint/parser -D</code></p></li><li><p>eslint 具体校验规则配置<br>eslint 规则有很多,我们可以根据自己的需求自行配置,但是过于麻烦!目前业界有三个流行开源配置方案,分别是 Airbnb、 Standard、 Google,严格程度对比是 Airbnb > Google > Standard,所以普遍使用 Airbnb 较多,所有我这里使用安装 Airbnb<br><code>pnpm i eslint-config-airbnb-base -D</code></p></li></ul><h3 id="prettier-配置以及解决-eslint-和-prettier-冲突"><a href="#prettier-配置以及解决-eslint-和-prettier-冲突" class="headerlink" title="prettier 配置以及解决 eslint 和 prettier 冲突"></a>prettier 配置以及解决 eslint 和 prettier 冲突</h3><ul><li>prettier 安装:<code>pnpm i prettier -D</code></li><li>解决 eslint 和 prettier 冲突<br>eslint-config-prettier: 关闭所有和 prettier 冲突的 eslint 规则<br>eslint-plugin-prettier: 告诉 eslint 应该怎么按照 prettier 的方式去格式化文档。<br><code>pnpm i eslint-config-prettier eslint-plugin-prettier -D</code></li><li>具体 prettierrc 规则配置,根目录创建.prettierrc.js 以及忽略文件.prettierignore</li></ul><pre class="line-numbers language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// printWidth: 100, // 一行最多 100 字符</span> <span class="token comment" spellcheck="true">// tabWidth: 2, // 使用 4 个空格缩进</span> <span class="token comment" spellcheck="true">// semi: false, // 行尾需要有分号</span> semi<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 行尾需要有分号</span> trailingComma<span class="token punctuation">:</span> <span class="token string">"none"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 末尾不需要逗号</span> singleQuote<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 使用单引号而不是双引号</span> <span class="token comment" spellcheck="true">// useTabs: false, // 用制表符而不是空格缩进行</span> <span class="token comment" spellcheck="true">// quoteProps: 'as-needed', // 仅在需要时在对象属性两边添加引号</span> <span class="token comment" spellcheck="true">// jsxSingleQuote: false, // 在 JSX 中使用单引号而不是双引号</span> <span class="token comment" spellcheck="true">// bracketSpacing: true, // 大括号内的首尾需要空格</span> <span class="token comment" spellcheck="true">// bracketSameLine: false, // 将多行 HTML(HTML、JSX、Vue、Angular)元素反尖括号需要换行</span> <span class="token comment" spellcheck="true">// arrowParens: 'always', // 箭头函数,只有一个参数的时候,也需要括号 avoid</span> <span class="token comment" spellcheck="true">// rangeStart: 0, // 每个文件格式化的范围是开头-结束</span> <span class="token comment" spellcheck="true">// rangeEnd: Infinity, // 每个文件格式化的范围是文件的全部内容</span> <span class="token comment" spellcheck="true">// requirePragma: false, // 不需要写文件开头的 @prettier</span> <span class="token comment" spellcheck="true">// insertPragma: false, // 不需要自动在文件开头插入 @prettier</span> <span class="token comment" spellcheck="true">// proseWrap: 'preserve', // 使用默认的折行标准 always</span> <span class="token comment" spellcheck="true">// htmlWhitespaceSensitivity: 'css', // 根据显示样式决定 html 要不要折行</span> <span class="token comment" spellcheck="true">// vueIndentScriptAndStyle: false, //(默认值)对于 .vue 文件,不缩进 <script> 和 <style> 里的内容</span> <span class="token comment" spellcheck="true">// // endOfLine: 'lf', // 换行符使用 lf 在Linux和macOS以及git存储库内部通用\n</span> <span class="token comment" spellcheck="true">// embeddedLanguageFormatting: 'auto' //(默认值)允许自动格式化内嵌的代码块</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>保证 plugin:prettier/recommended 放在.eslintrc extends 中最后</p><ul><li><p>运行时对代码进行 eslint 校验<br>这样配置完重启编辑器项目应该不会有报错,因为需要执行 eslint 命令去检测文件中不符合规则的代码这不是我们期望的<br>我们期望的是代码运行期间如果不符合 eslint 规范就报错提示。这里使用的是 rollup 的 eslint 插件<br><code>pnpm i @rollup/plugin-eslint -D</code><br>vite 配置文件里 plugins 开启 eslint:</p><pre class="line-numbers language-js"><code class="language-js"><span class="token comment" spellcheck="true">// ...,</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// 开启eslint</span> <span class="token operator">...</span><span class="token function">eslint</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// include: ['src</span><span class="token comment" spellcheck="true">/**/</span><span class="token operator">*</span><span class="token punctuation">.</span>vue<span class="token string">', '</span>src<span class="token comment" spellcheck="true">/**/</span><span class="token operator">*</span><span class="token punctuation">.</span>js'<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// fix: true, // 自动修复</span> include<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'src/**/*.js'</span><span class="token punctuation">,</span> <span class="token string">'src/**/*.ts'</span><span class="token punctuation">,</span> <span class="token string">'src/**/*.vue'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 需要检查的文件</span> <span class="token comment" spellcheck="true">// exclude: ['src</span><span class="token comment" spellcheck="true">/**/</span><span class="token operator">*</span><span class="token punctuation">.</span>js<span class="token string">', '</span>src<span class="token comment" spellcheck="true">/**/</span><span class="token operator">*</span><span class="token punctuation">.</span>vue'<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 忽略文件</span> throwOnError<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 有错误抛出</span> throwOnWarning<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 有警告抛出</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> enforce<span class="token punctuation">:</span> <span class="token string">'pre'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><p>这时重启项目,运行时某个文件代码不符合 eslint 规则就会直接报错,必须修复后才可以运行成功,至此到达了我们预期的效果。</p><blockquote><p>packge.josn 所有依赖</p></blockquote><pre class="line-numbers language-js"><code class="language-js"> <span class="token string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"dev"</span><span class="token punctuation">:</span> <span class="token string">"vite"</span><span class="token punctuation">,</span> <span class="token string">"build"</span><span class="token punctuation">:</span> <span class="token string">"vue-tsc --noEmit && vite build"</span><span class="token punctuation">,</span> <span class="token string">"preview"</span><span class="token punctuation">:</span> <span class="token string">"vite preview"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 环境变量</span> <span class="token string">"dev1"</span><span class="token punctuation">:</span> <span class="token string">"vite --mode development"</span><span class="token punctuation">,</span> <span class="token string">"test"</span><span class="token punctuation">:</span> <span class="token string">"vite --mode test"</span><span class="token punctuation">,</span> <span class="token string">"prod"</span><span class="token punctuation">:</span> <span class="token string">"vite --mode production"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// lint 检查./src下所有这些结尾的文件</span> <span class="token string">"lint"</span><span class="token punctuation">:</span> <span class="token string">"eslint --ext .js,.jsx,.ts,.tsx,.vue ./src"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// eslint fix修复问题(只能修复部分)</span> <span class="token string">"fix"</span><span class="token punctuation">:</span> <span class="token string">"eslint --ext .js,.jsx,.ts,.tsx,.vue ./src --fix"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"dependencies"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"@element-plus/icons-vue"</span><span class="token punctuation">:</span> <span class="token string">"^2.0.4"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 饿了么plus-icon</span> <span class="token string">"@types/node"</span><span class="token punctuation">:</span> <span class="token string">"^17.0.42"</span><span class="token punctuation">,</span> <span class="token string">"axios"</span><span class="token punctuation">:</span> <span class="token string">"^0.27.2"</span><span class="token punctuation">,</span> <span class="token string">"element-plus"</span><span class="token punctuation">:</span> <span class="token string">"^2.2.5"</span><span class="token punctuation">,</span> <span class="token string">"mockjs"</span><span class="token punctuation">:</span> <span class="token string">"^1.1.0"</span><span class="token punctuation">,</span> <span class="token string">"pinia"</span><span class="token punctuation">:</span> <span class="token string">"^2.0.14"</span><span class="token punctuation">,</span> <span class="token string">"vue"</span><span class="token punctuation">:</span> <span class="token string">"^3.2.25"</span><span class="token punctuation">,</span> <span class="token string">"vue-router"</span><span class="token punctuation">:</span> <span class="token string">"^4.0.16"</span><span class="token punctuation">,</span> <span class="token string">"vuex"</span><span class="token punctuation">:</span> <span class="token string">"^4.0.2"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"devDependencies"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// rollup插件开启eslint检查</span> <span class="token string">"@rollup/plugin-eslint"</span><span class="token punctuation">:</span> <span class="token string">"^8.0.2"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// ts解析器 让eslint支持对ts文件检查</span> <span class="token string">"@typescript-eslint/eslint-plugin"</span><span class="token punctuation">:</span> <span class="token string">"^5.28.0"</span><span class="token punctuation">,</span> <span class="token string">"@typescript-eslint/parser"</span><span class="token punctuation">:</span> <span class="token string">"^5.28.0"</span><span class="token punctuation">,</span> <span class="token string">"@vitejs/plugin-vue"</span><span class="token punctuation">:</span> <span class="token string">"^2.3.3"</span><span class="token punctuation">,</span> <span class="token string">"consola"</span><span class="token punctuation">:</span> <span class="token string">"^2.15.3"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// airbnb 比较火的eslint开源配置方案</span> <span class="token string">"eslint-config-airbnb-base"</span><span class="token punctuation">:</span> <span class="token string">"^15.0.0"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// "eslint-import-resolver-typescript": "^2.7.1",</span> <span class="token comment" spellcheck="true">// 对 mport/export的语法进行linting,并防止文件路径和导入名称拼写错误的问题</span> <span class="token string">"eslint-plugin-import"</span><span class="token punctuation">:</span> <span class="token string">"^2.26.0"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// prettier 以及 解决prettier和eslint冲突</span> <span class="token string">"prettier"</span><span class="token punctuation">:</span> <span class="token string">"^2.7.0"</span><span class="token punctuation">,</span> <span class="token string">"eslint-config-prettier"</span><span class="token punctuation">:</span> <span class="token string">"^8.5.0"</span><span class="token punctuation">,</span> <span class="token string">"eslint-plugin-prettier"</span><span class="token punctuation">:</span> <span class="token string">"^4.0.0"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 基础eslint</span> <span class="token string">"eslint"</span><span class="token punctuation">:</span> <span class="token string">"^8.17.0"</span><span class="token punctuation">,</span> <span class="token string">"eslint-plugin-vue"</span><span class="token punctuation">:</span> <span class="token string">"^9.1.1"</span><span class="token punctuation">,</span> <span class="token string">"less"</span><span class="token punctuation">:</span> <span class="token string">"^4.1.3"</span><span class="token punctuation">,</span> <span class="token string">"less-loader"</span><span class="token punctuation">:</span> <span class="token string">"^11.0.0"</span><span class="token punctuation">,</span> <span class="token string">"typescript"</span><span class="token punctuation">:</span> <span class="token string">"^4.5.4"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 饿了么css样式按需引入</span> <span class="token string">"vite-plugin-style-import"</span><span class="token punctuation">:</span> <span class="token string">"^2.0.0"</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 饿了么plus 组件按需引入</span> <span class="token string">"unplugin-auto-import"</span><span class="token punctuation">:</span> <span class="token string">"^0.8.8"</span><span class="token punctuation">,</span> <span class="token string">"unplugin-vue-components"</span><span class="token punctuation">:</span> <span class="token string">"^0.19.6"</span><span class="token punctuation">,</span> <span class="token string">"vite"</span><span class="token punctuation">:</span> <span class="token string">"^2.9.9"</span><span class="token punctuation">,</span> <span class="token string">"vue-tsc"</span><span class="token punctuation">:</span> <span class="token string">"^0.34.7"</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="vue3-ts-项目配置-eslint-遇到的具体问题"><a href="#vue3-ts-项目配置-eslint-遇到的具体问题" class="headerlink" title="vue3+ts 项目配置 eslint 遇到的具体问题"></a>vue3+ts 项目配置 eslint 遇到的具体问题</h3><p>eslint 问题所有相关配置都在根目录 .eslintrc.js 文件下配置<br>此项目 eslint 使用的是 <code>@rollup/plugin-eslint</code> 这个插件依赖</p><ul><li><p>vue3 一直报错 error: Parsing error: Unexpected token ?<br>我在引入 element-plus 类型时 type 这里 eslint 一直报这个错<br><code>import type { FormInstance, FormRules } from 'element-plus'</code><br><strong>vue3+ts 解决方法</strong><br>需要先安装 ts 解析器依赖: <code>yarn add @typescript-eslint/parser -D</code></p><pre class="line-numbers language-js"><code class="language-js">parserOptions<span class="token punctuation">:</span> <span class="token punctuation">[</span> parser<span class="token punctuation">:</span> <span class="token string">'@typescript-eslint/parser'</span><span class="token punctuation">,</span><span class="token punctuation">]</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></li><li><p>vue3+ts 解决 The template root requires exactly one element.eslintvue/no-multiple-template-root 问题?</p><pre class="line-numbers language-js"><code class="language-js"><span class="token keyword">extends</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token comment" spellcheck="true">// 解决根元素报错问题</span> <span class="token string">'plugin:vue/vue3-essential'</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// vue3 推使用这个规则支持.vue文件校验</span> <span class="token string">'plugin:vue/vue3-recommended'</span><span class="token punctuation">]</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>error Parsing error: ‘>‘ expected ?<br>让 eslint 检测.vue 代码<br><strong>解决</strong>:<br><code>parser: 'vue-eslint-parser',</code></p></li><li><p>Missing file extension “ts” for “xxx” import/extensions ?<br>导入/扩展缺少文件扩展名“ts”<br>使用了 airbnb-base 规则后,如引入 <code>import components from './components'</code> 文件报错,必须写到 components 下的 index.ts<br><strong>解决</strong>:rulse 规则配置忽略</p><pre class="line-numbers language-js"><code class="language-js">rules<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">'import/extensions'</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">'error'</span><span class="token punctuation">,</span> <span class="token string">'ignorePackages'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> js<span class="token punctuation">:</span> <span class="token string">'never'</span><span class="token punctuation">,</span> jsx<span class="token punctuation">:</span> <span class="token string">'never'</span><span class="token punctuation">,</span> ts<span class="token punctuation">:</span> <span class="token string">'never'</span><span class="token punctuation">,</span> tsx<span class="token punctuation">:</span> <span class="token string">'never'</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>Unable to resolve path to module xxx import/no-unresolved ?<br>配置别名后:无法解析模块 xxx 导入的路径/未解析路径<br><strong>解决</strong>:<br>vite.config 里配置别名<br>网上说还需要在 ts.config.json paths 配置同上的别名,但是配置了 eslint 还是会不通过;<br>安装: <code>pnpm i eslint-import-resolver-alias</code> 这个包是一个配合 eslint-plugin-import 使用的 resolver,用来 resolve 带别名的路径。<br>配置 eslint</p><pre class="line-numbers language-js"><code class="language-js"><span class="token comment" spellcheck="true">// .eslomtrc.js</span>settings<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">'import/resolver'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// 别名同vite.config</span> alias<span class="token punctuation">:</span> <span class="token punctuation">{</span> map<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span><span class="token string">'@'</span><span class="token punctuation">,</span> <span class="token string">'./src'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'@mock'</span><span class="token punctuation">,</span> <span class="token string">'./src/mock'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">//...</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> extensions<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'js'</span><span class="token punctuation">,</span> <span class="token string">'.ts'</span><span class="token punctuation">,</span> <span class="token string">'.jsx'</span><span class="token punctuation">,</span> <span class="token string">'.tsx'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><!-- -------------------------------------------------------- --><h3 id="其他报错问题"><a href="#其他报错问题" class="headerlink" title="其他报错问题"></a>其他报错问题</h3><ul><li><p>找不到模块“xxx”或其相应的类型声明?<br>没有相关的声明文件,在 ts 项目里面,.ts 文件是识别不了.vue 文件,.vue 文件也识别不了.ts 文件,这时候就需要在 src 下 创建 env.d.ts 声明文件来解决:</p><pre class="line-numbers language-js"><code class="language-js"> <span class="token comment" spellcheck="true">/// <reference types="vite/client" /></span> declare module <span class="token string">'*.vue'</span> <span class="token punctuation">{</span> <span class="token keyword">import</span> type <span class="token punctuation">{</span> DefineComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span> <span class="token comment" spellcheck="true">// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types</span> <span class="token keyword">const</span> component<span class="token punctuation">:</span> DefineComponent<span class="token operator"><</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> any<span class="token operator">></span> <span class="token keyword">export</span> <span class="token keyword">default</span> component <span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>但是我遇到的问题是自己写的 ts 文件: <code>import { getProducts, IProduct } from '@mock/pages/shop'</code> 也提示找不到模块“@mock/pages/shop”或其相应的类型声明。 但不影响运行<br>在 ts 文件中定义好有关的 interface 接口使用,在其他文件中引入的时候出现了该问题<br>一般出现这个问题都是路径问题!!!建议别名只配置一个 [‘@’, ‘./src’]</p></li></ul><h2 id="vue3-vite-项目中遇到的代码问题"><a href="#vue3-vite-项目中遇到的代码问题" class="headerlink" title="vue3+vite 项目中遇到的代码问题"></a>vue3+vite 项目中遇到的代码问题</h2><h3 id="Element-Plus-官网推荐的自动引入组件方式部分组件-css-无法引入"><a href="#Element-Plus-官网推荐的自动引入组件方式部分组件-css-无法引入" class="headerlink" title="Element Plus 官网推荐的自动引入组件方式部分组件 css 无法引入"></a>Element Plus 官网推荐的自动引入组件方式部分组件 css 无法引入</h3><p>官网推荐使用这个两个插件 <code>npm install -D unplugin-vue-components unplugin-auto-import</code> 实现自动按需导入</p><pre class="line-numbers language-js"><code class="language-js"><span class="token comment" spellcheck="true">// vite.config.ts</span><span class="token keyword">import</span> <span class="token punctuation">{</span> defineConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"vite"</span><span class="token punctuation">;</span><span class="token keyword">import</span> AutoImport <span class="token keyword">from</span> <span class="token string">"unplugin-auto-import/vite"</span><span class="token punctuation">;</span><span class="token keyword">import</span> Components <span class="token keyword">from</span> <span class="token string">"unplugin-vue-components/vite"</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token punctuation">{</span> ElementPlusResolver <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"unplugin-vue-components/resolvers"</span><span class="token punctuation">;</span><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineConfig</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// ...</span> plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token comment" spellcheck="true">// ...</span> <span class="token function">AutoImport</span><span class="token punctuation">(</span><span class="token punctuation">{</span> resolvers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">ElementPlusResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Components</span><span class="token punctuation">(</span><span class="token punctuation">{</span> resolvers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">ElementPlusResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如:引入 ElMessage 为例<br><code>import { ElMessage } from 'element-plus'</code><br><code>ElMessage.warning('warning')</code><br>如果不采用 import 的方式引入,会直接报错:ElMessage 没有定义,所以这个 import 是省不了的,但是 import 了之后,消息弹窗是出来了,但此时发现没有对应的样式!</p><ul><li>解决方案 1 (不推荐):<br>使用官网说的手动导入的 <code>unplugin-element-plus</code>的插件,但是很麻烦,不同组件需要手动引入不同的 css</li></ul><pre class="line-numbers language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token string">"element-plus/es/components/message/style/css"</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// import 'element-plus/es/components/用到的组件/style/css'</span><span class="token keyword">import</span> <span class="token punctuation">{</span> ElMessage <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"element-plus"</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><ul><li>解决方案 2 (推荐):<br>使用 <code>vite-plugin-style-import</code> 插件可以实现按需引入 css;<br>安装完成后在 vite.config.js 下 plugins: [] 使用。<br>该插件可以按需引入 VantResolve、 ElementPlusResolve 等 ui 样式<br>因为该插件的使用了 <code>consola</code> 包,所以还需要安装 <code>npm i consola -D OR yarn add consola -D</code></li></ul><blockquote><p>1.x 写法</p></blockquote><pre class="line-numbers language-js"><code class="language-js"><span class="token keyword">import</span> styleImport <span class="token keyword">from</span> <span class="token string">'vite-plugin-style-import'</span><span class="token function">styleImport</span><span class="token punctuation">(</span><span class="token punctuation">{</span> libs<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> libraryName<span class="token punctuation">:</span> <span class="token string">'element-plus'</span><span class="token punctuation">,</span> esModule<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> resolveStyle<span class="token punctuation">:</span> <span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token string">`element-plus/theme-chalk/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.css`</span></span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// resolveComponent: (name) => {</span> <span class="token comment" spellcheck="true">// return `element-plus/lib/components/${name}`</span> <span class="token comment" spellcheck="true">// },</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>2.x 写法</p></blockquote><pre class="line-numbers language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStyleImportPlugin<span class="token punctuation">,</span> VantResolve <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vite-plugin-style-import'</span><span class="token punctuation">;</span><span class="token function">createStyleImportPlugin</span><span class="token punctuation">(</span><span class="token punctuation">{</span> resolves<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">VantResolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h3 id="引入-Element-Plus-遇到的其他问题"><a href="#引入-Element-Plus-遇到的其他问题" class="headerlink" title="引入 Element Plus 遇到的其他问题"></a>引入 Element Plus 遇到的其他问题</h3><h3 id="本地环境无任何报错,部署上线后报错"><a href="#本地环境无任何报错,部署上线后报错" class="headerlink" title="本地环境无任何报错,部署上线后报错"></a>本地环境无任何报错,部署上线后报错</h3><ul><li>报错 Cannot read properties of null (reading ‘insertBefore‘)<br>本地项目启动操作无任何报错,部署后开始报这个错, 经过排查上网查资料原因总结如下:</li></ul><blockquote><p>v-if 导致<br>在 v-if 值为 false 时,如果操作了 v-if 控制的 DOM,可能会因为该 DOM 元素不存在而报错。<br><strong>解决方</strong>:v-show 替换 v-if</p></blockquote><blockquote><p>el-table 组件导致<br>el-table-column 渲染时报错,若 scope.row.xxx (xxx 为任意字段值)不存在,对其直接执行 split、toString() 等方法时报错。<br>我是因为这个报错<br><strong>解决方</strong>:<br>可选链操作符: <code>scope.row.field?.split</code></p></blockquote><blockquote><p>el-dialog 组件导致<br>默认弹框是关闭的,DOM 中没有弹框中的内容。打开弹框再关闭后,弹框中的 DOM 元素没有被销毁,可能会因为不该存在的 DOM 元素而报错<br><strong>解决方</strong>:给 el-dialog 组件增加 destroy-on-close 属性</p></blockquote><h3 id="jsx-使用"><a href="#jsx-使用" class="headerlink" title="jsx 使用"></a>jsx 使用</h3><ul><li><p>安装<br><code>npm i @vitejs/plugin-vue-jsx</code></p><pre class="line-numbers language-js"><code class="language-js"><span class="token comment" spellcheck="true">// vite.config.ts</span><span class="token keyword">import</span> <span class="token punctuation">{</span> defineConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"vite"</span><span class="token punctuation">;</span><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineConfig</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// ...</span> plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token comment" spellcheck="true">// ...</span> <span class="token function">vueJsx</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>然后就可以创建.jsx 文件使用 jsx 语法</p><pre class="line-numbers language-jsx"><code class="language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> defineComponent<span class="token punctuation">,</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"vue"</span><span class="token punctuation">;</span><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineComponent</span><span class="token punctuation">(</span><span class="token punctuation">{</span> props<span class="token punctuation">:</span> <span class="token punctuation">{</span> params<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> Object<span class="token punctuation">,</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function">setup</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> str <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token string">"tsx的使用"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> clickFunc1 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"没有参数"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> clickFunc2 <span class="token operator">=</span> <span class="token punctuation">(</span>msg <span class="token operator">=</span> <span class="token string">"默认值"</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>msg<span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"接收到的:"</span><span class="token punctuation">,</span> props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>async<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>str<span class="token punctuation">.</span>value<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token punctuation">=</span><span class="token punctuation">{</span>clickFunc1<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>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><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 operator">></span> <span class="token function">clickFunc2</span><span class="token punctuation">(</span><span class="token string">"额外参数"</span><span class="token punctuation">)</span><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>button</span><span class="token punctuation">></span></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>或者 .vue 里 script 写 jsx</p><pre class="line-numbers language-jsx"><code class="language-jsx"><span class="token operator"><</span><span class="token operator">!</span><span class="token operator">--</span> lang<span class="token operator">=</span>jsx tsx好像都可以 <span class="token operator">--</span><span class="token operator">></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>jsx<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span><span class="token script language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> defineComponent<span class="token punctuation">,</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineComponent</span><span class="token punctuation">(</span><span class="token punctuation">{</span> props<span class="token punctuation">:</span> <span class="token punctuation">{</span> params<span class="token punctuation">:</span> <span class="token punctuation">{</span> type<span class="token punctuation">:</span> Object<span class="token punctuation">,</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> setup <span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> str <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token string">'script lang=jsx写法'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> clickFunc1 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'没有参数'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> clickFunc2 <span class="token operator">=</span> <span class="token punctuation">(</span>msg <span class="token operator">=</span> <span class="token string">'默认值'</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'接收到的:'</span> <span class="token operator">+</span> msg<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">'jsxBox'</span><span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span>str<span class="token punctuation">.</span>value<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token function">clickFunc1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>点击<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token function">clickFunc2</span><span class="token punctuation">(</span><span class="token string">'额外参数'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>传参数点击<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>less<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token style language-css"> <span class="token selector"><span class="token class">.jsxBox</span></span><span class="token punctuation">{</span> <span class="token property">border</span><span class="token punctuation">:</span><span class="token number">1</span>px solid red<span class="token punctuation">;</span> <span class="token punctuation">}</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> eslint vite ts </category>
</categories>
<tags>
<tag> ts </tag>
<tag> eslint </tag>
<tag> vue3 </tag>
</tags>
</entry>
<entry>
<title>搭建自己的图床</title>
<link href="/posts/3e2v.html"/>
<url>/posts/3e2v.html</url>
<content type="html"><![CDATA[<h2 id="什么是图床?"><a href="#什么是图床?" class="headerlink" title="什么是图床?"></a>什么是图床?</h2><p>简单理解为将图片上传存储到服务器,同时可以在公网中通过 url 访问图片。</p><h2 id="为什么要搭建图床?"><a href="#为什么要搭建图床?" class="headerlink" title="为什么要搭建图床?"></a>为什么要搭建图床?</h2><p>我们在写 Markdown 文档时对于文档里面的图片,如果不使用图床,图片都是存放在本地,其他地方要用的话还得复制来复制去很不方便,也不好管理。<br>为了解决这种问题,达到一劳永逸的目的解决方法就是搭建自己的图床,把需要用的图片地址变成网络地址,这样想在哪里用直接通过链接方式使用。</p><h2 id="PicGo"><a href="#PicGo" class="headerlink" title="PicGo"></a>PicGo</h2><p>图床工具就是自动把本地图片转换成链接的一款工具!<br>网络上有很多图床工具 PicGo 是一款用 Electron-vue 开发的开源软件,可以支持微博,七牛云,腾讯云 COS,又拍云,GitHub,阿里云 OSS,SM.MS,imgur 等 8 种常用图床,功能强大,支持 Windowns,macOS 和 Linux 平台<br>github 下载地址:[<a href="https://github.com/Molunerfinn/PicGo/releases]">https://github.com/Molunerfinn/PicGo/releases]</a></p><p>这么多图床有收费的有免费的,且对应我们个人用户来说免费的也完全够用,我们当然选择白嫖啦!哈哈哈~</p><h2 id="搭建自己的图床"><a href="#搭建自己的图床" class="headerlink" title="搭建自己的图床"></a>搭建自己的图床</h2><p>按需下载安装完 PicGo 工具后,这里使用免费的 gitee、github 图床,先创建一个专门存储图片的仓库且设置为公开的。<br>生成一个新的个人令牌 token(需要注意的是生成后记得保存,该 token 只出现一次,后续是不可查看的)</p><ul><li>使用 gitee 图床(不推荐)</li></ul><!-- ![](https://gitee.com/sisi001/picBed/raw/master/blog/picgo1.png) --><p><img src="https://cdn.jsdelivr.net/gh/silin001/picBed@main/blog/pic1.png" alt=""><br>先在软件中安装 gitee 的插件来支持,安装完后在图床设置的最后就可以看到 gitee 点击进行配置 gitee<br><img src="https://cdn.jsdelivr.net/gh/silin001/picBed@main/blog/pic2.png" alt=""></p><!-- ![](https://gitee.com/sisi001/picBed/raw/master/blog/picgo2.png) --><p>repo: 仓库名称</p><p>path: 存放图片的目录,可以不写,默认根路径</p><p>token: 在 gitee 生成的 token</p><p>其他选项可以不填</p><p>然后就可以开心的使用了,在软件的上传区上传,这里很方便的是可以使用剪贴板的图片,这样我们拿微信或者其他截图工具随手截图后直接点击剪贴板图片就可以上传(注意剪贴板中必须要有图片否则会失败,如果有报错可以在设置中根据日志文件来定位问题)</p><p>上传成功后远程仓库就会看到上传成功的图片,在工具左侧相册中也可以看到图片,还可以预览、修改、删除等操作,但是这里的删除操作只是删除本地图片,无法同步删除远程仓库的图床。</p><p>gitee 作为图床:<br><strong>优点:</strong><br>免费<br>毕竟服务器在国内,访问速度比 github 更快<br><strong>缺点:</strong><br>gitee 本身还有 1 M 图片大小的限制,而且据了解现在不允许作为图床了,做了防盗链,使用图床的图片会变成 gitee 的 icon。</p><ul><li><p>使用 github 图床+jsDelivr<br>github 图床步骤和上面几乎一样; jsDelivr 下面详讲。</p></li><li><p>免费的代价<br>图片大小有限制;众多免费图床服务注册条款里均有禁止商用说明,万一哪天你使用的服务挂掉了或者关闭了图片外链,那你所有的链接都无法访问了,对你造成的损失或许不小。例如:前几年的微博图床。</p></li></ul><h2 id="github-jsDelivr-CDN加速访问"><a href="#github-jsDelivr-CDN加速访问" class="headerlink" title="github + jsDelivr CDN加速访问"></a>github + jsDelivr CDN加速访问</h2><p>地址: ![<a href="https://www.jsdelivr.com]">https://www.jsdelivr.com]</a><br>jsDelivr 不支持加载超过 20M 的资源<br>CDN 加速:可以通过 CDN 的就近访问原则加快图片的访问速度。</p><ul><li><p>为什么使用它?<br>因为 github 服务器在国外访问速度很慢所以我们使用 jsDelivr CDN 免费加速。<br>原本 github 的自定义域名应该是:<a href="https://raw.githubusercontent.com/[username]/[仓库名]">https://raw.githubusercontent.com/[username]/[仓库名]</a></p><p>但是使用这种方式访问图片很慢,所以使用 jsdelivr 作为 cdn 加速。<br>使用简单改变域名即可,不需要任何其他配置。</p></li><li><p>jsDelivr 的 CDN 加速链接格式<br><code>https://cdn.jsdelivr.net/gh/GitHub用户名/仓库名@发布的版本号/图片路径</code><br>因为我们这里上传的只是图片,就不设置版本了,所以链接修改如下:<br><code>https://cdn.jsdelivr.net/gh/GitHub用户名/仓库名/图片路径</code></p></li><li><p>cdn 加速图片</p></li></ul><p>例如我的 cdn 加速后的图片链接: <img src="https://cdn.jsdelivr.net/gh/silin001/picBed@main/avtion.png" alt=""></p><ul><li><p>静态文件接入 cdn(重点!)<br>可以像cdn图片的方式一样把所有的css、js等文件的加载路径都修改下,从而让全站使用CDN加速!<br>因为js、css 等静态文件管理和图片有些不同,因为我们会编辑他,会加入新的内容。所以要对 GitHub 中静态文件进行<strong>版本发布</strong>,在 cdn 中引用对应的版本。CDN 中引用的是 GitHub 的“发布版本(release)”,不是“标签版本(Tags)”<br>在任意 JS/CSS 文件后添加 .min 能得到一个缩小版,如果它本身不存在,将会为你生成:<br><a href="https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/src/core.min.js">https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/src/core.min.js</a><br>测试:<br>浏览器打开->F12->Network->Ctrl + F5(强制刷新,即不使用缓存刷新),然后看加载时间多少。</p></li><li><p>修改 PicGo 中的自定义链接<br>如下:<br><code>https://cdn.jsdelivr.net/gh/用户名/仓库名</code><br>现在我们直接上传图片,取得的链接就是 CDN 的链接了, 可以测试一下速度,还是很 nice 的。</p><p>github博客使用cdn全站加速前:<br><img src="https://cdn.jsdelivr.net/gh/silin001/picBed@main/blog/sj.png" alt=""><br>cdn全站加速后资源确实快了:<br><img src="https://cdn.jsdelivr.net/gh/silin001/picBed@main/blog/sj2.png" alt=""></p></li></ul><ul><li>jsDelivr 缓存问题<br>部分文件github已经修改更新,但是jsDelivr访问到的确没有更新,网上找了常见刷新缓存方法也无效,无奈下只好把没有更新的cdn资源替换为本地资源</li></ul><h2 id="遇到的问题"><a href="#遇到的问题" class="headerlink" title="遇到的问题"></a>遇到的问题</h2><ul><li><p>picGo 上传动图 gif<br>如果直接复制网页上的动图,去上传的话是截取的某帧,是静图。应该下载到本地,然后在拖进去上传就可以了</p></li><li><p>github 图床设置</p></li></ul><p>确保你的 GitHub 图床设置路径准确无误<br>检查仓库名不能出现空格,要有空格请用 - 来代替(因为 GitHub 中的空格默认换成-)<br> 图片上传成功到github了 但是访问加速后到链接404,检查发现<br> 在picgo中设置自定义域名时:<br> <code>https://cdn.jsdelivr.net/gh/silin001/silin001.io/@main</code><br> 此处的仓库名称应该是<strong>图床的仓库名称!</strong>:<br> <code>https://cdn.jsdelivr.net/gh/silin001/仓库地址/@main</code></p><ul><li><p>picgo 上传图片报错 401<br>报错日志: “message”:”Bad credentials” 根据百度有的说重启软件也不好使,最后在 github 提了 issues 作者解释为无权限,建议删除 token,生成新的 token 解决。不过我第一天就这样试过不行,第二天发现突然可以了,给我整 emo 了! 遇到这种情况如果反复检查配置没问题,就重新生成 token 试试。有时候都没问题可能是网络问题,多尝试几次.</p></li><li><p>mac电脑按照配置完无法上传成功!<br>我从我的win10配置完后,来到mac 使用picGo配置相同参数后上传失败,最后发现中win上github生成的token,来到mac上不存在了(这个暂时无解,我生成过30天、3个月、永久的token要么刷新就消失,要么过一段时间在刷新就消失很奇怪;虽然消失了但是之前使用的token好像还可以用) 只好需要生成一个新的token。</p></li><li><p>picgo 上传 github 后图片无法显示?</p></li></ul><p>原因是 github 屏蔽掉了图片,解决办法就是修改 host<br>win 路径:C:\Windows\System32\drivers\etc\hosts<br>添加如下:</p><pre class="line-numbers language-js"><code class="language-js"> # GitHub Start<span class="token number">140.82</span><span class="token punctuation">.</span><span class="token number">113.3</span> github<span class="token punctuation">.</span>com<span class="token number">140.82</span><span class="token punctuation">.</span><span class="token number">114.20</span> gist<span class="token punctuation">.</span>github<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> assets<span class="token operator">-</span>cdn<span class="token punctuation">.</span>github<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> raw<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> gist<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> cloud<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> camo<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars0<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">68.133</span> avatars0<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">28.133</span> avatars1<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars1<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars2<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">28.133</span> avatars2<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars3<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">68.133</span> avatars3<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars4<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">68.133</span> avatars4<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars5<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">68.133</span> avatars5<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars6<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">68.133</span> avatars6<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars7<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">68.133</span> avatars7<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">151.101</span><span class="token punctuation">.</span><span class="token number">184.133</span> avatars8<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com<span class="token number">199.232</span><span class="token punctuation">.</span><span class="token number">68.133</span> avatars8<span class="token punctuation">.</span>githubusercontent<span class="token punctuation">.</span>com# GitHub End<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>cmd 执行:<br><code>ipconfig /flushdns</code> 刷新一下本机的 DNS 解析<br>picgo 重启后相册中查看图片正常;刷新 github 页面发现图标可以显示了</p><h3 id="2022-后续更新"><a href="#2022-后续更新" class="headerlink" title="2022 后续更新"></a>2022 后续更新</h3><p> 后来发现jsDelivr在国内死掉了; jsDelivr + github图床根本访问不了,暂时使用聚合图床</p><ul><li>聚合图床</li></ul><p>我的示例图片:<img src="https://pic.imgdb.cn/item/6315abba16f2c2beb157672b.png" alt=""></p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> 工具 </category>
</categories>
<tags>
<tag> 图床 </tag>
</tags>
</entry>
<entry>
<title>h5接入浙里办爬坑</title>
<link href="/posts/f34e.html"/>
<url>/posts/f34e.html</url>
<content type="html"><![CDATA[<h1 id="记录个人遇到的-h5应用接入’浙里办’-的爬坑之路!"><a href="#记录个人遇到的-h5应用接入’浙里办’-的爬坑之路!" class="headerlink" title="记录个人遇到的 h5应用接入’浙里办’ 的爬坑之路!"></a>记录个人遇到的 h5应用接入’浙里办’ 的爬坑之路!</h1><p><strong>如果文章对你有帮助,可以点击链接关注我的<a href="https://juejin.cn/user/2041110775208184/posts">掘金社区账号</a> 更多技术分享请移步我的掘金哦~</strong> 😀😀😀</p><p>点击链接 <a href="https://juejin.cn/post/7146908831438602254">学习交流群(前端微信群) - 掘金 (juejin.cn)</a> 加vx拉你进 <strong>前端学习交流群</strong> 让我们一起 <del>好好学习</del>(🐟🐟🐟)吧😎😎😎</p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>最近接手一个公司之前使用vue2搭建的一个H5项目,现在要求接入到 浙里办APP、浙里办-支付宝小程序。 刚开始可能由于该项目的负责人没有讲的太清楚,导致我和后端哥们二脸懵逼!!!<br>就简单告诉我们app改造接入浙里办,然后群发了 语雀(<a href="https://odynww.yuque.com/docs/share/525e3e8a-ad52-421b-90da-2d76808e3050?#DB3a8">https://odynww.yuque.com/docs/share/525e3e8a-ad52-421b-90da-2d76808e3050?#DB3a8</a>) 这篇文档。 也没和我们讲’浙里办’是什么?之前的app是干嘛用的!我是挺无语的. 对于没接触过这个方向的同学来说简直是懵逼,直接去阅读这么长一篇文档的话也是晕头转向,无从下手的我们只好先请教了之前接触过这方面的同事给我们大致讲了讲流程才大体明白了我们需要做什么。接下来在开发过程中发现要注意的东西还是挺多的,踩了很多坑,特以此篇记录,也为能帮助到初次接触这方面的同学.</p><h3 id="文档阅读"><a href="#文档阅读" class="headerlink" title="文档阅读"></a>文档阅读</h3><p>拿到对接浙里办的文档时,一定要多阅读几遍!!!因为第一次看这东西,内容也多,理解能力不是特别强的同学没几遍还真整不明白。整个文档内容基本了解以后就可以专注前端开发部分了。</p><h3 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h3><p>首先问项目负责人要文档中说的 <em>应用开发管理平台相关账号</em>,这个平台也就是浙里办的应用中台。我们的h5应用开发完打包后需要上传到这个平台,然后测试、发布上线.<br>我们应用一部分内容需要调用浙里办的 <code>JSBridge API</code>调用原生功能, 而这个api只能在浙里办环境下运行,浏览器访问是不可以的! 所以要下载官网提供的debug工具,后面接口调试需要用.</p><h3 id="单点登录"><a href="#单点登录" class="headerlink" title="单点登录"></a>单点登录</h3><p>浙里办是硬性要求用户数据都是要走他那边的登录的,针对这个要求,需要把登录操作的页面跳转直接改为浙里办提供的登录地址。<em>参考文档 1.1.7.3 个人登录</em><br>首先单点登录分为:个人用户的单点登录和法人用户的单点登录,我这里只做了<em>个人用户*登录。<br>个人登录又分为:浙里办app环境登录 和 浙里办-支付宝小程序环境登录.<br>*环境判断见文档:1.1.7.1.浙里办APP、支付宝-浙里办小程序的判断代码</em></p><p>⭐⭐⭐个人登录注意点:<br>需要用到接入码、这个接入码也是找项目负责人由甲方配置提供;<em>goto跳转地址</em>就是我们前端应用的首页,这个地址需要提供给甲方让他们配置好。<br>这样我们就按照文档拼接成了一个登录的跳转地址,等他们把跳转地址配置完之后,用户操作一个涉及到用户读取却没有登录的地方时,就跳转到了浙里办的登录页面地址;<br>然后输入自己的账号密码点击登录,这时候登录成功后页面会自动的跳转到你在第二部分 <code>goto</code>设置的回调地址上,也就是我们h5应用的(一般为)首页。<br>在跳回来的过程中会在 URL 路径上带有登录时返回给你的 <code>ticket</code> 等参数,此时前端需要从url里取出这个标识传给后端进行 ①票据认证 ②票据认证完会返回一个 <code>token</code> 这时就可以拿这个 <code>token</code> 获取到用户信息了.<br>为了简洁操作 这里我们做的时候直接把ticket传给服务端,服务端处理完 直接把用户信息返回给了我客户端.</p><h3 id="埋点"><a href="#埋点" class="headerlink" title="埋点"></a>埋点</h3><p>他们提供的文档很模糊,我在初次接触这块的时候还是在网上查找了大量资料完成.<br>基础埋点代码如下:</p><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token operator"><</span>script<span class="token operator">></span> <span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> d<span class="token punctuation">,</span> s<span class="token punctuation">,</span> q<span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span> w<span class="token punctuation">[</span>q<span class="token punctuation">]</span> <span class="token operator">=</span> w<span class="token punctuation">[</span>q<span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">var</span> f <span class="token operator">=</span> d<span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>j <span class="token operator">=</span> d<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> j<span class="token punctuation">.</span>id <span class="token operator">=</span> <span class="token string">'beacon-aplus'</span><span class="token punctuation">;</span> j<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'https://alidt.alicdn.com/alilog/mlog/aplus_cloud.js'</span><span class="token punctuation">;</span> f<span class="token punctuation">.</span>parentNode<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span>j<span class="token punctuation">,</span> f<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span>window<span class="token punctuation">,</span> document<span class="token punctuation">,</span> <span class="token string">'script'</span><span class="token punctuation">,</span> <span class="token string">'aplus_queue'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> aplus_queue<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> action<span class="token punctuation">:</span> <span class="token string">'aplus.setMetaInfo'</span><span class="token punctuation">,</span> arguments<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'aplus-rhost-v'</span><span class="token punctuation">,</span> <span class="token string">'alog.zjzwfw.gov.cn'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> aplus_queue<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> action<span class="token punctuation">:</span> <span class="token string">'aplus.setMetaInfo'</span><span class="token punctuation">,</span> arguments<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'aplus-rhost-g'</span><span class="token punctuation">,</span> <span class="token string">'alog.zjzwfw.gov.cn'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> u <span class="token operator">=</span> navigator<span class="token punctuation">.</span>userAgent <span class="token keyword">var</span> isAndroid <span class="token operator">=</span> u<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'Android'</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token operator">-</span><span class="token number">1</span> <span class="token keyword">var</span> isIOS <span class="token operator">=</span> <span class="token operator">!</span><span class="token operator">!</span>u<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token regex">/\(i[^;]+;( U;)? CPU.+Mac OS X/</span><span class="token punctuation">)</span> aplus_queue<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> action<span class="token punctuation">:</span> <span class="token string">'aplus.setMetaInfo'</span><span class="token punctuation">,</span> arguments<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'appId'</span><span class="token punctuation">,</span> <span class="token string">'your appid'</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 operator">/</span>script<span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>其他pv\uv相关埋点建议写成单独js文件需要的埋点的页面引入,在vue项目里直接写到vue实例里可能导致埋点不成功。</p><h3 id="接口调试"><a href="#接口调试" class="headerlink" title="接口调试"></a>接口调试</h3><p>调试 <code>JSBridge API</code>时,就需要用到上面提到的debug工具。调试的过程中手机浙里办app 需要全程在线才能一直连接调试、屏幕熄灭也会断开。<br>所有关于浙里办的 JSBridge API 的原生访问接口都需在真机或 浙里办app环境上测试; <em>浏览器是不行的</em>!通过登录政务应用平台,上传源代码后生成的二维码,可以手机扫码查看效果。在扫码之前确定项目里引入了JSBridge API 资源。</p><h3 id="二次回退问题"><a href="#二次回退问题" class="headerlink" title="二次回退问题"></a>二次回退问题</h3><p>我这里遇到的问题是 应用首页返回浙里办app时需要2次或者多次点击才可返回,解决方案:利用router.beforeEach 判断路由然后调用 政务api的close关闭接口.</p><h3 id="支付宝小程序测试问题"><a href="#支付宝小程序测试问题" class="headerlink" title="支付宝小程序测试问题"></a>支付宝小程序测试问题</h3><p>应用管理平台发布上线后生成的访问地址二维码是给浙里办APP用的!!!支付宝扫码访问需要自己去转换:(<a href="https://3pwls.csb.app/)">https://3pwls.csb.app/)</a> 在这个网页中输入你浙里办预览二维码的网址,然后转换成支付宝能识别的二维码就可以在支付宝中看效果了。<br>原理:其实就是浙里办的支付宝小程序内嵌了一个浏览器,用这个内嵌的浏览器就可以调用浙里办的JSBridge了。</p><h3 id="h5适老化"><a href="#h5适老化" class="headerlink" title="h5适老化"></a>h5适老化</h3><p>自建h5应用接入浙里办以后还需要‘适老化’版本的开发,所谓‘适老化’ 主要是适应于年龄稍微大点的长辈,也就是长辈版。适老化版本内容、功能要求和标准版一致,标准版下架后理应适老化版本也一同下架,应为一个系统应用。这里我是使用了两版路由实现了不同环境的版本切换。</p><h3 id="打包发布"><a href="#打包发布" class="headerlink" title="打包发布"></a>打包发布</h3><p>前端应用不需要打包,只需要将项目 <code>src static index.html package.json gbc.json .postcssrc.js .babelrc</code> 等资源依赖压缩为.zip的包 且不能大于40M,然后上传到 政务中台应用管理等编译通过后就自动生成二维码和链接可以查看测试版本了。<br>⭐⭐⭐这里我遇到了坑1:<br>之前公司前端开发好的h5应用使用的图片有部分是中文命名,结果windows系统打包zip压缩后中文乱码了,导致上传应用平台编译失败,而mac系统打包不会乱码!切记开发中不要使用中文命名!!!<br>⭐⭐⭐坑2:<br>单点登录时配置的回调地址在发布时需要提供给浙里办的工作人员进行配置,不然如果配置是测试回调地址,发布上线后扫码跳转的还是测试地址!</p><p>注意:浙里办测试环境会有调试按钮,发布线上环境后就没有了.</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>虽然整个项目最开始是懵逼和无奈的,过程是崎岖和痛苦的.但是完成的那一刻心里还是挺开心的!说实话东西没多难,但是我觉得初次接触一个新事物、新项目的时候还是得先整明白 是什么?干什么?完成什么? 只有清楚这些才能理清思路和步骤然后再去进阶完成目标。另外吐槽一下浙里办的技术支持,有一些问题回答的太官方! 甚至你问到一个不清楚的问题他会直接丢给你对接文档原链接!!! 还是挺无语的只能和同事探讨或者网上看看相关博客。也可能是因为我比较菜吧, 总之还是要微笑面对生活,要相信没有克服不了的困难! 加油!</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> 浙里办应用 h5 </category>
</categories>
<tags>
<tag> 浙里办对接 </tag>
<tag> 浙里办 </tag>
</tags>
</entry>
<entry>
<title>服务端相关问题</title>
<link href="/posts/b032.html"/>
<url>/posts/b032.html</url>
<content type="html"><![CDATA[<h2 id="关于服务请求-服务端部署等相关相关问题记录"><a href="#关于服务请求-服务端部署等相关相关问题记录" class="headerlink" title="关于服务请求,服务端部署等相关相关问题记录"></a>关于服务请求,服务端部署等相关相关问题记录</h2><h3 id="axios-相关"><a href="#axios-相关" class="headerlink" title="axios 相关"></a>axios 相关</h3><ul><li>请求头相关<br>axios 使用 post 发送数据时,默认是直接把 json 放到请求体中提交到后端的。<br>也就是说,我们的 <code>Content-Type</code> 变成了 <code>application/json;charset=utf-8</code> (注意结尾不要带分号;),这是 axios 默认的请求头 content-type 类型。</li></ul><p>post 请求常见的数据格式、请求头(content-type)<br><code>Content-Type: application/json</code>: 请求体中的数据会以 json 字符串的形式发送到后端 如: {a:123}<br><code>Content-Type: application/x-www-form-urlencoded</code>:请求体中的数据会以普通表单形式(键值对,k=v 写法)发送到后端 body 中:a=100<br><code>Content-Type: multipart/form-data</code>: 它会将请求体的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。</p><p>客户端解决 <code>Content-Type: multipart/form-data</code> 的数据类型传参 ?</p><pre class="line-numbers language-js"><code class="language-js"><span class="token comment" spellcheck="true">// 方式 formData</span><span class="token comment" spellcheck="true">/* FormData对象的使用: 用一些键值对来模拟一系列表单控件:即把form中所有的元素的name与value组成一个queryString。 异步上传二进制文件。 对于这种类型的数据,我们常见前端页面上传个人图像,然后点击保存发送后端修改原始数据 如下:*/</span><span class="token keyword">let</span> params <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><span class="token comment" spellcheck="true">// const name = params.get("userName") // 还可以获取</span>params<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"file"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span>params<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">,</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">"userID"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>params<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"userName"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>params<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"sex"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sex<span class="token punctuation">)</span><span class="token punctuation">;</span>params<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"email"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>email<span class="token punctuation">)</span><span class="token punctuation">;</span>params<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"qq"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>qq<span class="token punctuation">)</span><span class="token punctuation">;</span>axios <span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span>URL<span class="token punctuation">,</span> params<span class="token punctuation">,</span> <span class="token punctuation">{</span> headers<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"Content-Type"</span><span class="token punctuation">:</span> <span class="token string">"multipart/form-data"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><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>res<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>data<span class="token punctuation">.</span>code <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$router<span class="token punctuation">.</span><span class="token function">go</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"更新用户数据失败"</span> <span class="token operator">+</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>客户端解决 <code>application/x-www-form-urlencoded</code> 形式的传参?</p><pre class="line-numbers language-js"><code class="language-js"><span class="token comment" spellcheck="true">// 方式1: URLSearchParams</span><span class="token comment" spellcheck="true">// 需要注意的是: URLSearchParams 不支持所有的浏览器,但是总体的支持情况还是 OK 的,所以优先推荐这种简单直接的解决方案</span><span class="token keyword">let</span> param <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>param<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"username"</span><span class="token punctuation">,</span> <span class="token string">"admin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>param<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"pwd"</span><span class="token punctuation">,</span> <span class="token string">"admin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">axios</span><span class="token punctuation">(</span><span class="token punctuation">{</span> method<span class="token punctuation">:</span> <span class="token string">"post"</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> <span class="token string">"/api/lockServer/search"</span><span class="token punctuation">,</span> data<span class="token punctuation">:</span> param<span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// 方式2:qs 转换数据为key=value格式</span><span class="token comment" spellcheck="true">// 引入 qs ,这个库是 axios 里面包含的,不需要再下载。</span><span class="token keyword">import</span> Qs <span class="token keyword">from</span> <span class="token string">"qs"</span><span class="token punctuation">;</span><span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token punctuation">:</span> <span class="token string">"cc"</span><span class="token punctuation">,</span> psd<span class="token punctuation">:</span> <span class="token string">"123456"</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token function">axios</span><span class="token punctuation">(</span><span class="token punctuation">{</span> headers<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"Content-Type"</span><span class="token punctuation">:</span> <span class="token string">"application/x-www-form-urlencoded"</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> method<span class="token punctuation">:</span> <span class="token string">"post"</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> <span class="token string">"/api/lockServer/search"</span><span class="token punctuation">,</span> data<span class="token punctuation">:</span> Qs<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><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="部署服务器后遇到的问题记录"><a href="#部署服务器后遇到的问题记录" class="headerlink" title="部署服务器后遇到的问题记录"></a>部署服务器后遇到的问题记录</h3><ul><li>客户端代码部署服务器后代理访问接口未授权?<br>客户端代码请求了第三方服务接口,接口请求头添加了自定义请求头类似 <code>__s__</code> <code>__token__</code> <code>_token_</code>,浏览器里可以看到这些请求头,但是接口是服务端 nginx 代理,nginx 默认会过滤掉请求头包含 <code>_ 、 -</code> 的字段,导致这些参数消失请求失败。</li></ul><h3 id="node-服务部署服务器遇到问题"><a href="#node-服务部署服务器遇到问题" class="headerlink" title="node 服务部署服务器遇到问题"></a>node 服务部署服务器遇到问题</h3><ul><li>添加 5000 端口外网访问不到?<br>宝塔面板启动后,默认 linux 服务器防火墙开启了,需手动关闭防火墙</li></ul><blockquote><p>my 服务器配置<br>1vCPUs | 2GB<br>CentOS 8.2 64bit<br>命令:<br>查看防火状态<br><code>systemctl status firewalld</code><br>暂时关闭防火墙<br><code>systemctl stop firewalld</code><br>永久关闭防火墙<br><code>systemctl disable firewalld</code><br>重启防火墙<br><code>systemctl enable firewalld</code></p></blockquote><p>查看 5000 端口是否被监听<br><code>ss -nutlp | grep 5000</code></p><p><em>curl 使用</em><br>查看某地址是否可访问</p><blockquote><p>curl <a href="http://123.60.111.103:5000">http://123.60.111.103:5000</a><br>curl <a href="http://localhost:5000">http://localhost:5000</a></p></blockquote><ul><li>node 服务启动文件监听 ip?<br>node 服务启动文件 监听 ip 一定要写成 <code>0.0.0.0</code> 或者可以省略不写;由于我写成了 <code>127.0.0.0</code>导致部署服务器后访问失败!</li><li>一般外网无法访问服务器指定端口排查如下<br>排查服务商对应端口安全组是否开放?<br>排查服务器对应端口是否放行<br>排查服务器防火墙是否关闭</li><li>服务器使用 pm2<br>服务器使用 pm2 启动 node 服务失败<br>在云服务器上使用 pm2 管理 node 服务器进程,启动时失败。mysql 连接 host 为 localhost 时可以,换成服务器公网 ip 就不行了。排查后发现是因为服务器数据库权限没添加对应 ip!!</li><li>mysql 数据库自动关闭<br>解决 <code>nodejs的Connection lost: The server closed the connection</code><br>原因:mysql 自带一段时间无动作会自动关闭的机制<br>node 服务部署服务器后默认 8 小时不操作数据库会自动关闭,解决方法:使用连接池</li></ul><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> node 服务器 </category>
</categories>
<tags>
<tag> node服务 </tag>
<tag> axios </tag>
</tags>
</entry>
<entry>
<title>js常用方法</title>
<link href="/posts/7a45.html"/>
<url>/posts/7a45.html</url>
<content type="html"><![CDATA[<h2 id="记录-js-常用方法"><a href="#记录-js-常用方法" class="headerlink" title="记录 js 常用方法"></a>记录 js 常用方法</h2><h2 id="js-类型判断"><a href="#js-类型判断" class="headerlink" title="js 类型判断"></a>js 类型判断</h2><ul><li>Object.prototype.toString</li></ul><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token comment" spellcheck="true">// 以下是11种:</span><span class="token keyword">var</span> number <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object Number]</span><span class="token keyword">var</span> string <span class="token operator">=</span> <span class="token string">"123"</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object String]</span><span class="token keyword">var</span> boolean <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object Boolean]</span><span class="token keyword">var</span> und <span class="token operator">=</span> undefined<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object Undefined]</span><span class="token keyword">var</span> nul <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object Null]</span><span class="token keyword">var</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> a<span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object Object]</span><span class="token keyword">var</span> array <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object Array]</span><span class="token keyword">var</span> date <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 comment" spellcheck="true">// [object Date]</span><span class="token keyword">var</span> error <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object Error]</span><span class="token keyword">var</span> reg <span class="token operator">=</span> <span class="token regex">/a/g</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object RegExp]</span><span class="token keyword">var</span> func <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// [object Function]</span><span class="token keyword">function</span> <span class="token function">checkType</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arguments<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>toString<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>arguments<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token function">checkType</span><span class="token punctuation">(</span> number<span class="token punctuation">,</span> string<span class="token punctuation">,</span> boolean<span class="token punctuation">,</span> und<span class="token punctuation">,</span> nul<span class="token punctuation">,</span> obj<span class="token punctuation">,</span> array<span class="token punctuation">,</span> date<span class="token punctuation">,</span> error<span class="token punctuation">,</span> reg<span class="token punctuation">,</span> func<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="Object-对象"><a href="#Object-对象" class="headerlink" title="Object 对象"></a>Object 对象</h2><ul><li>Object.defineProperty(obj,prop,descriptor)<br>vue2.0 数据劫持就是使用此方法</li><li>hasOwnProperty()<blockquote><p>判断对象自身属性中是否具有指定的属性。<br>obj.hasOwnProperty(‘name’)</p></blockquote></li><li>Object.is()<blockquote><p>判断两个值是否相对返回布尔值</p></blockquote></li><li>Object.keys()、Object.values()<blockquote><p>方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for…in 循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )</p></blockquote></li><li>Object.freeze()<blockquote><p>冻结一个对象,阻止修改现有属性特性的值,并阻止添加新属性</p></blockquote></li><li>Object.assign(target,source1,source2,…)<br>对象合并</li></ul><h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><ul><li>slice() 截取数组,不改变原数组</li><li>splice() 更新数组,改变原数组</li><li>forEach()、map()、filter()、some()、every() 迭代方法,不改变原数组</li><li>every</li></ul><blockquote><p>arr.every((currentValue , index , arr) => {}, thisValue) 判断数组中的每一项是否都满足条件,全部符合就会返回 true,否则 false。</p></blockquote><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">const</span> str <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span><span class="token punctuation">(</span>currentValue<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> currentValue <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// false</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>some</li></ul><blockquote><p>判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回 true,不再往下执行</p></blockquote><pre class="line-numbers language-javascript"><code class="language-javascript">arr<span class="token punctuation">.</span><span class="token function">some</span><span class="token punctuation">(</span><span class="token punctuation">(</span>currentValue<span class="token punctuation">,</span> index<span class="token punctuation">,</span> arr<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> thisValue<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">const</span> str <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">some</span><span class="token punctuation">(</span><span class="token punctuation">(</span>currentValue<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>currentValue<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> currentValue <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// 1</span><span class="token comment" spellcheck="true">// 2</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// true</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>keys()、values()、entries() 遍历数组方法,不改变原数组。 (es6 新增方法)</li></ul><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token string">"b"</span><span class="token punctuation">,</span> <span class="token string">"c"</span><span class="token punctuation">,</span> <span class="token string">"d"</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token keyword">of</span> arr<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment" spellcheck="true">//打印:</span><span class="token comment" spellcheck="true">// [0, "a"]</span><span class="token comment" spellcheck="true">// [1, "b"]</span><span class="token comment" spellcheck="true">// [2, "c"]</span><span class="token comment" spellcheck="true">// [3, "d"]</span><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">[</span>idx<span class="token punctuation">,</span> item<span class="token punctuation">]</span> <span class="token keyword">of</span> arr<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>idx <span class="token operator">+</span> <span class="token string">":"</span> <span class="token operator">+</span> item<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment" spellcheck="true">//打印:</span><span class="token comment" spellcheck="true">// 0:a</span><span class="token comment" spellcheck="true">// 1:b</span><span class="token comment" spellcheck="true">// 2:c</span><span class="token comment" spellcheck="true">// 3:d</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>Array.from() (es6 新增方法)</li></ul><blockquote><p>Array.from() 用于类似数组的对象(即有 length 属性的对象)和可遍历对象转为真正的数组。</p></blockquote><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token keyword">const</span> json <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token number">0</span><span class="token punctuation">:</span> <span class="token string">"喜"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">:</span> <span class="token string">"欢"</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">:</span> <span class="token string">"你"</span><span class="token punctuation">,</span> length<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token keyword">const</span> arr <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token keyword">from</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// ["喜", "欢", "你"]</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>includes() 不改变原数组。 (es6 新增方法)</li></ul><blockquote><p>arr.includes(searchElement , fromIndex) 用来判断一个数组是否包含一个指定的值,如果是返回 true,否则 false。</p></blockquote><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token string">"b"</span><span class="token punctuation">,</span> <span class="token string">"c"</span><span class="token punctuation">,</span> <span class="token string">"d"</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">const</span> result1 <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"b"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> result2 <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"b"</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> result3 <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"b"</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> result4 <span class="token operator">=</span> arr<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"b"</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// true</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// false</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result3<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// flase</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// true</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>reduce()、reduceRight() 归并方法,不改变原数组<br>这两个方法都会迭代数组中的所有项,然后生成一个最终返回值。他们都接收两个参数,第一个参数是每一项调用的函数,函数接受四个参数分别是初始值,当前值,索引值,和当前数组,函数需要返回一个值,这个值会在下一次迭代中作为初始值。第二个参数是迭代初始值,参数可选,如果缺省,初始值为数组第一项,从数组第一个项开始叠加,缺省参数要比正常传值少一次运算。<br>[total] 必须项,初始值, 或者计算结束后的返回值。<br>[cur] 必须项,当前元素。<br>[index] 可选。当前元素的索引值<br>[arr] 可选。当前元素所属的数组对象<br>[initialValue] 可选。传递给函数的初始值。</li></ul><blockquote><p>arr.reduce((total , cur , index , arr) => {}, initialValue) 从数组的第一项开始,逐个遍历到最后<br>arr.reduceRight((total , cur , index , arr) => {}, initialValue) 从数组的最后一项开始,向前遍历到第一项</p></blockquote><h2 id="ES2017-ES8"><a href="#ES2017-ES8" class="headerlink" title="ES2017(ES8)"></a>ES2017(ES8)</h2><ul><li>Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组。</li></ul><pre class="line-numbers language-javaScript"><code class="language-javaScript"> const obj = { name: "jimmy", age: 18, height: 188,};console.log(Object.entries(obj)); // [ [ 'name', 'jimmy' ], [ 'age', 18 ], [ 'height', 188 ] ]console.log(Object.entries([1, 2, 3])); // [ [ '0', 1 ], [ '1', 2 ], [ '2', 3 ] ]<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>String.prototype.padStart<br>把指定字符串填充到字符串头部,返回新字符串。</li></ul><pre class="line-numbers language-javaScript"><code class="language-javaScript">'abc'.padStart(10); // " abc"'abc'.padStart(10, "foo"); // "foofoofabc"'abc'.padStart(6,"123465"); // "123abc"'abc'.padStart(8, "0"); // "00000abc"'abc'.padStart(1); // "abc"// 应用场景:// 数字替换(手机号,银行卡号等)const tel = '18781268679'const newTel = tel.slice(-4).padStart(tel.length, '*')console.log(newTel) // *******5678<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="ES2018-ES9"><a href="#ES2018-ES9" class="headerlink" title="ES2018(ES9)"></a>ES2018(ES9)</h2><ul><li>Object Rest<br>Object rest 的示例:</li></ul><pre class="line-numbers language-javaScript"><code class="language-javaScript">const input = { a: 1, b: 2, c: 3}let { a, ...rest } = inputconsole.log(a, rest) // 1 {b: 2, c: 3}// 当对象 key-value 不确定的时候,把必选的 key 赋值给变量,用一个变量收敛其他可选的 key 数据,这在之前是做不到的。注意,rest 属性必须始终出现在对象的末尾,否则将抛出错误。<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>for await of<br>异步迭代器(for-await-of):循环等待每个 Promise 对象变为 resolved 状态才进入下一步。</li></ul><p>我们知道 for…of 是同步运行的,看如下代码</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">function TimeOut(time){ return new Promise(function(resolve, reject) { setTimeout(function() { resolve(time) }, time) })}async function test() { let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)] for (let item of arr) { console.log(Date.now(),item.then(console.log)) }}test()// 上述代码证实了 for of 方法不能遍历异步迭代器,得到的结果并不是我们所期待的,于是 for await of 就粉墨登场啦!// ES9 中可以用 for...await...of 的语法来操作function TimeOut(time) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(time) }, time) })}async function test() { let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)] for await (let item of arr) { console.log(Date.now(), item) }}test()// 1560092345730 2000// 1560092345730 1000// 1560092346336 3000// for await of 环等待每个Promise对象变为resolved状态才进入下一步。所有打印的结果为 2000,1000,3000<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>Promise.prototype.finally()<br>Promise.prototype.finally() 方法返回一个 Promise,在 promise 执行结束时,无论结果是 fulfilled 或者是 rejected,在执行 then()和 catch()后,都会执行 finally 指定的回调函数。这为指定执行完 promise 后,无论结果是 fulfilled 还是 rejected 都需要执行的代码提供了一种方式,避免同样的语句需要在 then()和 catch()中各写一次的情况。</li></ul><pre class="line-numbers language-javaScript"><code class="language-javaScript">new Promise((resolve, reject) => { setTimeout(() => { resolve('success') // reject('fail') }, 1000)}).then(res => { console.log(res)}).catch(err => { console.log(err)}).finally(() => { console.log('finally')})// 使用场景// loading关闭// 需要每次发送请求,都会有loading提示,请求发送完毕,就需要关闭loading提示框,不然界面就无法被点击。不管请求成功或是失败,这个loading都需要关闭掉,这时把关闭loading的代码写在finally里再合适不过了<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="ES2019-ES10"><a href="#ES2019-ES10" class="headerlink" title="ES2019(ES10)"></a>ES2019(ES10)</h2><p>*Object.fromEntries()<br>方法 Object.fromEntries() 把键值对列表转换为一个对象,这个方法是和 Object.entries() 相对的。</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">Object.fromEntries([ ['foo', 1], ['bar', 2]])// {foo: 1, bar: 2}// 案例1:Object 转换操作const obj = { name: 'jimmy', age: 18}const entries = Object.entries(obj)console.log(entries)// [Array(2), Array(2)]// ES10const fromEntries = Object.fromEntries(entries)console.log(fromEntries)// {name: "jimmy", age: 18}// 案例2:Map 转 Objectconst map = new Map()map.set('name', 'jimmy')map.set('age', 18)console.log(map) // {'name' => 'jimmy', 'age' => 18}const obj = Object.fromEntries(map)console.log(obj)// {name: "jimmy", age: 18}// 案例3:过滤// course表示所有课程,想请求课程分数大于80的课程组成的对象:const course = { math: 80, english: 85, chinese: 90}const res = Object.entries(course).filter(([key, val]) => val > 80)console.log(res) // [ [ 'english', 85 ], [ 'chinese', 90 ] ]console.log(Object.fromEntries(res)) // { english: 85, chinese: 90 }// 案例4:url的search参数转换// let url = "https://www.baidu.com?name=jimmy&age=18&height=1.88"// queryString 为 window.location.searchconst queryString = "?name=jimmy&age=18&height=1.88";const queryParams = new URLSearchParams(queryString);const paramObj = Object.fromEntries(queryParams);console.log(paramObj); // { name: 'jimmy', age: '18', height: '1.88' }<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>*Array.prototype.flat()<br>let newArray = arr.flat([depth])<br>depth 可选 指定要提取嵌套数组的结构深度,默认值为 1。<br>flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">const arr1 = [0, 1, 2, [3, 4]];console.log(arr1.flat()); // [0, 1, 2, 3, 4]const arr2 = [0, 1, 2, [[[3, 4]]]];console.log(arr2.flat(2)); // [0, 1, 2, [3, 4]]//使用 Infinity,可展开任意深度的嵌套数组var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]// `flat()` 方法会移除数组中的空项:var arr5 = [1, 2, , 4, 5];arr5.flat(); // [1, 2, 4, 5]<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>*Array.prototype.flatMap()<br>flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。从方法的名字上也可以看出来它包含两部分功能一个是 map,一个是 flat(深度为 1)。</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">const numbers = [1, 2, 3]numbers.map(x => [x * 2]) // [[2], [4], [6]]numbers.flatMap(x => [x * 2]) // [2, 4, 6]// 这个示例可以简单对比下 map 和 flatMap 的区别。当然还可以看下下面的示例:let arr = ['今天天气不错', '', '早上好']arr.map(s => s.split(''))// [["今", "天", "天", "气", "不", "错"],[""],["早", "上", "好"]]arr.flatMap(s => s.split(''))// ["今", "天", "天", "气", "不", "错", "", "早", "上", "好"]// flatMap 方法与 map 方法和深度depth为1的 flat 几乎相同.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>*String.prototype.trimStart()<br>trimStart() 方法从字符串的开头删除空格,trimLeft()是此方法的别名。</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">let str = ' foo 'console.log(str.length) // 8str = str.trimStart() // 或str.trimLeft()console.log(str.length) // 5<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>*可选的 Catch Binding<br>在 ES10 之前我们都是这样捕获异常的:</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">try { // tryCode} catch (err) { // catchCode}// 在这里 err 是必须的参数,在 ES10 可以省略这个参数:try { console.log('Foobar')} catch { console.error('Bar')}// 应用// 验证参数是否为json格式// 这个需求我们只需要返回true或false,并不关心catch的参数。const validJSON = json => { try { JSON.parse(json) return true } catch { return false }}<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="ES2020-ES11"><a href="#ES2020-ES11" class="headerlink" title="ES2020(ES11)"></a>ES2020(ES11)</h2><p>*可选链操作符( ?. )<br>?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为 null 或者 undefined 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。<br>*空值合并运算符(Nullish coalescing Operator)<br>空值合并操作符( ?? )是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。</p><pre class="line-numbers language-js"><code class="language-js">与空值合并操作符一起使用<span class="token punctuation">;</span><span class="token keyword">let</span> customer <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> <span class="token string">"jimmy"</span><span class="token punctuation">,</span> details<span class="token punctuation">:</span> <span class="token punctuation">{</span> age<span class="token punctuation">:</span> <span class="token number">18</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token keyword">let</span> customerCity <span class="token operator">=</span> customer<span class="token operator">?</span><span class="token punctuation">.</span>city <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">"成都"</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>customerCity<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// "成都"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><pre class="line-numbers language-javaScript"><code class="language-javaScript">const foo = undefined ?? "foo"const bar = null ?? "bar"console.log(foo) // fooconsole.log(bar) // bar<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>*Promise.allSettled()<br>我们都知道 Promise.all() 具有并发执行异步任务的能力。但它的最大问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,Promise 直接进入 reject 状态。</p><p>场景:现在页面上有三个请求,分别请求不同的数据,如果一个接口服务异常,整个都是失败的,都无法渲染出数据</p><p>我们需要一种机制,如果并发任务中,无论一个任务正常或者异常,都会返回对应的的状态,这就是 Promise.allSettled 的作用</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">const promise1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve("promise1"); // reject("error promise1 "); }, 3000); });};const promise2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve("promise2"); // reject("error promise2 "); }, 1000); });};const promise3 = () => { return new Promise((resolve, reject) => { setTimeout(() => { // resolve("promise3"); reject("error promise3 "); }, 2000); });};// Promise.all 会走到catch里面Promise.all([promise1(), promise2(), promise3()]) .then((res) => { console.log(res); }) .catch((error) => { console.log("error", error); // error promise3 });// Promise.allSettled 不管有没有错误,三个的状态都会返回Promise.allSettled([promise1(), promise2(), promise3()]) .then((res) => { console.log(res); // 打印结果 // [ // {status: 'fulfilled', value: 'promise1'}, // {status: 'fulfilled',value: 'promise2'}, // {status: 'rejected', reason: 'error promise3 '} // ] }) .catch((error) => { console.log("error", error); });<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>*import()可以在需要的时候,再加载某个模块。</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">button.addEventListener('click', event => { import('./dialogBox.js') .then(dialogBox => { dialogBox.open(); }) .catch(error => { /* Error handling */ })});<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="ES2021-ES12"><a href="#ES2021-ES12" class="headerlink" title="ES2021(ES12)"></a>ES2021(ES12)</h2><p>*&&=</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">// 逻辑与赋值 x &&= y等效于:x && (x = y);// 上面的意思是,当x为真时,x=y。// 具体请看下面的示例:let a = 1;let b = 0;a &&= 2;console.log(a); // 2b &&= 2;console.log(b); // 0<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>*||=</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">逻辑或赋值(x ||= y)运算仅在 x 为false时赋值。x ||= y 等同于: x || (x = y);const a = { duration: 50, title: '' };a.duration ||= 10;console.log(a.duration); // 50a.title ||= 'title is empty.';console.log(a.title); // "title is empty"<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>*??=</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">逻辑空赋值运算符 (x ??= y) 仅在 x 是 nullish[3] (null 或 undefined) 时对其赋值。x ??= y 等价于:x ?? (x = y);const a = { duration: 50 };a.duration ??= 10;console.log(a.duration); // 50a.speed ??= 25;console.log(a.speed); // 25function config(options) { options.duration ??= 100; options.speed ??= 25; return options;}config({ duration: 125 }); // { duration: 125, speed: 25 }config({}); // { duration: 100, speed: 25 }<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>*String.prototype.replaceAll()<br>replaceAll() 方法返回一个新字符串,新字符串中所有满足 pattern 的部分都会被 replacement 替换。pattern 可以是一个字符串或一个 RegExp,replacement 可以是一个字符串或一个在每次匹配被调用的函数。</p><p>原始字符串保持不变。</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">'aabbcc'.replaceAll('b', '.'); // 'aa..cc'// 使用正则表达式搜索值时,它必须是全局的。// 'aabbcc'.replaceAll(/b/, '.');// TypeError: replaceAll must be called with a global RegExp这将可以正常运行:'aabbcc'.replaceAll(/b/g, '.');"aa..cc"<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>*Promise.any<br>方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">const promise1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve("promise1"); // reject("error promise1 "); }, 3000); });};const promise2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve("promise2"); // reject("error promise2 "); }, 1000); });};const promise3 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve("promise3"); // reject("error promise3 "); }, 2000); });};Promise.any([promise1(), promise2(), promise3()]) .then((first) => { // 只要有一个请求成功 就会返回第一个请求成功的 console.log(first); // 会返回promise2 }) .catch((error) => { // 所有三个全部请求失败 才会来到这里 console.log("error", error); });只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><!-- *```javaScript``` --><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<tags>
<tag> js </tag>
</tags>
</entry>
<entry>
<title>js相关</title>
<link href="/posts/e9a0.html"/>
<url>/posts/e9a0.html</url>
<content type="html"><![CDATA[<h2 id="为什么使用es6的class类"><a href="#为什么使用es6的class类" class="headerlink" title="为什么使用es6的class类"></a>为什么使用es6的class类</h2><p>OOP 即 面向对象编程 (Object Oriented Programming)<br>ES6 开始引入class的概念。实际上,JavaScript 中class的本质也是基于原型prototype的实现方式作了进一步的封装,其本质还是函数function。虽说如此,class和function还是有不同之处。<br><strong>优点</strong>:<br>使用class实现功能完全不用关心原型链和this会带来什么问题。this就是实例本身,可以专注的在内部进行维护开发,只用暴露方法给外部使用即可。<br>当一个功能足够单纯就完全可以用函数来实现,函数的通用性更强。因为就一个功能。class就好比,一个功能的集合,在里面可以对函数调用,可以使用this对内部状态和数据进行操作。</p><h2 id="js-DOM事件流"><a href="#js-DOM事件流" class="headerlink" title="js-DOM事件流"></a>js-DOM事件流</h2><p>事件发生时,会在元素节点之间按照特定的顺序传播,这个传播过程既‘DOM事件流’</p><ul><li>事件传播三个阶段<br>w3c将 事件传播 分成3个阶段:<br>捕获:从最外层祖先元素向目标元素进行捕获此时不会触发事件<br>目标:事件捕获到目标元素,捕获结束,开始在目标元素上触发事件<br>冒泡:事件从目标元素向他的祖先传递,依次触发祖先元素身上的事件</li><li>事件捕获<br>从外向里,一般情况下不会使用捕获阶段执行事件</li></ul><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token function">addEventListener</span><span class="token punctuation">(</span>‘click’<span class="token punctuation">,</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>第三个参数默认false 冒泡阶段</p><ul><li>事件冒泡(事件默认是冒泡阶段)<br>事件默认是冒泡阶段</li><li>事件委托概念<br>利用事件冒泡机制实现事件委托,提供代码执行性能</li></ul><h2 id="数据类型-amp-隐式转换"><a href="#数据类型-amp-隐式转换" class="headerlink" title="数据类型&隐式转换"></a>数据类型&隐式转换</h2><ul><li><p>js数据类型分为基础类型和引用类型<br>原始类型(基本类型):undefined、null、boolean、number、string<br>引用类型(复杂类型):object</p></li><li><p>typeof 检测数据类型</p><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token keyword">typeof</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// object 为什么不是null js历史遗留的一个bug</span><span class="token keyword">typeof</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// object</span><span class="token keyword">typeof</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// object</span><span class="token keyword">typeof</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// function</span><span class="token keyword">typeof</span><span class="token punctuation">(</span>Array<span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// function 为什么不是object</span><span class="token comment" spellcheck="true">//js在设计时在引用类型内部方法[[call]] 方法, typeof 检测引用类型时看引用类型上有没有 [[call]] 方法,有返回 function, 没有返回 object</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>instanceof<br>A 对象是否是 B 对象实例化后的对象</p><pre class="line-numbers language-javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token keyword">instanceof</span> <span class="token class-name">Array</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// true</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token keyword">instanceof</span> <span class="token class-name">Object</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// true</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token keyword">instanceof</span> <span class="token class-name">Object</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// true 为什么?</span><span class="token comment" spellcheck="true">// 因为 instanceof 是顺着原型链去检测的</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>除了typeof方法,检测数据类型方法</p><pre class="line-numbers language-javascript"><code class="language-javascript">Object<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>toString<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">'1'</span><span class="token punctuation">)</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>toString<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">'1'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// string</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>toString<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// Array</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></li><li><p>特殊类型的隐式转换<br>5种: NaN、0、undefined、null、”” => false / true<br>栗子:</p><pre class="line-numbers language-javascript"><code class="language-javascript"> <span class="token keyword">if</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// 如果val 为以上5种时隐式转换为 false</span> <span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 应该改为:</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>val<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span> <span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><h2 id="开发中一些概念"><a href="#开发中一些概念" class="headerlink" title="开发中一些概念"></a>开发中一些概念</h2><ul><li>重载和多态?<br>重载的概念: 在程序中可以定义相同的名字,不同参数形式的不同函数。调用函数时,自动识别不同参数对应的函数,实现了相同函数名,不同的函数调用。<br>js本身是没有重载的,但是可以通过arguments实现函数重载。根据参数不同返回不同结果,执行不同逻辑。很多框架底层源码就是这样实现重载的。<br>多态:同一个东西在不同情况下的表现不同状态。</li></ul><h2 id="js进阶概念"><a href="#js进阶概念" class="headerlink" title="js进阶概念"></a>js进阶概念</h2><ul><li>深、浅拷贝有那些方式?<br>概念: 假设B复制了A,当修改A时,看B是否发生变化,如果变化则是浅拷贝;如果B不变则是深拷贝。<br>浅拷贝常用:<br><code>for in 遍历</code> for in 目标对象取出key 创建新对象<br><code>Object.creat()</code> 会复制到<strong>proto</strong>原型上<br>深拷贝常用:<br><code>JSON.parse(JSON.stringify(obj))</code></li><li>什么是闭包?<br>函数和其周围的状态的引用捆绑在一起形成闭包<br>可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域的成员。<br>闭包的本质:<br>函数在执行的时候会被放到一个执行栈上,当函数执行完毕后会从执行栈上移除。但是堆上的作用域成员因为被外部引用不能释放,因此内部函数依然可以访问外部函数的成员。<br>闭包的好处是:延长了外部函数他内部变量的作用范围。</li><li>什么的高阶函数?<br>可以把函数当作参数传递给另外一个函数<br>可以把函数当作另一个函数的返回结果<br>常用高阶函数:<br>ForEach、map、filter、some、reduce、stor、</li><li>什么是纯函数?<br>相同的输入永远会得到相同的输出,而且没有任何可观察的副作用</li></ul><!-- 什么是副作用: --><p>slice:返回数组中的指定部分,不会改变原数组 —纯函数<br>Splice: 对数组进行操作返回该数组,会改变原数组 —非纯函数</p><ul><li>什么是函数柯里化?<br>当一个函数有多个参数时,先传递一部分参数调用他(这部分参数以后永远不变)<br>然后返回一个新的函数接收剩余的参数,返回结果。<br>总结:<br>1、柯里化可以让我们给一个函数传递较少参数得到一个已经记住了某些固定参数的新函数<br>2、这是一种对函数参数的缓存<br>3、让函数变的更灵活,让函数的粒度更小<br>4、可以把多元函数转化为一元函数,可以组合使用函数产生强大的功能</li><li>什么是函数组合?<br>如果一个函数要经过多个函的处理才能得到最终值,这个时候可以把中间过程的函数合并成一个函数。这些中间函数会相应得到中间结果这些结果我们不需要关注。函数组合默认是从右到左执行的。</li></ul><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> javaScript </category>
</categories>
<tags>
<tag> 个人 </tag>
<tag> js </tag>
</tags>
</entry>
<entry>
<title>vue2源码探秘</title>
<link href="/posts/9108.html"/>
<url>/posts/9108.html</url>
<content type="html"><![CDATA[<h1 id="vue2-0-实现原理探秘"><a href="#vue2-0-实现原理探秘" class="headerlink" title="vue2.0 实现原理探秘"></a>vue2.0 实现原理探秘</h1><h2 id="vue底层渲染过程大致可以分成4个阶段:"><a href="#vue底层渲染过程大致可以分成4个阶段:" class="headerlink" title="vue底层渲染过程大致可以分成4个阶段:"></a>vue底层渲染过程大致可以分成4个阶段:</h2><ul><li>template 模板解析后生成AST语法树<br>模板解析:通过正则等方式提取出 <code><template></template></code> 模板里的标签元素、属性、变量等信息,并解析成抽象语法树 AST</li><li>AST树解析生成对应的render函数:<br>AST是Abstract Syntax Tree的简称,Vue使用HTML的Parser将HTML模板解析为<strong>AST语法树</strong>,并且对AST进行一些优化的标记处理,提取最大的静态树,方便Virtual DOM时直接跳过Diff。</li><li>数据通过render函数(渲染函数)解析生成VNode<br>Virtual DOM:虚拟DOM树,Vue的Virtual DOM Patching算法是基于 <code>Snabbdom</code>库的实现,并在些基础上作了很多的调整和改进。</li><li>VNode经过diff和patch后生成真实DOM展示</li></ul><h2 id="核心概念"><a href="#核心概念" class="headerlink" title="核心概念"></a>核心概念</h2><h3 id="虚拟dom"><a href="#虚拟dom" class="headerlink" title="虚拟dom"></a>虚拟dom</h3><p>用js模拟dom结构,计算最小变更,操作dom</p><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string">"div1"</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"container"</span> style<span class="token operator">=</span><span class="token string">"color: red"</span><span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span>vdom<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>ul style<span class="token operator">=</span><span class="token string">"font-size: 20px"</span><span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span>a<span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>ul<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span>js描述如下:<span class="token punctuation">{</span> tag<span class="token punctuation">:</span> <span class="token string">'div'</span><span class="token punctuation">,</span> sel<span class="token punctuation">:</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token string">'div1'</span><span class="token punctuation">,</span> className<span class="token punctuation">:</span> <span class="token string">'container'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> props<span class="token punctuation">:</span> <span class="token punctuation">{</span> style<span class="token punctuation">:</span> <span class="token string">'color: red'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> children<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> tag<span class="token punctuation">:</span> <span class="token string">'p'</span><span class="token punctuation">,</span> children<span class="token punctuation">:</span> <span class="token string">'vdom'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> tag<span class="token punctuation">:</span> <span class="token string">'ul'</span><span class="token punctuation">,</span> props<span class="token punctuation">:</span> <span class="token punctuation">{</span> style<span class="token punctuation">:</span> <span class="token string">'font-size: 20px'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> children<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> tag<span class="token punctuation">:</span> <span class="token string">'li'</span><span class="token punctuation">,</span> children<span class="token punctuation">:</span> <span class="token string">'a'</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="vue中-diff算法"><a href="#vue中-diff算法" class="headerlink" title="vue中 diff算法"></a>vue中 diff算法</h3><p>只比较同一层级,不跨级比较。<br>tag不相同,直接删除重建,不做再深度比较。<br>tag和key相同,认为是同一节点,不做再深度比较。</p><ul><li>最小量更新,key很重要是节点的唯一标识,在更改前后告诉diff他是同一节点</li><li>只有是同一个虚拟节点才进行精细化比较,否则就暴力删除旧的插入新的,<br>同一虚拟节点?选择器相同,且key相同</li><li>只进行同层比较,不进行跨层级比较。<br>即使是同一片虚拟节点, 跨层了也不会进行diff 暴力删除旧的插入新的</li></ul><h3 id="vue中的-render函数"><a href="#vue中的-render函数" class="headerlink" title="vue中的 render函数"></a>vue中的 render函数</h3><ul><li>什么是render函数?<br>vue中在一些复杂场景下使用template模板不太方便,例如需要引入大量子组件时,使用template模板会使代码重复冗余,这时用render函数就可以轻松解决问题,而用render函数构建DOM,vue也免了去转译的过程。<br>在vue中我们使用模板HTML语法组建页面的,使用render函数我们可以用js语言来构建DOM。</li><li>render函数作用?<br>生成虚拟DOM<br>当使用render函数描述虚拟DOM时,vue提供一个函数,这个函数是就构建虚拟DOM所需要的工具。官网上给他起了个名字叫 <code>createElement</code> 还有约定的简写叫 <code>h</code>, vm中有一个方法 <code>_c</code>,也是这个函数的别名。</li><li><code>render</code>函数的使用<br>比如说我们需要写很多 if 判断的时候</li></ul><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token operator"><</span>template<span class="token operator">></span> <span class="token operator"><</span>h1 v<span class="token operator">-</span><span class="token keyword">if</span><span class="token operator">=</span><span class="token string">"level === 1"</span><span class="token operator">></span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string">"xxx"</span><span class="token operator">></span> <span class="token operator"><</span>slot<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>slot<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>h2 v<span class="token operator">-</span><span class="token keyword">else</span><span class="token operator">-</span><span class="token keyword">if</span><span class="token operator">=</span><span class="token string">"level === 2"</span><span class="token operator">></span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string">"xxx"</span><span class="token operator">></span> <span class="token operator"><</span>slot<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>slot<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span>h3 v<span class="token operator">-</span><span class="token keyword">else</span><span class="token operator">-</span><span class="token keyword">if</span><span class="token operator">=</span><span class="token string">"level === 3"</span><span class="token operator">></span> <span class="token operator"><</span>a href<span class="token operator">=</span><span class="token string">"xxx"</span><span class="token operator">></span> <span class="token operator"><</span>slot<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>slot<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>template<span class="token operator">></span><span class="token operator"><</span>script<span class="token operator">></span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> props<span class="token punctuation">:</span><span class="token punctuation">[</span><span class="token string">'level'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>直接写 render</p><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token operator"><</span>script<span class="token operator">></span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> props<span class="token punctuation">:</span><span class="token punctuation">[</span><span class="token string">'level'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token function">render</span><span class="token punctuation">(</span>h<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'h'</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>level<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</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 operator">/</span>script<span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="数组数据响应式的处理原理"><a href="#数组数据响应式的处理原理" class="headerlink" title="数组数据响应式的处理原理"></a>数组数据响应式的处理原理</h3><p>重新数组方法,以 <code>Arrap.prototype</code>为原型创建了一个 <code>arrayMethods</code>的对象,在使用 <code>es6</code>的一个强硬的方法 <code>object.setPrototytypeOf(o,arrayMethods)</code>,让数组的<strong>proto</strong>指向 <code>arrayMethods</code></p><h2 id="vue2-0-源码地址"><a href="#vue2-0-源码地址" class="headerlink" title="vue2.0 源码地址"></a>vue2.0 源码地址</h2><ul><li>项目地址:<a href="https://github.com/vuejs/vue">https://github.com/vuejs/vue</a></li><li>文件结构核心部分</li></ul><pre><code>src compiler 编译器相关 core 核心代码 components 通用组件,如 keep-alive global-api 全局 api,如$set、$delete instance 构造函数等 observer 响应式相关 util vdom 虚拟 dom</code></pre><h2 id="vue2响应式原理-底层源码核心类"><a href="#vue2响应式原理-底层源码核心类" class="headerlink" title="vue2响应式原理-底层源码核心类"></a>vue2响应式原理-底层源码核心类</h2><p>栗子:</p><pre class="line-numbers language-javascript"><code class="language-javascript"><span class="token operator"><</span>div id<span class="token operator">=</span><span class="token string">"mvvm-app"</span><span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> v<span class="token operator">-</span>model<span class="token operator">=</span><span class="token string">"word"</span><span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span>word<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>button v<span class="token operator">-</span>on<span class="token punctuation">:</span>click<span class="token operator">=</span><span class="token string">"sayHi"</span><span class="token operator">></span>change model<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token comment" spellcheck="true">//点击这个button,word的值会发生改变</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string">"./js/observer.js"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string">"./js/watcher.js"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string">"./js/compile.js"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string">"./js/mvvm.js"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><span class="token operator"><</span>script<span class="token operator">></span> <span class="token keyword">var</span> vm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MVVM</span><span class="token punctuation">(</span><span class="token punctuation">{</span> el<span class="token punctuation">:</span> <span class="token string">'#mvvm-app'</span><span class="token punctuation">,</span> data<span class="token punctuation">:</span> <span class="token punctuation">{</span> word<span class="token punctuation">:</span> <span class="token string">'Hello World!'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> methods<span class="token punctuation">:</span> <span class="token punctuation">{</span> sayHi<span class="token punctuation">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>word <span class="token operator">=</span> <span class="token string">'Hi, everybody!'</span><span class="token punctuation">;</span> <span class="token punctuation">}</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 operator">/</span>script<span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>实现这种数据双向绑定的效果,需要以下几大模块:</p><ul><li><code>Compile -模板编译</code>:对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数.<br>Compile主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的<em>观察者watcher</em>,将来一旦数据有变动,收到通知触发回调函数进行更新视图。</li><li><code>Observer -数据劫持</code>:能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者.<br>Observer的核心是通过Obeject.defineProperty()来监听数据的变动,这个函数内部可以定义setter和getter,每当数据发生变化,就会触发setter。这时候Observer就要通知订阅者,订阅者就是Watcher。<br>get里: 初始化订阅数据变化时 往dep里添加观察者与其关联<br>set里: 通知;数据发生变化时dep去通知<em>观察者watcher</em></li><li><code>dep类 -发布者</code>:<br>作用:收集对应<em>观察者watcher*、通知watcher更新。<br>有多少属性dep里就有多少个watcher<br>*订阅:addSub()</em><br><em>发布:notify()</em></li><li><code>Watcher -观察者(订阅者)</code>:作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,在更改数据时进行watcher监听,把新值callback。</li></ul><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> vue2 </category>
</categories>
<tags>
<tag> vue2源码 </tag>
</tags>
</entry>
<entry>
<title>ts入门</title>
<link href="/posts/4d03.html"/>
<url>/posts/4d03.html</url>
<content type="html"><![CDATA[<h1 id="什么是typeScript"><a href="#什么是typeScript" class="headerlink" title="什么是typeScript?"></a>什么是typeScript?</h1><p>官方网站的定义是:TypeScript 是 js 类型的超集。简单说你可以将 TypeScript 看作是 JavaScript 之上的一个外壳。<br>TypeScript 是一个外壳,因为编写 TypeScript 的代码,在编译之后,,剩下的只是简单的 js 代码。<br>但是 JS 引擎无法读取 TypeScript 代码,因此任何 TypeScript 文件都应该经过预翻译过程,即编译。只有在第一个编译步骤之后,才剩下纯 JS 代码,可以在浏览器中运行。<br>Ps: 浏览器只能运行js、无法直接运行ts,因此需要ts编译js后运行。</p><pre class="line-numbers language-bash"><code class="language-bash">全局安装<span class="token function">npm</span> i -g typescript查看版本tsc -v运行tstsc xxx.ts<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="开发运行环境"><a href="#开发运行环境" class="headerlink" title="开发运行环境"></a>开发运行环境</h2><p><strong>因为ts代码不能直接在node里运行 需要先编译为js再执行</strong></p><ul><li>运行方式1:</li></ul><pre class="line-numbers language-bash"><code class="language-bash">tsc a.ts <span class="token operator">=</span><span class="token operator">></span> 编译为 a.jsnode a.js<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><ul><li>运行方式2:<br>如上操作每次执行很麻烦, (这个依赖包会在内部把ts编译为js,不再输出js文件)</li></ul><pre class="line-numbers language-bash"><code class="language-bash">全局安装 <span class="token function">npm</span> i -g ts-node查看版本好 ts-node -v 直接运行 ts-node xxx.ts<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="vscode里配置自动编译ts为js"><a href="#vscode里配置自动编译ts为js" class="headerlink" title="vscode里配置自动编译ts为js"></a>vscode里配置自动编译ts为js</h2><p>vsCode 新建ts文件 –> ts文件目录cmd,初始化 tsc –init,生成一个tsconfig.json文件 –> 修改tsconfig.json文件的 “outDir”: “./js”, ./js为要生成的文件夹 –>点击vsCode终端 》点击运行任务》点击选择typescript 》点击选择监视typescript </p><p>好处:没事修改ts文件不会像方法一每次在控制台输入tsc index.js,这个是自动的方式<br>tsc –init 生成配置文件 做以下修改</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">"outDir": "./js" // 把ts编译后放js文件夹下"strict": false //改为不严格模式<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>该目录终端-运行任务-所有任务-tsc监视 <strong>ps:这里目录不能有&符号会报错</strong><br>修改配置文件后执行指定文件 tsc 不生效。 要执行tsc</p><h2 id="ts里的一些概念"><a href="#ts里的一些概念" class="headerlink" title="ts里的一些概念"></a>ts里的一些概念</h2><ul><li>类型注解?<br><strong>是一种轻量级的为函数或者变量添加的约束</strong></li></ul><pre class="line-numbers language-javaScript"><code class="language-javaScript"> function test (str: string) { return 'hell------' + str }<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><ul><li>隐式类型推断?</li></ul><pre class="line-numbers language-javaScript"><code class="language-javaScript"> let age = 18 // 我们赋值变量数字18, 那么这个变量ts会推断为number类型 // age ='qweq' // 语法不允许 let name // 如,我们声明变量name 没有赋值,ts无法推断当前变量类型 默认为any类型 name = 18 name = true // ps: 虽然ts会做隐式类型推断, 但是建议为每个变量明确类型,便于后期更直观的理解代码<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>类型断言?<br><strong>在有些特殊情况下,ts无法推断出一个变量的具体类型,而我们开发者根据代码的使用情况知道这个变量到底什么类型的。从而辅助ts更加明确代码中每个成员的类型。</strong><br><strong>!!!重点!!!类型断言并不是类型转换,类型转换是代码运行时的概念,类型断言是编译过程中的概念, 编译后这个断言也就不存在了</strong></li></ul><pre class="line-numbers language-javaScript"><code class="language-javaScript"> const nums = [1, 2, 4] const res = nums.find(i => i > 0)//此时res类型可能是number 或者 undefined 所以要使用断言指定类型 // 断言写法:// as 关键字 const num1 = res as number // jsx时不能使用 有语法冲突 const num2 = <number>res<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>类型声明?<br><strong>在实际开发中 ts中引入第三方模块,有的不是那ts写的, 就没有强类型的提示体验!!!</strong><br><strong>在使用第三方库过程中,如果当前模块不包含类型声明文件, 我们可以尝试安装对应模块的类型声明模块(一般为:@types/…/), 如果没有的话我们只能使用declare语法进行类型声明。 具体使用查看官方文档</strong></li></ul><h2 id="ts基础类型"><a href="#ts基础类型" class="headerlink" title="ts基础类型"></a>ts基础类型</h2><h3 id="一、原始类型7个"><a href="#一、原始类型7个" class="headerlink" title="一、原始类型7个"></a>一、原始类型7个</h3><pre class="line-numbers language-javaScript"><code class="language-javaScript"> const a: string = '123' const b: number = 123 const c: boolean = true const d: null = null const e: undefined = undefined const f: void = undefined const g: symbol = Symbol('123') console.log(a, b, c, d, e, f, g)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="二、其他类型"><a href="#二、其他类型" class="headerlink" title="二、其他类型"></a>二、其他类型</h3><h4 id="1-Object类型"><a href="#1-Object类型" class="headerlink" title="1.Object类型"></a>1.Object类型</h4><p> 不是单指普通的对象,可以是对象 数组 fun<br> <code>const foo: object = {} // [] // function() { }</code></p><h4 id="2-Array类型"><a href="#2-Array类型" class="headerlink" title="2.Array类型"></a>2.Array类型</h4><p> <code>const arr1: number[] = [1, 2, 3]</code><br> <code>const arr2: Array<number> = [1, 2, 3] // 泛型写法</code></p><h4 id="3-元组类型"><a href="#3-元组类型" class="headerlink" title="3.元组类型"></a>3.元组类型</h4><p> 明确元素数量以及元素类型的数组<br> <code>const tuple: [number, string] = [2, '2']</code></p><h4 id="4-枚举类型"><a href="#4-枚举类型" class="headerlink" title="4. 枚举类型"></a>4. 枚举类型</h4><p> 特点:给有一组数值给上更好理解的名字,一个枚举中只会出现固定的几个值不会出现超出范围的可能性</p><pre class="line-numbers language-javaScript"><code class="language-javaScript"> enum postState { draft = 0, // 值可以不指定, 默认从0累加。 如果初始化值是 字符串 必须手动给每个成员指定值 -不常见。 unpublished = 1 } // 常量枚举 const enum postState2 { draft = 0, unpublished = 1 } // 使用 const obj = { title: '', state: postState.draft, // 0 1 2 state1: postState[0] // 可以使用索引值访问, } // ps:我们在ts中使用的大部分类型经过编译转换后都会被移除掉,因为他只是为了我们在编译过程中做类型检查!而枚举不会,枚举会影响我们编译后的结果,他最终编译成一个双向的键值对对象:其实就是可以用键获取值 用值获取键。 // 如果确认我们代码中不会使用索引值方式获取枚举值 我们建议使用常量枚举,enum前面添加const。使用常量枚举,编译后枚举会被移除掉。<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="5-函数类型"><a href="#5-函数类型" class="headerlink" title="5.函数类型"></a>5.函数类型</h4><p> // 定义分为:1声明函数, 2函数表达式</p><pre class="line-numbers language-javaScript"><code class="language-javaScript"> // d参数可选, 必须放最后 // rest任意个数参数使用es6的 function func1 (a: number, b: number, d?: number, ...rest: number[]): string { return 'func1' } func1(1, 2) // 函数表达式,接收这个函数的变量也需要类型注解 vscode会推断出这个变量类型 (a: number, b: number) => string const func2: (a: number, b: number) => string = function (a: number, b: number) { return 'func2' }<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="6-任意类型any"><a href="#6-任意类型any" class="headerlink" title="6.任意类型any"></a>6.任意类型any</h4><p> 属于动态类型,ts不会对any做类型检查, 兼容js老代码时需要any类型</p><pre class="line-numbers language-javaScript"><code class="language-javaScript"> function func3 (val: any) { return JSON.stringify(val) // stringify方法接收任意类型参数 }<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="7-接口类型-interface"><a href="#7-接口类型-interface" class="headerlink" title="7.接口类型-interface"></a>7.接口类型-interface</h4><p> 一种规范契约,可以用来约定对象的结构,我们使用一个接口就必须遵守这个接口的全部约定。</p><pre class="line-numbers language-javaScript"><code class="language-javaScript"> interface userFace { age: number, name: string, title?: string // 可选成员 readonly content?: string // 只读成员,初始化后不可改变 } // 参数user使用接口 function getUser (user: userFace) { return user.age + user.name } console.log(getUser({ age: 18, name: 's' })) // 动态接口写法: interface userFace2 { [key: string]: string // key代表属性名称任意名称string代表可以的类型, 第二个string代表键值的类型 } const cache: userFace2 = {} cache.foo = 'val1' cache.bar = 'val2'<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="8-泛型"><a href="#8-泛型" class="headerlink" title="8.泛型"></a>8.泛型</h4><p> 把我们定义时不明确的类型变成一个参数 ,使用时在传递这样的类型参数!</p><pre class="line-numbers language-javaScript"><code class="language-javaScript"> function createNumberArray (length: number, value: number) { // 因为Array对象默认创建是的any类型,所以我们要指定下他默认的类型 使用泛型指定 // const arr = Array(length).fill(value) const arr = Array<number>(length).fill(value) return arr } const rest = createNumberArray(3, 100) console.log(rest) // ps:此时 createNumberArray函数只能创建数字类型的数组。 如果还想创建字符串类型的数组 就可以使用泛型参数, // !!!!!!泛型参数方法 改进 createNumberArray!!!! // 一般泛型参数为T ,然后把函数中不明确的参数类型都改为T function createArray<T> (length: number, value: T) { const arr = Array<T>(length).fill(value) return arr } // 泛型使用 const rest2 = createArray<string>(3, 'foo') console.log(rest2)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> ts </category>
</categories>
<tags>
<tag> ts </tag>
</tags>
</entry>
<entry>
<title>vue多服务启动</title>
<link href="/posts/e22d.html"/>
<url>/posts/e22d.html</url>
<content type="html"><![CDATA[<h1 id="vue项目-nodejs服务,如何前后端服务同时启动?"><a href="#vue项目-nodejs服务,如何前后端服务同时启动?" class="headerlink" title="vue项目+nodejs服务,如何前后端服务同时启动?"></a>vue项目+nodejs服务,如何前后端服务同时启动?</h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>有时我们在vue项目里使用了Nodejs 提供接口服务或者使用到jar包程序时,这时就需要同时执行两条服务命令,我们可以分别开两个cmd窗口去启动对应服务但是比较麻烦.</p><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p>使用 concurrently 依赖并行地运行多个命令。</p><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> concurrentlyoryarn add concurrently<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>然后在package.json 文件 scripts中, 例如修改:</p><pre class="line-numbers language-javaScript"><code class="language-javaScript">"scripts": { "start": "craco start", "build": "scraco build", "test": "craco test", "eject": "react-scripts eject", "node": "npm run serve --prefix nodeServer", "dev": "concurrently npm:node yarn:start"}<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>有了 –prefix nodeServer 就不用 cd nodeServer 文件夹了,也就是说运行 <strong>npm run node</strong> 就会跑后端的服务,相当于:<strong>npm run serve</strong><br>此时只需要<strong>npm run dev</strong> 就会执行 <strong>npm run node</strong> 和 <strong>npm run start</strong> 也就实现了同时启动了服务端和客户端。<br>ps:这里命令我有用了yarn也是可以的</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> vue node </category>
</categories>
<tags>
<tag> vue </tag>
<tag> node </tag>
</tags>
</entry>
<entry>
<title>vim简单使用</title>
<link href="/posts/9cde.html"/>
<url>/posts/9cde.html</url>
<content type="html"><![CDATA[<h1 id="vim-是什么?"><a href="#vim-是什么?" class="headerlink" title="vim 是什么?"></a>vim 是什么?</h1><p>vim/vi 是 Unix / Linux 上最常用的文本编辑器而且功能非常强大。但是【只有命令,没有菜单】</p><h1 id="Vscode-vim-基础使用:"><a href="#Vscode-vim-基础使用:" class="headerlink" title="Vscode vim 基础使用:"></a>Vscode vim 基础使用:</h1><p>y 复制(先选中)<br>yy 复制一行<br>nyy 复制多行(n 为行数)<br>p 粘贴<br>u 撤销<br>移动光标至所选行的开头,按 v 进入视图,键盘上按向下键,选中所需行即可。<br>恢复刚才的操做 ctrl+r<br>v+w 打开选中模式,并向后移动一个单词<br>v+b 打开选中模型,并向前移动一个单词<br>v+i+w 打开选中模式,并选中当前单词</p><h1 id="vim-的模式"><a href="#vim-的模式" class="headerlink" title="vim 的模式"></a>vim 的模式</h1><h2 id="一、默认-normal-模式"><a href="#一、默认-normal-模式" class="headerlink" title="一、默认 normal 模式"></a>一、默认 normal 模式</h2><p>正常模式一般用于浏览文件,也包括一些复制、粘贴、删除等操作。这时击键时,一般的键/键组合会被当成功能键,而不会键入对应的字符。在这个模式下,我们可能通过键盘在文本中跳来跳去,跳动的范围从小到大是字符、单词、行、句子、段落和屏幕。启动 vim 后默认位于正常模式。不论位于什么模式,按下<code><Esc></code>键(有时需要按两下)都会进入正常模式。</p><ul><li><p>移动<br><code><font color=red ></code>单词操作:<code></font></code><br>w= word 跳到下一个单词的开头<br>e= 跳到下一个单词的结尾<br>b= back word 跳到上一个单词的开头<br><code><font color=red ></code>行操作:<code></font></code><br>0 行首<br>I 单词行首<br>$ 行尾<br>A 单词行尾<br>15gg 跳转到 15 行<br>:18 = 进入 18 行<br>18G =进入 18 行<br>gg 文件首行<br>G 文件末行<br>Shift + [] 是以「代码块」为单位跳行<br>Ctrl + u 和 Ctrl + d 实现上下滚动页面,滚动行数默认为半页大小<br>[[跳到文件首行,而]] 则是行末。<br>gd: 函数的跳转 go to defined<br>ctr+o 退出到原先的函数位置<br>当前行下移一行 :m+<br>当前行上移一行 :m-2</p></li><li><p>选中<br>v+i+w 放在一个单词的任意位置时均可选中本单词<br>v+e 光标放在一个单词的开头时可选中本单词<br>v+h/j/k/l 进入视图模式后使用方向键容易选中你想选的部分</p></li><li><p>删除<br>d = delete 删除 d 是开启剪切模式<br>x= 删除一个字符<br>dG = 删除全部<br>3x = 3 个字符<br>dd= 剪切一行/ndd 删除 n 是数字<br>dw = delete word 删除一个单词-光标在单词位置<br>diw = delete inner word 删除一个单词进入插入模式<br>daw = delete around word 包含空格<br>s 是删除当前光标所指并转为 insert 模式</p></li><li><p>改<br>c= change<br>cc= 删除一行并且进入写入模式<br>ciw=删除一个单词并进入插入模式<br>ct) = 光标不在括号内,修改到右括号,<br>ct) =光标在括号内容第一个字符,删除()内容进入插入模式<br>以下命令可以对标点内的内容进行操作。<br>ci’、ci”、ci(、ci[、ci{、ci< - 分别更改这些配对标点符号中的文本内容<br>di’、di”、di(或 dib、di[、di{或 diB、di< - 分别删除这些配对标点符号中的文本内容<br>yi’、yi”、yi(、yi[、yi{、yi< - 分别复制这些配对标点符号中的文本内容<br>vi’、vi”、vi(、vi[、vi{、vi< - 分别选中这些配对标点符号中的文本内容</p></li><li><p>查</p><blockquote><p>查<br>查找’name’: <code>/name</code> n 向下 N 向上<br>取消查找高亮命令: <code>:nohl</code><br>在 normal 模式下按下*即可查找光标所在单词<br>在查找模式中加入\c 表示大小写不敏感查找,\C 表示大小写敏感查找。<br>例如:<code>/foo\c</code> 将会查找所有的”foo”,”FOO”,”Foo”等字符串。<br>查找替换<br>:s(substitute)命令用来查找和替换字符串<br>例如:<code>%s/foo/bar/g</code> 会在全局范围(%)查找 foo 并替换为 bar,所有出现都会被替换(g)<br>g 即是替换标志之一,如: i 表示大小写不敏感查找,I 表示大小写敏感。<br>还有空替换标志表示只替换从光标位置开始,目标的第一次出现:<br><code>:%s/foo/bar</code></p></blockquote></li></ul><p>作用范围分为当前行、全文、选区等等。<br>当前行:<br><code>:s/foo/bar/g</code><br>全文:<br><code>:%s/foo/bar/g</code><br>选区,在 Visual 模式下选择区域后输入:,Vim 即可自动补全为 :’<,’>。<br><code>:'<,'>s/foo/bar/g</code><br>2-11 行:<br><code>:5,12s/foo/bar/g</code><br>当前行.与接下来两行+2:<br><code>:.,+2s/foo/bar/g</code></p><h2 id="二、insert-插入模式"><a href="#二、insert-插入模式" class="headerlink" title="二、insert 插入模式"></a>二、insert 插入模式</h2><p>在正常模式中按下 i, I, a, A 等键,会进入插入模式。<br>小写包含空格,大写不包含空格<br>a/A = append: 后面插入<br>i /I = insert :前面插入<br>o/O = open a line :另起一行<br>现在只用记住按 i 键会进行插入模式。插入模式中,击键时会写入相应的字符<br>保存:<br>:w 保存文件但不退出vi<br>:w file 将修改另外保存到file中,不退出vi<br>:w! 强制保存,不推出vi<br>:wq 保存文件并退出vi<br>:wq! 强制保存文件,并退出vi<br>:q 不保存文件,退出vi<br>:q! 不保存文件,强制退出vi<br>:e! 放弃所有修改,从上次保存文件开始再编辑命令历史</p><h2 id="三、visual-可视模式"><a href="#三、visual-可视模式" class="headerlink" title="三、visual 可视模式"></a>三、visual 可视模式</h2><p>在正常模式按下 v, V, <code><Ctrl></code>+v,可以进入可视模式。可视模式中的<br>操作有点像拿鼠标进行操作,选择文本的时候有一种鼠标选择的即视感,有时候会很方便。</p><p>i( =会选中括号里面的单词<br>i” = 会选中””引号里内容<br>a( =会选中括弧以及括弧里面的单词<br>a” =会选中””和内容<br>aw =会选中单词以及单词前面的一个空格<br>iw = 会选中一个单词 (visual 模式)</p><h2 id="四、command-命令模式"><a href="#四、command-命令模式" class="headerlink" title="四、command 命令模式"></a>四、command 命令模式</h2><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> 其他 </category>
</categories>
<tags>
<tag> vim </tag>
</tags>
</entry>
<entry>
<title>vue3优势!</title>
<link href="/posts/8d7.html"/>
<url>/posts/8d7.html</url>
<content type="html"><![CDATA[<h2 id="vue3-x-开始"><a href="#vue3-x-开始" class="headerlink" title="vue3.x 开始"></a>vue3.x 开始</h2><p>2020年 9.18发布3.0版本、代号: One Piece (海贼王),耗时两年,2600+提交,99位贡献者。</p><h2 id="vue2-x-面临的问题"><a href="#vue2-x-面临的问题" class="headerlink" title="vue2.x 面临的问题"></a>vue2.x 面临的问题</h2><p>vue2.x版本发布于数年前,基于es5的技术架构,受限于当时通用浏览器的版本问题,在某些功能方面做了一些妥协:</p><ul><li>监听数据的方法 <code>Object.definePerproty</code>, 不能对Object类型做深度监听。而为了深度监听,以及为了达到目的所要付出的代价,也就是<strong>递归遍历</strong>侦听数据</li><li><code>optionsApi</code>存在问题,功能分块混乱,我们需要把逻辑分别散落在 <code>data,methods、computed</code>对象里,新增一个需求就需要分别在各项里修改,来回滚动</li><li>vue2.0缺少一种较为简洁的低成本的机制来完成逻辑复用,虽然可以minxis完成逻辑复用,但是当mixin变多的时候,会使得难以找到对应的data、computed或者method来源于哪个mixin,使得类型推断难以进行</li><li>ts支持不友好</li></ul><h2 id="2-0-3-0-实现原理"><a href="#2-0-3-0-实现原理" class="headerlink" title="2.0 / 3.0 实现原理"></a>2.0 / 3.0 实现原理</h2><ul><li>Vue2.0: 实现MVVM(双向数据绑定)的原理是通过 <code>Object.defineProperty</code> 来劫持各个属性的 <code>setter、getter</code>在数据变动时发布消息给订阅者,触发相应的监听回调。<br>缺点:<br>基于 <code>Object.defineProperty</code> 不具备监听数组的能力,需要重写数组的原型方法来达到响应式。<br><code>Object.defineProperty</code> 无法检测到对象属性的添加和删除 。<br>由于Vue会在初始化实例时对属性执行getter/setter转化,所有属性必须在data对象上存在才能让Vue将它转换为响应式。<br>深度监听需要一次性递归,对性能影响比较大</li><li>Vue3.0: 重构响应式系统,使用 <code>Proxy</code>代理 + <code>Reflect</code>反射,替换 <code>Object.defineProperty</code><br>使用Proxy代理优势:<br>可直接监听数组类型的数据变化<br>监听的目标为对象本身,不需要像Object.defineProperty一样<em>递归遍历每个属性</em>,有一定的性能提升<br>可拦截apply、ownKeys、has等13种方法,而Object.defineProperty不行<br>不需要一次性遍历data的属性,可以显著提高性能。<br>因为Proxy是ES6新增的属性,有些浏览器还不支持,只能兼容到IE11<br>源码:</li></ul><pre class="line-numbers language-javascript"><code class="language-javascript"> <span class="token keyword">const</span> proxyData <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span>key<span class="token punctuation">,</span>receive<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// 只处理本身(非原型)的属性</span> <span class="token keyword">const</span> ownKeys <span class="token operator">=</span> Reflect<span class="token punctuation">.</span><span class="token function">ownKeys</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span> <span class="token keyword">if</span><span class="token punctuation">(</span>ownKeys<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'get'</span><span class="token punctuation">,</span>key<span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// 监听</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> result <span class="token operator">=</span> Reflect<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span>key<span class="token punctuation">,</span>receive<span class="token punctuation">)</span> <span class="token keyword">return</span> result <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">set</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> val<span class="token punctuation">,</span> reveive<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// 重复的数据,不处理</span> <span class="token keyword">const</span> oldVal <span class="token operator">=</span> target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token keyword">if</span><span class="token punctuation">(</span>val <span class="token operator">==</span> oldVal<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> result <span class="token operator">=</span> Reflect<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> val<span class="token punctuation">,</span>reveive<span class="token punctuation">)</span> <span class="token keyword">return</span> result <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true">// 删除属性</span> <span class="token function">deleteProperty</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">const</span> result <span class="token operator">=</span> Reflect<span class="token punctuation">.</span><span class="token function">deleteProperty</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span>key<span class="token punctuation">)</span> <span class="token keyword">return</span> result <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="vue3带来了什么?"><a href="#vue3带来了什么?" class="headerlink" title="vue3带来了什么?"></a>vue3带来了什么?</h2><p>打包大小减少41%、初次渲染快55%、更新渲染快133%、内存减少54%</p><ul><li>新增 <code>Composition API</code>更好的逻辑复用和代码组织<br>Vue2.0中,随着功能的增加,组件变得越来越复杂,越来越难维护,而难以维护的根本原因是Vue的API设计迫使开发者使用watch,computed,methods选项组织代码,而不是实际的业务逻辑。<br><code>Composition Api</code>的出现,主要是也是为了解决Option API带来的问题<br>第一个是代码组织问题,Compostion API可以让开发者根据业务逻辑组织自己的代码,让代码具备更好的可读性和可扩展性,也就是说当下一个开发者接触这一段不是他自己写的代码时,他可以更好的利用代码的组织反推出实际的业务逻辑,或者根据业务逻辑更好的理解代码。<br>第二个是实现代码的逻辑提取与复用,当然mixin也可以实现逻辑提取与复用,但是像前面所说的,多个mixin作用在同一个组件时,很难看出property是来源于哪个mixin,来源不清楚,另外,多个mixin的property存在变量命名冲突的风险。而Composition API刚好解决了这两个问题。</li><li>重构 <code>Virtual DOM</code><br>Vue2 中的虚拟dom 是进行全量对比<br>Vue3 新增静态标记,模板编译时的优化,将一些静态节点编译成常量<br>slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组件<br>模板中内联事件的提取并重用(原本每次渲染都重新生成内联函数)</li></ul><h2 id="Vue3-x搭建起步"><a href="#Vue3-x搭建起步" class="headerlink" title="Vue3.x搭建起步"></a>Vue3.x搭建起步</h2><p>安装好vue-cli后, 终端输入vue -V 出现4.5.x以上版本为3.x的脚手架。</p><pre class="line-numbers language-bash"><code class="language-bash">使用脚手架创建第一个3.x项目:Vue create vue3demo01<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>使用 <code>Vite</code>创建项目:</p><pre class="line-numbers language-bash"><code class="language-bash">全局安装vite:<span class="token function">npm</span> <span class="token function">install</span> -g create-vite-app创建项目create-vite-app yourProjectName<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><ul><li>npm:</li></ul><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">npm</span> init @vitejs/app 按照提示操作or<span class="token function">npm</span> init @vitejs/app my-vue-app<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><ul><li>yarn:</li></ul><pre class="line-numbers language-bash"><code class="language-bash">yarn create @vitejs/app 按照提示操作oryarn create @vitejs/app my-vue-app<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><ul><li>你还可以通过附加的命令行选项直接指定项目名称和你想要使用的模板</li></ul><pre class="line-numbers language-bash"><code class="language-bash">例如,要构建一个 Vite + Vue 项目运行:yarn create @vitejs/app my-vue-app --template vue例如创建 vue+ts:yarn create @vitejs/app my-vue-app --template vue-ts<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> vue3 </category>
</categories>
<tags>
<tag> vue3优势 </tag>
<tag> vue3起步 </tag>
</tags>
</entry>
<entry>
<title>Markdown基础</title>
<link href="/posts/f82f.html"/>
<url>/posts/f82f.html</url>
<content type="html"><![CDATA[<h1 id="什么是Markdown?"><a href="#什么是Markdown?" class="headerlink" title="什么是Markdown?"></a>什么是Markdown?</h1><p>Markdown 设计灵感主要来源于纯文本电子邮件的格式,目标是让人们能够使用易读、易写的纯文本格式编写文档,而且这些文档可以转换为 HTML(Hyper Text Markup Language,超文本标记语言)文档。</p><p>简单来说,Markdown 是由一些简单的符号(如*/->[]()#)组成的用于排版的标记语言,其最重要的特点就是可读性强。</p><p>Markdown 相当于简化了的 HTML,它只提供用户最常用的语法格式,更易读和易写,用户可以不必关心复杂的 HTML 标签,只专注于写作就行了。</p><p>常用的标记符号也不超过十个,这种相对于更为复杂的HTML 标记语言来说,Markdown 可谓是十分轻量的,学习成本也不需要太多,且一旦熟悉这种语法规则,会有一劳永逸的效果。</p><h1 id="Markdown优点"><a href="#Markdown优点" class="headerlink" title="Markdown优点"></a>Markdown优点</h1><p>直接创建,没啥限制和要求。<br>排版简单,可读、直观、学习成本低<br>支持插入图片,视频等等(根据平台不同而定)<br>轻松的导出 HTML、.md 文件<br>可跨平台同步数据<br>随时可修改(不必像word等易混乱)</p><h1 id="基础语法"><a href="#基础语法" class="headerlink" title="基础语法"></a>基础语法</h1><h2 id="标题"><a href="#标题" class="headerlink" title="标题"></a>标题</h2><pre><code>一级标题对应一个 # 号;二级标题对应两个 # 号;以此类推。。。一共六级标题。</code></pre><h2 id="文本"><a href="#文本" class="headerlink" title="文本"></a>文本</h2><pre><code>*斜体文本*_斜体文本_**粗体文本**__粗体文本__***粗斜体文本***___粗斜体文本___</code></pre><h2 id="字体颜色"><a href="#字体颜色" class="headerlink" title="字体颜色"></a>字体颜色</h2><pre><code><font face="黑体" color=green size=5>黑体,绿色,尺寸为5(任意内容)`</font>`or$\color{red}{红色字}$</code></pre><h2 id="链接"><a href="#链接" class="headerlink" title="链接"></a>链接</h2><pre><code>[name:大话卷积神经网络CNN(title:干货满满)](url:https://blog.csdn.net/TeFuirnever/article/details/100057229)or[https://blog.csdn.net/TeFuirnever/article/details/100057229](https://blog.csdn.net/TeFuirnever/article/details/100057229)</code></pre><h2 id="图片"><a href="#图片" class="headerlink" title="图片"></a>图片</h2><pre><code>![图片描述](图片地址)支持 jpg、png、gif、svg 等图片格式,其中 svg 文件仅可在微信公众平台中使用。</code></pre><h2 id="代码块"><a href="#代码块" class="headerlink" title="代码块"></a>代码块</h2><pre><code>单行代码:代码之间分别用一个反引号包起来即可Use the`printf()` function.代码块高亮:``key 支持多种语言 js java bash .... 代码块 ``</code></pre><h2 id="分割线"><a href="#分割线" class="headerlink" title="分割线"></a>分割线</h2><pre><code>可以在一行中用3个 - 或者 * 来建立一个分隔线,同时需要在分隔线的上面空一行,如下:---或者**** * ******- - -</code></pre><h2 id="删除线"><a href="#删除线" class="headerlink" title="删除线"></a>删除线</h2><pre><code>删除线的使用,在需要删除的文字前后各使用两个 ~~~这是要被删除的内容。~~</code></pre><h2 id="下划线"><a href="#下划线" class="headerlink" title="下划线"></a>下划线</h2><pre><code>下划线的使用,在需要添加下划线的文字首部和尾部加上`<u>`文本 `</u>`,如下:`<u>`这行文字已被添加下划线 `</u>`</code></pre><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> 其他 </category>
</categories>
<tags>
<tag> Markdown </tag>
</tags>
</entry>
<entry>
<title>个人常用方法、终端指令记录</title>
<link href="/posts/c9f9.html"/>
<url>/posts/c9f9.html</url>
<content type="html"><![CDATA[<hr><h1 id="个人常用方法、终端指令记录"><a href="#个人常用方法、终端指令记录" class="headerlink" title="个人常用方法、终端指令记录"></a>个人常用方法、终端指令记录</h1><h2 id="快速删除-node-modules"><a href="#快速删除-node-modules" class="headerlink" title="快速删除 node_modules"></a>快速删除 node_modules</h2><p>windows 系统在项目目录下打开 cmd 窗口, 使用如下命令快速删除:<br><code>rd /s /q node_modules</code><br>or<br>如果是 powershell,使用命令:<br><code>rd -r node_modules</code><br>or<br>使用 node 插件 rimraf 以包的形式包装 rm -rf 命令,用来删除文件和文件夹的,不管文件夹是否为空,都可删除;</p><pre class="line-numbers language-js"><code class="language-js">npm install rimraf <span class="token operator">-</span>g <span class="token comment" spellcheck="true">// 全局安装</span>rimraf node_modules<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h2 id="git相关"><a href="#git相关" class="headerlink" title="git相关"></a>git相关</h2><ul><li>初始化</li></ul><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">git</span> init<span class="token function">git</span> status<span class="token function">git</span> log <span class="token comment" spellcheck="true"># 显示提交日志</span><span class="token function">git</span> config --global user.name <span class="token string">"xxx"</span> <span class="token comment" spellcheck="true"># 配置用户名</span><span class="token function">git</span> config --global user.email <span class="token string">"xxx@xxx.com"</span> <span class="token comment" spellcheck="true"># 配置邮件</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>本地创建 git 仓库?</li></ul><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">mkdir</span> xxx<span class="token function">cd</span> xxx<span class="token function">git</span> init<span class="token function">touch</span> README.md添加文件:<span class="token function">git</span> add README.md<span class="token function">git</span> commit -m <span class="token string">"first commit"</span><span class="token function">git</span> remote add origin git@gitee.com:sisi001/xxx.git<span class="token function">git</span> push -u origin <span class="token string">"main"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong>(注意 gitee 远程主分支是 master github 已经修改为 main)</strong></p><ul><li>远程已有仓库?</li></ul><p>本地创建文件夹关联远程库</p><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">cd</span> existing_git_repo<span class="token function">git</span> remote add origin git@gitee.com:sisi001/xxx.git<span class="token function">git</span> push -u origin <span class="token string">"main"</span> (注意gitee 远程主分支是 master github是main)<span class="token comment" spellcheck="true"># git提交时报错:</span><span class="token comment" spellcheck="true">#Updates were rejected because the tip of your current branch is behind......解决方案</span><span class="token function">git</span> push -u origin master -f <span class="token comment" spellcheck="true">#-f意为强制推送。</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>直接从远程仓库拉取现有内容(gitee 远程创建的仓库主分支为 master)</p><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">git</span> clone git@gitee.com:sisi001/xxx.git<span class="token function">cd</span> xxx<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h3 id="git遇到的问题"><a href="#git遇到的问题" class="headerlink" title="git遇到的问题"></a>git遇到的问题</h3><ul><li>git pull遇到错误:error: Your local changes to the following files would be overwritten by merge</li></ul><p>方法1: 保留刚才本地修改的代码,并把git服务器上的代码pull到本地(本地刚才修改的代码将会被暂时封存起来)</p><pre class="line-numbers language-bash"><code class="language-bash"> <span class="token function">git</span> stash <span class="token function">git</span> pull origin master <span class="token function">git</span> stash pop<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>方法2: 完全地覆盖本地的代码,只保留服务器端代码,则直接回退到上一个版本,再进行pull:</p><pre class="line-numbers language-bash"><code class="language-bash"> <span class="token function">git</span> reset --hard <span class="token function">git</span> pull origin main<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h3 id="git-push、git-pull"><a href="#git-push、git-pull" class="headerlink" title="git push、git pull"></a>git push、git pull</h3><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">git</span> clone URL <span class="token comment" spellcheck="true">#拉取远程代码到本地</span><span class="token function">git</span> commit -m <span class="token string">"提交内容"</span> <span class="token comment" spellcheck="true">#提交暂存区的更改,并记录下备注</span><span class="token function">git</span> push origin main <span class="token comment" spellcheck="true">#将完成的项目推送到远程仓库中(注意github默认主分支为main,gitee为matser )</span><span class="token function">git</span> push -u origin main <span class="token comment" spellcheck="true">#第一次提交, 加上 -f 强制推送</span><span class="token comment" spellcheck="true"># 更新</span><span class="token function">git</span> fetch<span class="token function">git</span> merge<span class="token function">git</span> pull <span class="token operator"><</span>远程主机名<span class="token operator">></span> <span class="token operator"><</span>远程分支名<span class="token operator">></span>/<span class="token operator"><</span>本地分支名<span class="token operator">></span><span class="token comment" spellcheck="true">#从远程仓库拉取代码并合并到本地,可简写为 git pull 等同于 git fetch && git merge 拉去并且合并</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>git pull 的时候多次碰见下面的情况:</li></ul><pre class="line-numbers language-bash"><code class="language-bash"><span class="token comment" spellcheck="true"># 错误信息:</span>There is no tracking information <span class="token keyword">for</span> the current branch.Please specify <span class="token function">which</span> branch you want to merge with.See git-pull<span class="token punctuation">(</span>1<span class="token punctuation">)</span> <span class="token keyword">for</span> details.<span class="token function">git</span> pull <span class="token operator"><</span>remote<span class="token operator">></span> <span class="token operator"><</span>branch<span class="token operator">></span>If you wish to <span class="token keyword">set</span> tracking information <span class="token keyword">for</span> this branch you can <span class="token keyword">do</span> so with:<span class="token function">git</span> branch --set-upstream-to<span class="token operator">=</span>origin/<span class="token operator"><</span>branch<span class="token operator">></span> release <span class="token comment" spellcheck="true">#解决:git branch --set-upstream 本地关联远程分支</span> <span class="token function">git</span> branch --set-upstream-to<span class="token operator">=</span>origin/remote_branch main <span class="token comment" spellcheck="true">#其中,origin/remote_branch是你本地分支对应的远程分支; main是你当前的本地分支。</span><span class="token comment" spellcheck="true"># 然后就会提示这个错误信息:</span>fatal: branch <span class="token string">'main'</span> does not exist <span class="token comment" spellcheck="true"># 出现这个问题原因就是本地没有 main 分支导致的。</span> 输入 <span class="token function">git</span> branch -a 发现只有远程分支。 解决方式就是:输入 <span class="token function">git</span> checkout master<span class="token comment" spellcheck="true"># 错误信息:</span>出现 Already on <span class="token string">'master'</span> ,Branch <span class="token string">'master'</span> <span class="token keyword">set</span> up to track remote branch <span class="token string">'master'</span> from <span class="token string">'origin'</span>.,说明已经切换到 master 上。再次输入 <span class="token function">git</span> branch -a 发现已经有本地分支<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="git-branch"><a href="#git-branch" class="headerlink" title="git branch"></a>git branch</h3><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">git</span> branch :查看本地分支<span class="token function">git</span> branch -r :查看远程分支<span class="token function">git</span> branch -a :查看本地和远程分支<span class="token function">git</span> branch 分支名字 :新建本地分支<span class="token function">git</span> branch -d 分支名字 :删除本地分支 (分支被合并后才允许删除 ,把 -d 改成 -D 强制删除)<span class="token function">git</span> branch -m 旧的分支名字 新的分支名字 :重新命名分支<span class="token function">git</span> branch --merged:查看哪些分支已经合并到当前分支<span class="token function">git</span> branch --no-merged:查看当前哪些分支还没有合并到当前分支<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="git-checkout"><a href="#git-checkout" class="headerlink" title="git checkout"></a>git checkout</h3><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">git</span> checkout --<span class="token operator"><</span>file<span class="token operator">></span> :撤销上一次对文件的操作<span class="token function">git</span> checkout 想要切换的分支名:从当前所处的分支切换到其他分支(当切换分支的时候,需要把暂存区里面的文件进行提交,不然暂存区里面的文件会跟着到切换的这条分支上<span class="token punctuation">)</span><span class="token function">git</span> checkout -b <span class="token operator"><</span>branch-name<span class="token operator">></span>:新建并切换到新建分支上<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h3 id="git-其他"><a href="#git-其他" class="headerlink" title="git 其他"></a>git 其他</h3><ul><li><p>git 密钥<br>显示出在.ssh 文件下的文件,如果存在的话<br><code>$ ls -al ~/.ssh</code><br>git 本地查找钥:gitbash 打开终端窗口:</p><pre class="line-numbers language-bash"><code class="language-bash"><span class="token function">cd</span> ~/.ssh<span class="token function">cat</span> id_rsa.pub 查看生成的 ssh公钥,可用于git添加到SSH Keys到github账户中,之后使用git协议+ssh密钥不就不用每次输入密码了。<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></li></ul><h2 id="cmd-终端操作"><a href="#cmd-终端操作" class="headerlink" title="cmd 终端操作"></a>cmd 终端操作</h2><ul><li><p>连接远程 linux 服务器<br>ssh 用户名@服务器地址 如 <code>ssh root@39.123.124.99</code><br>ssh 是以 ssh 模式连接远程服务器的命令<br>如果用户名和服务器地址都对了,那么下一行就会让你输入 password, 需要注意的是,在你输入的时候它并不会显示输入, 只需要输入完后回车不出意外就连接成功了。<br>Linux 或者 Mac OS 系统的本地电脑中通过 SSH 登录 Linux 实例。(本地电脑必须是 Linux 操作系统或者 Mac OS 系统)</p></li><li><p>基础命令:<br>dir 查看目录</p></li><li><p>文件夹相关</p><p>md 创建文件夹<br>rm 只能删除空文件夹 / cmd:rd 删除文件夹<br>rm /s 删整个文件夹 /q 不提示</p></li><li><p>文件相关<br>del [filename] - 删除文件<br>首先是创建空文件,命令 type nul>[filename]<br>命令 echo [fileContent]>[filename] 向文件写入内容</p></li></ul><h2 id="linux-系统"><a href="#linux-系统" class="headerlink" title="linux 系统"></a>linux 系统</h2><p>rm -rf node_modules 快速删除 node_modules<br>mkdir ‘’ 创建目录<br>rm -r test 删除目录<br>touch ‘’ 创建文件<br>rm 文件名 删除<br>打开文件: vi 文件名 <br>退出打开的文件 q: 不报错强制 退出 q!<br>搜索目录【查】find<br>命令:find 目录 参数 文件名称<br>示例:find /usr/tmp -name ‘a*‘ 查找/usr/tmp 目录下的所有以 a 开头的目录或文件</p><script> document.querySelectorAll('.github-emoji') .forEach(el => { if (!el.dataset.src) { return; } const img = document.createElement('img'); img.style = 'display:none !important;'; img.src = el.dataset.src; img.addEventListener('error', () => { img.remove(); el.style.color = 'inherit'; el.style.backgroundImage = 'none'; el.style.background = 'none'; }); img.addEventListener('load', () => { img.remove(); }); document.body.appendChild(img); }); </script>]]></content>
<categories>
<category> 终端命令 cmd git linux </category>
</categories>
<tags>
<tag> git </tag>
<tag> cmd </tag>
<tag> linux </tag>
<tag> vscode终端 </tag>
</tags>
</entry>
</search>