-
Notifications
You must be signed in to change notification settings - Fork 2
/
atom.xml
912 lines (898 loc) · 93.9 KB
/
atom.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
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>https://sansui233.com</id>
<title>Sansui's blog</title>
<updated>2024-11-13T18:57:34.484Z</updated>
<generator>https://github.com/jpmonette/feed</generator>
<author>
<name>Sansui</name>
<email>sansuilnm@gmail.com</email>
<uri>https://sansui233.com/about.ico</uri>
</author>
<link rel="alternate" href="https://sansui233.com"/>
<link rel="self" href="https://sansui233.com/atom.xml"/>
<subtitle>记录学习和生活的个人博客</subtitle>
<icon>https://sansui233.com/favicon.ico</icon>
<rights>All rights reserved 2022, Sansui</rights>
<entry>
<title type="html"><![CDATA[懒、快节奏与赛博巨婴]]></title>
<id>https://sansui233.com/posts/2024-11-13-懒-快节奏与赛博巨婴</id>
<link href="https://sansui233.com/posts/2024-11-13-懒-快节奏与赛博巨婴"/>
<updated>2024-11-13T22:55:00.000Z</updated>
<summary type="html"><![CDATA[科技为了便利,可便利是否有尽头]]></summary>
<content type="html"><![CDATA[<p>1</p>
<p>今天我想把一张图从 iPad 传到 iPhone 时,突然感觉很麻烦,因为需要打开并解锁,ipad,打开照片,再点击分享,点击AirDrop。</p>
<p>然后猛然意识到,我是不是越来越懒了?</p>
<p>对于懒与对于快节奏的追求本质上是一回事,都是简化简化再简化。我对简化的追求似乎有无止境的趋势,也喜欢比对市面上的效率工具,但这真的能提高生产力吗?</p>
<p>从前拿着U盘传照片,会感叹信息化的便利。我学习计算机也想做让生活便利的事情,在更短的时间去体验到更多原本无法体验到的东西。后来用 qq 传照片,也感觉很方便。是什么时候开始连 AirDrop 都嫌弃太麻烦了呢?是不是对于我,只有意念传输才是终点?可那之后又能如何呢?</p>
<p>2</p>
<p>生活的意义来自于过程,而非终点。而衡量事物价格来自于终点,而非过程。</p>
<p>毫无疑问,工作、劳动力是商品化的,意义与复杂性从不等于价格。不如说以找寻意义的方式寻找工作,很大程度上会面临吃不上饭。</p>
<p>3</p>
<p>从前会写书信,后来能随时短信联系变得好方便,一个月发几十块的短信。再后来即时通讯工具出来,联络更便宜更方便了,可人渐渐变成了24小时 oncall 状态,隔几个小时不看微信就会被说太慢了。大概一天只看两次微信的已经是异端了。</p>
<p>也许和人有关,微信从一个方便联系感情的软件,变成了生产力工具,是随时随地接受需求的怪物。我起初能理解在微信同时加工作的人和亲人,之后变得难以理解,到现在又变得可以理解,感受是大不相同。从前是四海为友,后来是要把社交分开,到现在是感觉其实都是一回事,亲人不会更特别。</p>
<p>当真的想要放松联络时,就会使用其他软件了。为什么 qq 依然在年轻人中流行?其实就是长辈不用。qq 的用户群有特别老的和特别年轻的,中间有明显的断层。</p>
<p>4</p>
<p>国人非常喜欢开发效率类工具,也喜欢记录。近几年新的效率工具,我所知道的绝大部分是国人在开发。可能与老中整体的环境相关。在我记忆中,如果一件事做得不好,就是要反省的,如果一件事做得好但慢,那就是没有效率。「效率」这个词似乎成为了魔咒。</p>
<p>再加上不要自大、时刻谦逊、居安思危等等,于是养成了无法接受任何夸赞的性格。夸就是客套,真夸就是直冒冷汗。嗯,只要还面对着别人,没有一件事是我满意的。满意的东西现在会小心收藏起来,像 led 屏一样,不要轻易就被弄碎了。</p>
<p>5</p>
<p>人类造就科技成长,但又被科技裹挟,造就一个个被高度封装的便利化包裹的巨婴。从逻辑上说,国内早就已经进入赛博朋克,只是社会形态还没有跟上。</p>
<p>这类抽象思考的空虚感令人害怕,时常觉得早已非人。也可能只是我的个人想法。希望脱离宏大叙事,去做出微小的选择。</p>
<p>想画漫画了,草。</p>
<p>写于2024年11月13日03时15分。</p>]]></content>
<category label="生活"/>
<published>2024-11-13T22:55:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[把 draw.io 装修为简单且现代的白板应用]]></title>
<id>https://sansui233.com/posts/2024-11-12-把drawio装修为简单美观的白板应用</id>
<link href="https://sansui233.com/posts/2024-11-12-把drawio装修为简单美观的白板应用"/>
<updated>2024-11-12T05:19:00.000Z</updated>
<summary type="html"><![CDATA[装修无止境!]]></summary>
<content type="html"><![CDATA[<link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/11/202411120511240.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/11/202411120511552.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/11/202411120516688.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/11/202411120513014.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/11/202411120514766.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/11/202411120511067.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/11/202411120515358.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/11/202411120516990.webp"/><p><a href="http://draw.io">draw.io</a> 是一个功能丰富的流程图绘制软件。此前写论文时我一直使用这个软件画图。在没有系统性的画图需要,转而变成了有时想要随手画矢量示意图后,这个软件启动交互流程步骤繁琐,我便极少使用它了。但在使用了 tldraw, excalidraw 后,又回到了 <a href="http://draw.io">draw.io</a>,才发现这个软件的可定制性其实非常强,完全能满足随手画图的需要。这里记录一下如何把 draw.io 变成一个更适合打开即用的、默认效果更加现代的白板应用。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/11/202411120511240.webp" alt="image.png"/></p>
<p>(草……windows 截图这边缘的黑框好丑啊!)</p>
<h2>为什么是 draw.io</h2>
<p>先对比一下适合需求的竞品(不想看请跳转下一节):</p>
<ul>
<li><a href="https://www.microsoft.com/en-us/microsoft-365/visio/flowchart-software">visio</a>: 收费,而且 mac 上没有。</li>
<li><a href="https://www.tldraw.com/">tldraw</a>, <a href="https://excalidraw.com/">excalidraw</a>: 更适合作为 sdk 使用,作为成品有些过于简单,在易用的同时,想多做一点非流程图的东西又很复杂,中文字体也不契合其默认的手写设计。而且并没有打包为桌面 App,文件关联是个问题。</li>
<li><a href="https://www.processon.io/">processon</a>: 要登录</li>
<li><a href="https://www.figma.com/">figma</a>: 要用梯子登录</li>
<li>powerpoint: ……我只是想偶尔画个示意图</li>
<li>飞书: 每30天要扫码登录 ……我只是想偶尔画个示意图</li>
<li>adobe illustrator: 没有常用预制样式库,漫长的启动时间,对于没接触过的人学习成本很高。</li>
<li>无边记、goodnotes: 苹果移动端生态 only</li>
</ul>
<p><a href="http://draw.io">draw.io</a> 没有上述的问题,但它由于设计之初不是个草图应用,所以:</p>
<ul>
<li>默认较为重型的 UI</li>
<li>启动先选择储存位置,太慢了</li>
<li>默认组件样式很丑,看起来只适合工控图</li>
<li>有时会感觉曲线箭头很难调,怎么都不流畅</li>
</ul>
<p>我根据以上三点问题大致说一下如何改进。</p>
<h2>更换UI布局</h2>
<p>默认的 UI 较为传统的重型设计,熟悉这类UI是相当好用的,但按钮组过多会显得不够轻便。在 <code>其它→主题→外观</code> 中可以更换为其他的主题,有5套可用:经典、极简、简易、草图、atlas。</p>
<p>我个人用得比较多的是「简易」,并且关掉了左侧栏形状库的栏,改为用顶栏,右侧格式栏在顶部有快速按钮展开。</p>
<p>习惯 tldraw、excalidraw 的用户应该还是更适合「草图」主题,绑定了基础形状的快捷键。需要去手动调出格式栏。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/11/202411120511552.webp" alt="image.png"/></p>
<h2>更改启动流程</h2>
<p>默认情况下,启动时会弹出选择保存位置的框。新建画布时,又会先看到一大串模板的选择题,还得去想命名。但很多时候,随便画图是不需要保存的。</p>
<p>在经典主题下,需要去「其它」→「显示开始画面」上取消勾选。在其它的主题下,则需要去菜单的「设置」→「配置」里取消勾选「显示开始画面」。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/11/202411120516688.webp" alt="image.png"/></p>
<h2>配置默认样式</h2>
<p>要做到更改默认样式,需要写 JSON 配置。尽管可以在侧栏按「设置为默认样式」,但只能当前打开的窗口生效,刷新、新开文档都会导致默认样式回到最初的样子。</p>
<p>在经典主题下,需要通过 「其它」→「配置」打开,其它主题下,则是「设置」→「配置」。</p>
<blockquote>
<p><strong>我的配置已经上传到 <a href="https://gist.github.com/Sansui233/a7f5b88e35194f82b1a76a7e05df4f5c">gist</a>。</strong></p>
</blockquote>
<p>JSON 写法参考了如下文档:</p>
<ul>
<li><a href="https://drawio-app.com/blog/customise-default-shape-libraries-templates-and-plugins-in-draw-io-for-confluence-cloud/">Customise default shape libraries, templates and plugins in draw.io for Confluence Cloud - draw.io</a></li>
<li><a href="https://www.drawio.com/doc/faq/configure-diagram-editor">Configure the draw.io editor</a></li>
</ul>
<p><a href="http://draw.io">draw.io</a> 的图形分为 vertex(顶点图形) 和 edge(箭头、线段)两类,选中按 <code>ctrl + e</code> 即可查看当前图形应用的样式。</p>
<h3>配色与样式设计</h3>
<p>整体采用的粗线条粗体,比较契合现代简约又活泼的趋势。edge 采用黑色,与高饱和的 vertex 非常好搭配。</p>
<p>直接抄的无边记的颜色,有的有轻微的改动。不过无边记最印象化的水蓝色没有抄上去。</p>
<p>默认的配色改为了最后一个蓝色。以下配色均可以在右侧的「格式栏」中找到并应用。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/11/202411120513014.webp" alt="配色方案.png"/></p>
<h3>关于圆角矩形</h3>
<p>现代设计中圆角矩形用得更多。对于圆角的弧度,可以通过属性 Arc Size 去调整。可以点击设置为默认样式,也可以配置到 JSON 里。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/11/202411120514766.webp" alt="image.png"/></p>
<p>如果你使用的「经典」主题,需要自己选择圆角矩形的图形。在「草图」主题下,按 <code>D</code> 就是默认配置好的圆角矩形,相当简单。「简易」主题下的位置如图:</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/11/202411120511067.webp" alt="image.png"/></p>
<h3>关于曲线设置</h3>
<p>曲线设置不对会变得很难调整,一张图说明大多数情况下的曲线操作与设置:</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/11/202411120515358.webp" alt="曲线.png"/></p>
<h3>想更换为手写风格?</h3>
<p>在不选中任何东西的情况下,把右侧格式栏的草图勾选上即可,就可以获得类似 excalidraw 的手写风格啦!</p>
<p>另外,如果没有自定义 JSON, 「草图」主题下的默认样式也是手写风格的。</p>
<h3>关于默认字体(附网页用字号推荐)</h3>
<p>JSON 中这几个字段设置默认字体。我默认英文是 Inter,中文是使用的系统黑体。文字大小我设置为了网页标准 16px。</p>
<pre><code class="hljs language-json"><span class="hljs-punctuation">{</span>
<span class="hljs-attr">"customFonts"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
<span class="hljs-string">"Inter"</span><span class="hljs-punctuation">,</span>
<span class="hljs-string">"pingfang sc"</span>
<span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"defaultVertexStyle"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
<span class="hljs-attr">"fontSize"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">16</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"fontFamily"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Inter"</span>
<span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"defaultEdgeStyle"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
<span class="hljs-attr">"fontSize"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">16</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"fontFamily"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Inter"</span>
<span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<p>另外介绍一下常用网页文字大小的规范,现代的美术设计由于自己屏幕很大,或者对标准视距缩放大小没太多概念,非常容易把字给设置得很小(点名星穹铁道)</p>
<ul>
<li>16px 为默认正文大小,但由于主要是考虑了希腊字母面积比较小,所以也有的中文网站会设置为 15px。</li>
<li>14px 偏次级小段落、不重要的文字,长时间阅读会累。</li>
<li>13px 为代码常用大小。</li>
<li>12px 已经非常小了,是正常视距下最小可视大小,适合做脚注、引用。</li>
</ul>
<p>再小的字号不推荐作为内容性文本使用。</p>
<h3>关于背景网格</h3>
<p>在简易主题中默认关闭的,经典主题中可以通过配置 JSON 为默认关闭。关掉背景网格会显得比较现代化。</p>
<pre><code class="hljs language-json"><span class="hljs-punctuation">{</span>
<span class="hljs-attr">"defaultGridEnabled"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"defaultPageVisible"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span>
<span class="hljs-punctuation">}</span>
</code></pre>
<p>但还是有时可能需要开启网格,那就什么都不选中,右侧栏开启网格就可以了。</p>
<h2>其他使用 Tips</h2>
<h3>导出设置</h3>
<p>导出时注意一下缩放。网页标准大小字体为 16px,编辑时画布 100% 缩放下一切正常。但是当导出为位图(jpg, png)时,需要根据你的显示器缩放进行放大,否则文字一定会糊。</p>
<p>我的显示器为 150% 界面缩放,因此需要缩放到 150% 才能大概清晰,如果要让 4k 屏也看得无比清晰,最好导出 200% 缩放,且 dpi 尽量在 180 以上。</p>
<p>另外可以直接框选后右键复制,不一定要导出。</p>
<h3>一个文件画多张图</h3>
<p>经常会遇到多张同系列图的需求。为此,你可以选择都画在一页上,要用时框选特定范围,右键复制为 png 。这样很适合边聊天边画图发给别人,但也会失去缩放、加白底、加白边等设置。至少你得打个组,把 16px 的文字放大后再复制,以确保结果不会糊。</p>
<p><a href="http://draw.io">draw.io</a> 也可以分页,建议是一页一个图,可批量导出。</p>
<h3>从 Mermaid 生成图、嵌入 Notion</h3>
<p>mermaid 是一种画流程图的代码,比较适合不想可视化排列对齐的强迫症。</p>
<p>draw.io 可以在菜单中的「高级」使用 mermaid 生成图,下面的图就是导入 mermaid 生成的。</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/11/202411120516990.webp" alt="未命名绘图.png"/></p>
<p>由于 notion 无法画图,在 notion 我都是用的 mermaid,有点不好看但至少目的达到了。不过最近发现,<a href="http://draw.io">draw.io</a> 的导出可以选择直接嵌入notion,点开还能进行编辑……实现方式是图像数据全部存放在了链接里……不得不说 draw.io 自主兼容性做得很强,从接入了那么多网盘就可见一斑。</p>
<h3>自定义CSS</h3>
<p>如果还是觉得 UI 太丑了,在 <a href="https://www.drawio.com/doc/faq/configure-diagram-editor">Configure the draw.io editor</a> 中可以找到自定义 CSS 的部分(但我觉得 UI 排列上还是不错的,这足够了)</p>]]></content>
<category label="工具"/>
<published>2024-11-12T05:19:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[碎碎念001]]></title>
<id>https://sansui233.com/memos?id=2024-11-08 12:41</id>
<link href="https://sansui233.com/memos"/>
<updated>2024-11-08T04:41:00.000Z</updated>
<content type="html"><![CDATA[<h2>2024-11-14 02:52:18</h2>
<p>疯狂 debug 快3小时,自从 next.js 升级依赖后,rss 就不会在 build 时更新了,仔细一查竟然是卡在 code splitting 上……然后开个 branch 查了半天,发现把茴字换一种 dynamic import 写法就不会有问题了,啊?啊?不是?我不明白……另外这要怎么 debug 啊……</p>
<h2>2024-11-13 22:45:23</h2>
<p>啊啊啊听歌就好像画画真的好想画画有想画的但画技太烂了又会画一半被自己气死!</p>
<h2>2024-11-12 05:49:48</h2>
<p>今天又抓住 secs 聊天,大概确定评估标准就是生活质量+感兴趣吧。北京生活质量的活,antarx 说是觉得得 50w,我觉得长期生活的话确实是这样的,很难想象一个月一万块在这个出门就是雾霾的地方生活个十几年,每天看着 AQI 破百的空气质量发愁。啥也存不下,那我不如回老家,也是一个月一万多但至少有房……</p>
<p>然后 secs 和 andy 出去的理由其实都是有比较明确的,离开家的动力。但鉴于之前种种原因吧,我差不多没有任何生活上换地方的动力了,或者说哪里都一样。会觉得换个地方可能很好,但是不是那种很想去看看的好,而是觉得达不到的理想美。我现在有动力可能是上门维修网络疑难杂症,可能是太需要帮人解决问题以维持自身那点薄弱的价值感了。</p>
<p>说来买的软排线还没到……搜了好久才知道中关村那边是还有在卖的。怪我没有做硬件的朋友,尽管本科专业是硬件相关的但那时没有人喜欢自己 DIY,我那时也不喜欢,现在,“超有意思”……</p>
<p>然后说回朋友,其实感觉工作后的人会觉得人脉重要还是没有公开透明有效的机制,以及大熔炉的环境吧。在学校的话,找到合适的人是相当容易的,很多被迫社交的场合和活动,至少对我这种 i 人来说也不会存在非常多的信息不对称。出来后是因为社交广度变窄了。</p>
<p>还有到底为什么父母为什么觉得回家等于不工作啊!回家只是少房租啊该工还是工啊!没工一样找啊!不过早就听过自由职业者谈过这个问题,最后甚至出去租工位假装上班了。我个人也不愿意回家,只要不是活不下去了,一分钱也不想用家里的……</p>
<p>然后 secs 写的那篇如何识别野鸡公司,是针对技术岗的,非常有用,我觉得可以拿去开讲座的程度。就是策划岗不太适用吧。</p>
<h2>2024-11-07 23:56:52</h2>
<p>游戏策划这个事情、何と言うかさあ……果然还是不太行的样子。老实说呢我本科时是还真是挺想进的,日记会写想做 ACG 相关的。但是时代变了大人……朝令夕改的谁也不保。而且我始终想做的是技术(就算画画也是技术),而不是策划这样门槛低,但比炒股都难赚,还要指挥别人 social……我真的很 i 的 i 人,要是感觉 e 都是装的(也并没有遇到有人感觉我 e)</p>
<p>另外前途这个事,hr 说了很多还是不觉得策划的发展路线是明朗的,更类似创业吧,创业多不明朗做策划就多不明朗。今天 hr 说的没招老策划的原因,那很可能就是我今后再次找工作面临的问题。</p>
<p>技术后期再做策划,大概是我觉得最好的方式了,也不会有拍脑袋一想结果没法落地的问题。我甚至觉得技术有想法那是不需要专门找策划的,要找只能是因为人一天只能工8小时……</p>
<p>我在以前也是觉得只要能力对口就能找,但现在发现好多公司都是草台班子混口饭吃,工作内容就是谁都能做,做久了能力没有提升只是熟悉了业务流程,这时就是拼的简历、学历什么的……如果有生活得更轻松的工作,业余时间打点游戏,就是再好不过了。</p>
<p>当然还蛮开心和制作人聊天的,整个过程还挺神奇的,被动找过来的,不是一个诈骗公司还是有在做原创的公司就很幸运了,但就还是,一个不能做技术的职位,还谁都能做,确实不会想去,说浪费我游戏设计的天赋,但我长期实践过也无比清楚我设计很一般,比下有余比上不足,每次看到好作品一查作者都是艺术、设计相关专业出身,无一例外。所以这是巧合吗?设计是天赋吗?上限是的但是下限不是,下限是经验,是可以学习的。我开始画画真的是被说没天赋的,画什么都很怪,完全看不出特点和方向,但后面上了课后就被说有天赋了……不是……那其实就是基础和经验而已。</p>
<p>相比之下做策划更浪费我学技术的天赋,或者说动力吧……艺术生就业更加困难这种机会还是给他们吧,我还遇到了挺多逻辑挺好的艺术生的,但鄙人的艺术生朋友无一例外都是技术党,明确表示技术做到头了也不想去混管理,还想学虚幻5,要转去做个人品牌。</p>
<p>不过我也听说了同专业学长有一些本科去了游戏策划,可能16年左右吧,只能说,时代啊时代……但策划也没有在我的考虑范围内,毕竟我更习惯直接动手实践,而且策划钱太少了(图穷匕现!)真就在北京贷款上班是吧,同样的工资在老家 955 躺平不好吗,想干什么做成副业不好吗……</p>
<p>不过也感谢强行把我从待机状态拉出来的 HR 吧,说明我还不是真的想摆烂……开头面试时整个牙齿都在抖,这就是社恐久了……</p>
<h2>2024-11-01 17:42:59</h2>
<p>真切感受到 App 各自圈地带来的影响是,有个妹妹问 ps 穿透模式有什么作用,说换了八个关键词都没有搜到。我有点震惊。然后搜了一下百度……确实搜不到!唯一有用的靠前的还是个 抖 的长视频,看一眼就可以明白的东西用视频讲了 9 分钟……</p>
<p>然后换了小红书搜,虽然相关内容不多,但第一条就是。</p>
<p>然后换了 bing 搜,也是第一条就有,adobe 的官网,但可惜她打不开。csp 台湾地区 tips 也非常详细,但可惜她打不开。国内优动漫的运营做的说明其实也很详细了,但在百度的 seo 排名非常之低,完全搜不到 ,用 bing 倒是排在第一个。</p>
<p>好烂的信息茧房。</p>
<hr/>
<p>但说来十二年 ps 老登其实也没看说明书,就是对着老爸吃灰的 PS3 零基础案例书学会的。不过接触 Adobe illustrator 是真的会觉得有理解成本在的</p>
<h2>2024-10-18 00:38:10</h2>
<p>华强北的小作坊便携显示器坏了,于是换了 ipad moonlight 串流。屏幕感觉太舒服了感动。Apple 的屏幕能莫名觉得很稳定。PC 再好的屏幕都还是会有一种刺眼的感觉,换个角度的观感就不一样。</p>
<h2>2024-10-16 18:36:24</h2>
<p><span class="tag">#博客 </span>对了哦,这个页面的无限滚动的框重做了,其实是参考的 Thread。但做的时候发现一个问题……头顶那两个圆角很难做!因为无限滚动是使用 transform3d 定位的,然后就会新建一个图层。众所周知,新建图层的 方形 background 会覆盖父级容器……</p>
<p>然后我想那是不是 first-child 就可以了呢?然后发现我的 virtual list 实现是每个 list item 外面都套了一圈 div,当时的原因是 ref 传不了函数式组件,但我又需要在父级使用 ref,因为我这个无限滚动容器大概是做了个除了微博以外的平台都没有做的 feature —— 可变高度(微博的那个可变高度还有 bug 草,收起时状态没有同步)</p>
<p>然后我可能会想 virtual list div 上去写样式不就好了吗?不行不行,我的 virtual list 设计是通用组件,不能带样式,样式应该由外部决定。</p>
<p>Thread 的解决方案是,绝对定位单独画了两个角……是的,你没有听错,那两个圆角甚至是两个单独的图层……我不想这么做。</p>
<p>我想不能在组件接口上开个口, style 传给内部吗?哒咩,一个组件的参数既有 container 的样式,和 item list 的样式,感觉就是很混乱。而且样式又分 style 和 classname。这个组件只有两个层级还好,只用暴露四个样式接口,但要是那种很多层的,不能也设计这么多样式接口吧!这是个原则性问题,絶対無理!</p>
<p>最后解决方法其实非常简单但开始时没有想到,那就是 在父级总节点加了 class,用最原始的, css 的,“>”…………</p>]]></content>
<category label="Diary"/>
<published>2024-11-08T04:41:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[Windows 调整之中文字体]]></title>
<id>https://sansui233.com/posts/2023-09-29-windows-system-chinese-fonts-adjustment</id>
<link href="https://sansui233.com/posts/2023-09-29-windows-system-chinese-fonts-adjustment"/>
<updated>2024-08-01T18:08:00.000Z</updated>
<summary type="html"><![CDATA[让 windows11 字体更好看的一些设置与字体浅谈]]></summary>
<content type="html"><![CDATA[<link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/08/202408190158527.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/08/202408190318888.webp"/><link rel="preload" as="image" href="https://img-cf.sansui233.com/imgs/2024/07/202407260100518.webp"/><blockquote>
<p>以下仅适用于低于 4k 缩放 200% 的显示器</p>
</blockquote>
<p>微软雅黑作为随着 Windows7 出现的字体,加上遥遥领先(?)的 ClearType,在当时的 1080p 显示器上十分清晰易读。</p>
<p>但如今的显示器分辨率越来越高,旧版微软雅黑的设计存在着明显的缺陷。</p>
<p>一是其字形设计并不平衡,中宫过大,有的字形可以以难看来形容;二是微软雅黑字形只在 4K 屏 200% 缩放(以上的配置)上有着较好的显示效果。</p>
<p>微软曾经设计过“另一版的微软雅黑”,即 Noble Scarlet,但并没有在正式的系统中使用。这一版字体设计依然中宫偏大,但相对老版收敛了不少,平衡了一些。</p>
<p>另外,如果你不巧像我一样用着 2K 或 2.5K 屏,</p>
<ul>
<li>在 24寸时,100% 缩放字体比较合适,但与 16 寸 1080p 显示器差不多清晰度,不过屏幕可用空间更大。</li>
<li>在 21 寸时,100% 缩放字体会偏小,比较锻炼眼睛。150% 缩放字体大小比较合适,效果更细腻,但字型会比较怪,且屏幕可用空间与 1080p 相同。</li>
<li>在 16 寸时,150% 缩放字体稍微偏小,效果比较细腻,但非整数倍缩放+ClearType 的加持下,一些像素被吞掉,笔画的间距不平衡,有种“ windows 特有的字被虫噬的美”。</li>
</ul>
<p><img src="https://img-cf.sansui233.com/imgs/2024/08/202408190158527.webp" alt="字形"/></p>
<p>可以看到,上图的 100% 200% 缩放没有字形变形问题,可以说微软雅黑小字优化是考虑的 100% 缩放。100% 缩放显得糊则是因为图片放大放大倍率过高,实际不会有糊,而是有锯齿感。</p>
<p>150% 缩放会由于 clearType 的“锐化”导致字形变化,不知道的还以为换了个字体。如果是125%、175%的缩放,字体变形更加糟糕。</p>
<p>造成缩放问题的原因大概可以用下图进行简要解释:</p>
<p><img src="https://img-cf.sansui233.com/imgs/2024/08/202408190318888.webp" alt="缩放"/></p>
<p>Mac 上的 Retina 渲染相当于 4k 200% 缩放起步。而 windows 下, 2k-2.5k 的屏幕都在 200% 以下的缩放中挣扎。如果软件没有适配高分屏,没有 clearType,强制进行双线性缩放(常见于图片UI),就会显得非常糊。想体验这样的糊,可以下载旧版的原神启动器。</p>
<h2>需要准备</h2>
<ul>
<li>
<p><strong>Noble Scarlet</strong> 替换系统的微软雅黑。由于 Noble Scarlet 是一个未完成的字体,普遍使用的是社区修正版,以下是资源参考。</p>
<ul>
<li><a href="https://bbs.pcbeta.com/viewthread-1960120-1-4.html">pcbeta</a></li>
<li><a href="https://www.bilibili.com/read/cv6059905/">bilibili</a></li>
</ul>
</li>
<li>
<p>系统字体替换工具:搜索 “<a href="https://www.fishlee.net/soft/SysFontReplacer/">字体替换工具 by 随风飘扬</a>”。替换完后重启,否则可能有缩放错误。另外,github 上有一个非侵入式的系统字体替换工具 <a href="https://github.com/Tatsu-syo/noMeiryoUI">noMeiryoUI</a>,可惜换不全 windows 11,只是作为预览不同字体在系统上的效果倒是个很不错的工具。</p>
</li>
<li>
<p><a href="https://www.mactype.net/"><strong>MacType</strong></a> 改善 ClearType 的虫噬渲染方式带来的不均匀,使用后提升非常非常大。</p>
</li>
<li>
<p><strong><a href="https://source.typekit.com/source-han-serif/cn/">思源宋体</a></strong>:推荐将浏览器的 Serif 字体设置为此字体。默认的宋体真的,不论中文英文,都很丑……只适合打印。</p>
</li>
</ul>
<h2>常用正文黑体简述</h2>
<p><img src="https://img-cf.sansui233.com/imgs/2024/07/202407260100518.webp" alt=""/></p>
<h3>苹方</h3>
<p>苹方是一款设计上很优秀的字体,其间架结构、中宫非常平衡,既兼顾了传统的汉字笔画细节又有规整而现代的几何化,间距合理,阅读起来非常舒适。</p>
<p>但是……苹方的设计缺字重。</p>
<p>在设计上,苹方没有 Heavy 字重(<a href="https://support.apple.com/en-us/103203">参考</a>)。而在<a href="https://github.com/paraself/PingFang-Fonts">流行的 github 苹方字体仓库</a>中,则是将 Bold 字重映射到了 Heavy,而将原本的Medium 映射到了 bold。虽然这个问题不是苹果设计的导致的,而是一个再次分发时的错误,但致使目前网上能搜索到的第三方仓库的苹方字体整体字重均偏细。</p>
<p>另外,苹方在 2.5K 屏上表现非常糊,苹方问世时已经进入了 Retina 屏的时代,没考虑过在低 PPI 屏幕上的表现(不是4K屏缩放200%都别用)。</p>
<p>第三,苹果设备的显示的西文字体是 <a href="https://zh.wikipedia.org/zh-hans/San_Francisco_(2014%E5%B9%B4%E7%9A%84%E5%AD%97%E4%BD%93)">San Francisco</a>,不是苹方。在 <a href="https://lrd.im/blog/2022-01-17">细数 Pingfang SC 的七宗罪</a> 中,也提到仅使用苹方导致不同设备字体 fallback 的不一致的问题。而作为系统字体里的其他问题,例如缺失本地化的字型,也是大部分字体所缺乏的,这已经不仅仅是一个字体问题,而是和字体相关的和 UI 技术标准化问题,难以仅通过字体解决。而无比例数字、冒号不垂直居中、没有垂直标点等细节,则都是因为苹果显示标点数字用的 SF 字体,苹方在此类字符上算是基本能用,但缺少多种场景下的细节。</p>
<p>其他资源: <a href="https://www.figma.com/community/file/1089832205783108371">Pingfang for windows - Figma</a></p>
<p>另外,苹方是有版权限制,以下字体除了思源黑体,和大厂的开源黑体,均不可免费商用。</p>
<h3>思源黑体系列</h3>
<p>思源黑体(Noto sans) 是 google 的开源可商用字体,用于 Android 系统,在开源可商用的的黑体其质量无可替代。</p>
<p>更纱黑体是思源黑体的衍生,修改了西文部分,相比思源黑体上更符合作为 无明显风格特征的系统字体,带 hinting 在 1080p 和 2.5k 下都能保证良好的清晰度。</p>
<p>但是,思源黑体系列设计相比于国产的商用字体并不能算好,有时间架结构比较怪异,字形的细节不太统一,比如“用”字明显矮了一截,整理风格上给人一种不稳定感。同时也不是一个大气的字体,比如口字旁处理对于黑体而言偏小,“用”字矮了一些,但是在宋体设计上,“用”字矮的这一截反而让字体看起来平衡。而一个系列的字体衬线、非衬线的统一感来源于其比例,个人理解为思源/更纱系列是优先考虑宋体的字形,和黑体的比例有一定的结合。整体而言还是宋体的设计更加优秀。</p>
<p>相对而言更纱黑体更适合作为系统字体,有着合理的 hinting。思源黑体是不太适合低 ppi 屏的,它的 Regular 字重看起来像 Bold。</p>
<h3>方正兰亭系列(微软雅黑)</h3>
<p>Noble Scarlet (社区版)常规体是新设计中宫收窄的微软雅黑,而粗体是方正兰亭黑 Pro,因此在加粗时,字体明显会变小一圈。</p>
<p>微软雅黑系列字体在标点处理上很差,最直观的就是全角引号,太像半角的处理方式,很难看出前引号与后引号的区别。其实我在写这一篇文的时候,换了 Typora 的字体,才发现前后引号全打反了……</p>
<p>方正兰亭黑 Pro 想对于两版微软雅黑都有着更小的中宫,字形设计中正。但也由于稍小了一些,在低 ppi 屏的小字上笔画更容易显得不太均匀,渲染效果不太好。另外使用此字体需要相比于其他所有字体更大的行距,因为其较小的中宫,字间距显得相对宽了。</p>
<h3>汉仪旗黑系列</h3>
<p>近年来的国产安卓厂商字体都是汉仪旗黑的衍生,代表阿里的普惠体、鸿蒙体、小米的字体、Oppo的字体。</p>
<p>这系列字体间架结构合理,但笔画上更加激进,减弱了起笔与收笔的的传统突出,以追求几何感与现代的科技感。在观感上,这样规矩的方形会使得字体相比方正系列更加圆润,多了现代感但少了汉字的人情味,用于阅读小说时尤其明显。</p>
<p>仅字形而言,作为 UI 是非常不错的。不过 Misans 渲染出来明显偏粗,我没有测试其他同系列字体是否也有这样的问题。</p>
<h2>改掉 Windows 的默认中文无衬线字体</h2>
<p>很多无法分别修改中英字体的 windows 原生应用,当只设置了英文字体时,显示的中文是新宋体(SimSun),比如 vs studio。原因在于系统里的 Microsoft Sans-serif 字体名,回落到的第一个字体就是新宋体……难以想象微软雅黑出了十多年了还有这样的问题。</p>
<p>解决办法:</p>
<ul>
<li>winkey + R, 输入 regdit,进入 windows注册表</li>
<li>进入 <code>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink</code></li>
<li>把 Microsoft Sans Serif 的值中 SIMSUN.TTC 那一行去掉。这样默认的无衬线体就会往后 fallback 到系统的微软雅黑上。</li>
</ul>
<hr/>
<p>创建于 2023-09-29 02:25:44</p>
<p>更新于 2024-08-19 01:45:31</p>]]></content>
<category label="工具"/>
<published>2024-08-01T18:08:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[Windows 命令行相关配置之 msys2+zsh+zi]]></title>
<id>https://sansui233.com/posts/windows-zsh-conf</id>
<link href="https://sansui233.com/posts/windows-zsh-conf"/>
<updated>2024-03-15T20:35:00.000Z</updated>
<content type="html"><![CDATA[<p>长久以来,遇到 bash 脚本会临时切 git-bash 中的 bash。由于用的语言都有自己的包管理器,倒也一直够用。但是最近涉及到一些 c++,由 git-bash 提供的最小化环境东西缺得太多,几乎不能当个日常 shell 用,也没有 pacman 包管理,最后决定还是单独安装 msys2。</p>
<p>git-bash 和 msys2 同时安装不会冲突。msys2 是独立的 home 目录,而 git-bash 是与 windows 当前用户通用的。我本来想卸载 git-bash,但由于我现在还是用 powershell,最终发现 git-bash 不能卸载。一是 posh-git 只支持 git-bash 的 git;其次是,astro-nvim 中的一些插件需要 <code>git.exe</code> 在环境变量下,使用 alias 链接的 git 不行,而手动加环境变量会把 git 以外的程序也加进去,造成 msys2 的工具与 powershell 本身工具的冲突。</p>
<p>想来想去,决定保留 git-bash 到最小化的状态,当成 powershell 的插件用。unix-like shell 以及相应的包管理还是 msys2。</p>
<h2>安装 msys2</h2>
<p>见 <a href="https://www.msys2.org/">https://www.msys2.org/</a> 。安装过程没什么好说的,唯一要注意的在于安装目录的权限必须是当前用户可以完全控制,否则后续各种包的安装都会有一大堆问题。如果因为强迫症安装到 Program Files 下,则需要手动添加当前用户的权限。</p>
<h3>软链接问题</h3>
<p>windows 的软链接本来也是个很麻烦的问题。到 msys2 下,还多了一个软链接方式兼容问题。msys2 默认是 <code>ln -s</code> 是复制,要用 windows 风格的软链接,可以改安装目录下的各种 <code>.ini</code> 文件中的配置。</p>
<pre><code>MSYS="winsymlinks:lnk"
</code></pre>
<h2>zsh + zi</h2>
<h3>zsh 的安装</h3>
<pre><code class="hljs language-bash">pacman -S zsh
</code></pre>
<p>老实说个人觉得和 linux 上的 zsh 相比还是差了一大截,用起来和 bash 感觉差不多。只是 zsh 插件管理的选择比较多</p>
<h3>zi 的安装</h3>
<p>关于 zsh 插件管理,之前在 git-bash 上我也安装了 oh-my-zsh,但是环境原因,遇到的 bug 着实太多,基本不用。另外,最大的问题是启动太慢,每次启动长达 10 秒。我分析了一下初始化脚本的执行时长,发现拖慢速度的罪魁祸首是初始化命令补全(就不能异步吗啊!)当然用 mac 时 omz 也有点慢,但显然没有 msys2 里这么离谱。</p>
<p>下午吐槽这个事情后,Antarx 说他换 zi 了。我试了下,确实很快,从没超过3s,令人偷税。</p>
<ul>
<li>zi 的安装:<a href="https://wiki.zshell.dev/docs/getting_started/installation">https://wiki.zshell.dev/docs/getting_started/installation</a></li>
</ul>
<p>安装过程最好在 msys2 的 GUI 终端下进行,因为需要登录的默认目录是在 home 的当前用户下。但这里又有另一个问题 —— msys2 不带 git。如果系统有另外安装 git,想复用,可以 cmd 启动 zsh,不指定启动的目录,指定继承环境变量。</p>
<pre><code class="hljs language-cmd">C:\\msys64\\msys2_shell.cmd -defterm -no-start -mingw64 -use-full-path -shell zsh
</code></pre>
<h3>zi 的配置与插件</h3>
<p><a href="https://wiki.zshell.dev/docs/getting_started/installation">安装Wiki</a> 在不断更新,检查最新版的安装方法。</p>
<p>安装好后,<code>.zshrc</code> 里添加如下,写好重启 zsh 即可。</p>
<pre><code class="hljs language-bash">$ vi ~/.zshrc
<span class="hljs-comment"># zsh</span>
<span class="hljs-built_in">setopt</span> AUTO_PUSHD
<span class="hljs-built_in">export</span> CLICOLOR=1
<span class="hljs-built_in">export</span> LSCOLORS=ExGxFxdaCxDaDahbadeche
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':completion:*'</span> list-colors <span class="hljs-string">"<span class="hljs-variable">${(@s.:.)LS_COLORS}</span>"</span>
<span class="hljs-built_in">alias</span> <span class="hljs-built_in">ls</span>=<span class="hljs-string">'ls --color=auto'</span>
<span class="hljs-built_in">alias</span> la=<span class="hljs-string">'la --color=auto'</span>
<span class="hljs-comment"># zi</span>
<span class="hljs-built_in">typeset</span> -A ZI
ZI[BIN_DIR]=<span class="hljs-string">"<span class="hljs-variable">${HOME}</span>/.zi/bin"</span>
<span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">${ZI[BIN_DIR]}</span>/zi.zsh"</span>
<span class="hljs-built_in">autoload</span> -Uz _zi
(( <span class="hljs-variable">${+_comps}</span> )) && _comps[zi]=_zi
<span class="hljs-comment"># source <(curl -sL init.zshell.dev); zzinit</span>
<span class="hljs-comment"># 插件</span>
<span class="hljs-comment"># 提前运行一次 zi ice pick"async.zsh" src"pure.zsh"</span>
zi light sindresorhus/pure
zi light agkozak/zsh-z <span class="hljs-comment"># 不能用 eval "$(zoxide init zsh)" 会冲突</span>
zi snippet OMZP::git
zi light zsh-users/zsh-completions
<span class="hljs-comment"># 提前运行一次 zi ice wait lucid atload'_zsh_autosuggest_start'</span>
zi light zsh-users/zsh-autosuggestions
<span class="hljs-comment"># 提前运行一次 zi ice wait lucid atinit='zpcompinit'</span>
zi light zdharma/fast-syntax-highlighting
</code></pre>
<h2>Windows Terminal 设置</h2>
<p>在设置里改 json,加相应的 profile。可以使用 <code>-use-full-path</code> 继承 windows 系统的环境变量。</p>
<pre><code class="hljs language-json"><span class="hljs-punctuation">{</span>
<span class="hljs-attr">"commandline"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"C:\\msys64\\msys2_shell.cmd -defterm -here -no-start -mingw64 -use-full-path -shell zsh"</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"guid"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"{c420e0af-28d9-4742-a6b8-83d5fcf424e9}"</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"icon"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"C:\\msys64\\mingw64.ico"</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"msys2 zsh"</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"startingDirectory"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"%USERPROFILE%"</span>
<span class="hljs-punctuation">}</span>
</code></pre>
<h2>Vscode Terminal 设置</h2>
<pre><code class="hljs language-json"><span class="hljs-attr">"terminal.integrated.profiles.windows"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
<span class="hljs-attr">"MSYS2 zsh"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
<span class="hljs-attr">"path"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"C:\\msys64\\msys2_shell.cmd"</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"args"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"-defterm"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"-here"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"-no-start"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"-mingw64"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"-use-full-path"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"-shell"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"zsh"</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"env"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"MSYSTEM"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"MINGW64"</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"overrideName"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>
<span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
<span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
</code></pre>
<h2>Mintty 设置</h2>
<p>Mintty 是 msys2 里默认的终端 GUI,默认 shell 是 bash。修改 <code>mingw64.ini</code> 为如下内容。</p>
<pre><code>MSYS=winsymlinks:lnk
MSYS2_PATH_TYPE=inherit
MSYSTEM=MINGW64
SHELL=/usr/bin/zsh
</code></pre>
<h2>npm设置</h2>
<p>如果有使用 npm 进行包管理,继承自环境变量的 npm 补全时会报错。需要设置为</p>
<pre><code class="hljs language-shell"><span class="hljs-meta prompt_">$ </span><span class="bash">npm config edit</span>
script-shell=C:\msys64\usr\bin\bash.exe
shell=C:\msys64\msys2\usr\bin\bash.exe # 重要<span class="hljs-meta prompt_">
$ </span><span class="bash">npm config list</span>
</code></pre>
<h2>conda 设置</h2>
<p>如果有使用 conda 进行 python 开发,继承自环境变量的 conda 默认初始化脚本也有问题……从 Github 上查到的解决方法……</p>
<pre><code class="hljs language-shell"><span class="hljs-meta prompt_"># </span><span class="bash">>>> conda initialize >>></span><span class="hljs-meta prompt_">
# </span><span class="bash">!! Contents within this block are managed by <span class="hljs-string">'conda init'</span> !!</span>
if [ -f '/c/Users/me/miniconda3/Scripts/conda.exe' ]; then
#eval "$('/c/Users/me/miniconda3/Scripts/conda.exe' 'shell.zsh' 'hook')"
eval "$('/c/Users/me/miniconda3/Scripts/conda.exe' 'shell.zsh' 'hook' | sed -e 's/"$CONDA_EXE" $_CE_M $_CE_CONDA "$@"/"$CONDA_EXE" $_CE_M $_CE_CONDA "$@" | tr -d \x27\\r\x27/g')"
fi<span class="hljs-meta prompt_">
# </span><span class="bash"><<< <span class="hljs-string">conda initialize <<<</span></span>
</code></pre>
<h3>ssh配置共用</h3>
<p>如果有多个 ssh 账户的密钥,最好是软链接一下配置目录。注意需要前面的修改软链接方式,否则还是去资源管理器手动软链接吧。</p>
<pre><code class="hljs language-shell">ln -s /c/Users/me/.ssh ~/.ssh
</code></pre>
<h2>参考</h2>
<p><a href="https://hustlei.github.io/2018/11/msys2-for-win.html#%E5%AE%89%E8%A3%85git%E5%92%8Cvim">msys2-for-win</a></p>
<p><a href="https://sdl.moe/post/zsh-conf/">https://sdl.moe/post/zsh-conf/</a></p>]]></content>
<category label="工具"/>
<published>2024-03-15T20:35:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[笔记 - 像素的一生]]></title>
<id>https://sansui233.com/posts/2024-02-29_像素的一生</id>
<link href="https://sansui233.com/posts/2024-02-29_像素的一生"/>
<updated>2024-02-29T23:45:00.000Z</updated>
<summary type="html"><![CDATA[浏览器渲染原理]]></summary>
<content type="html"><![CDATA[<link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342847.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342848.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342849.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342850.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342851.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342852.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342853.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342854.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342856.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342857.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342858.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342859.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342860.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342861.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342862.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342863.webp"/><link rel="preload" as="image" href="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342864.webp"/><p>内容来自于 2018 年谷歌的一个视频。原视频不长但内容很多,非常值得一看。Chrome 的渲染机制是在不断变化的。</p>
<p>笔记原存于 Logseq,如果有类似于,“见CSS/图层”一类的语句,为笔记内超链接。相关概念需自行了解。</p>
<p>📚 <strong>资料</strong></p>
<ul>
<li>
<p><a href="https://www.bilibili.com/video/av35265997/?vd_source=a94b8ba67535fb1431364b8c5fac341d">b站视频 - 2018</a></p>
</li>
<li>
<p><a href="https://docs.google.com/presentation/d/1boPxbgNrTU0ddsc144rcXayGA_WF53k96imRH8Mp34Y/edit?pli=1">英文slides</a></p>
</li>
<li>
<p><a href="https://segmentfault.com/a/1190000020102554">思否文章</a></p>
</li>
</ul>
<p><strong>渲染流程</strong>:web content → magic(rendering) → pixels</p>
<h2>1. Web content</h2>
<p>最常见的 HTML + CSS + Javascript API</p>
<p>还有图片、视频、音频、web assembly、WebGL、Canvas、PDF等等</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342847.webp" alt="Web Content"/></p>
<h2>2. 渲染</h2>
<p>渲染是在一个 sandbox 进行的。渲染引擎 Blink 是渲染代码的一个子集。</p>
<p>操作系统渲染 API:OpenGL,DirectX(Windows), vulkan。包含 textures shaders 等等。</p>
<h3>2.1 渲染目标</h3>
<ol>
<li>
<p>把 web content 渲染为 openGL 的调用</p>
</li>
<li>
<p>为更新渲染建立起对应的数据结构</p>
</li>
</ol>
<h3>2.2 基本渲染流程</h3>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342848.webp" alt="渲染流程"/></p>
<p>渲染流程太复杂,会被分为几个阶段进行数据结构的转换</p>
<p>不是每一次更新渲染,都要走全部的流程。相关看 浏览器/渲染原理 中的回流与重绘。</p>
<h4>HTML to DOM</h4>
<p>解析 HTML 为 DOM 树。DOM树的作用有两个,一个表示文档结构,二是暴露 API 给 Javascript,由 V8 JS引擎进行 API 绑定。</p>
<h4>CSS to ComputedStyle</h4>
<p>CSS 转换为 StyleRule 集,每个 StyleRule 包含 CSSSelector 和 CSSPropertyValue。流程如图</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342849.webp" alt="css parser"/></p>
<p>根据 css 样式规则,计算出每个 DOM 元素样式属性的最终值,存储于 <strong>ComputedStyle</strong> 对象模型中,是一个 style properties 与 values 的超大映射。这个过程被称为 Style Resolution。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342850.webp" alt="style resolution"/></p>
<p><strong>ComputedStyle</strong> 对象已经暴露给了 JS。使用<code>getComputedStyle(element)['padding-top']</code>即可获取。在 Dev tools 的 Elements 中的 Computed 选项卡的值就是依据此 对象来的。</p>
<h4>Layout Stage</h4>
<p>例子:</p>
<ul>
<li>Web 最基础的 Block Flow 布局,需要计算出 Block 的 x、y、width、height。</li>
<li>由于 Block 自适应高度,需要根据内容的尺寸,找到文字换行的地方,以计算每个 Block 的高度。</li>
<li>每一个 Block 的矩形有多种边界(在CSS/盒模型中说得很清楚)。内容 overflow 时,需要计算两个矩形,一个是<strong>实际内容区域</strong>,一个是<strong>能显示出的内容的区域</strong>。如果内容可滚动,还要计算<strong>滚动边界</strong>和<strong>滚动条边界</strong>。</li>
</ul>
<p>Document 的根节点本身就是 overflow 且可滚动的。</p>
<p>Layout Objects 也树结构存在,几乎与 DOM 是一对一,但并非总是如此。比如伪元素、浮动元素。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342851.webp" alt="layout"/></p>
<p>在 style 计算后会构建一个没有填入任何数据的 <strong>Layout Tree</strong>。</p>
<p><strong>更新布局</strong>的本质就是遍历 layout tree 并向里面填充所有数据。</p>
<p>Slides里说目前没有把 Layout Stage 的输入输出区分开,但没细说,只是说下个版本会改。放个图</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342852.webp" alt="Layout Stage NG"/></p>
<h4>Paint to display item lists</h4>
<p>做类似于在指定坐标内画一个红色的矩形这样的动作。代码结构上 ,是 LayoutObject 有一个 Paint 方法。去调用更底层的 Paint API。</p>
<p><strong>此阶段生成“作画步骤”,还没有真的画出像素</strong>。步骤是可以重放的。至于为什么这样做,之后再说(然而之后并没有说)。</p>
<p>Paint 是从 z-index 最大到最小进行的,而不是 DOM 的前后顺序。而两个并列的层叠上下文时,后覆盖前。在一个 CSS/层叠上下文 内,按层叠上下文的堆叠规则绘制(z轴的层叠规则),如图</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342853.webp" alt="image.png"/></p>
<h4>Rasterization 栅格化</h4>
<p>将 Display Item(位于 CC Layer 中,之后说)中记录的 Paint 操作转化为<strong>位图</strong>(bitmap)。</p>
<p>raster bitmap 通常保存于 GPU 内存中,被 <strong>OpenGL Texture Object</strong> 引用。GPU 不仅可以保存 bitmap,也可以生成 bitmap。叫 <strong>accelerated rasterization</strong>。</p>
<p><strong>此时像素纹理已经生成到内存,但还是没有画到屏幕上。</strong></p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342854.webp" alt="Rasterization"/></p>
<p>栅格化通过 <strong>SKIA 库</strong>生成对 <strong>OpenGL</strong> 的调用。SKIA 提供了一系列对硬件的抽象。具体而言,PaintOps 会调用 SKIA 中的 SkCanvas 对象。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342856.webp" alt="SKIA"/></p>
<p>由于渲染过程是在 sandbox 进行的, 不能产生系统调用,OpenGL 调用是通过 command buffer 塞进另一个进程 <strong>GPU Process</strong> 执行的。GPU Process 接受到绘制命令后通过 GL API 去产生真正的 GL 调用。</p>
<p>使用 GPU process 隔离渲染进程除了渲染进程有沙盒机制外,OpenGL 可能也不太稳定或者是有漏洞。GPU Process 可以做一些保护措施。</p>
<p>GL API 来源于系统动态库 <code>libGLESv2.so</code>。但是 windows 中来自于 Google 的 ANGLE 库 <code>libglesv2.dll</code>,因为 Windows 上渲染不是用的 OpenGL,而是 DirectX API。ANGLE 库可以翻译 OpenGL 调用为 DirectX 调用。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342857.webp" alt="GL API"/></p>
<h2>3. 图层合成</h2>
<h3>3.1 帧与动画</h3>
<p>每一帧是当前 Web 内容的完整呈现。</p>
<p>动画是连续的帧。针对第一部分提到的 style、layout、paint、raster,浏览器都做了跟踪失效的处理,只重绘改变的部分,其他部分复用。</p>
<h3>3.2 合成线程</h3>
<p>一个单独的渲染线程,减少 JS 主线程的其他操作和渲染之间 block。</p>
<p><strong>图层</strong>给合成线程渲染。比如 video 和 gif 在单独的图层,还有 transform3D, will-change 等 css 属性也会新建图层进行处理。</p>
<p>合成线程也需要处理交互。能处理的先合成线程处理(比如滚动),处理不了的就进主线程。</p>
<p><strong>Layer Tree</strong>(CC Layer Tree)</p>
<p>图层也是以树结构存在,前序遍历。</p>
<p>有的图层的存在不是绘制,而是图层效果,比如剪贴蒙版、滤镜。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342858.webp" alt="layer tree"/></p>
<p>图层的合成位于 CC (Chronium compositor) namspace, 所以代码里有很多 <code>cc::layer</code>。</p>
<p>如果一个 Layout Object 没有指定单独的 layer(比如没有 will-change 属性),就会被绘制到父 layer 的图层。</p>
<p>Paint Layer 是要被分到 CC LayerTree 的。这就是CSS/层叠上下文与CSS/图层之间的关系。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342859.webp" alt="image.png"/></p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342860.webp" alt="paint layer map"/></p>
<h3>3.3 compositioning update</h3>
<p>在上一章的流程中,没有讲到合成这步,实际要加上。因为合成不是必须的,但合成步骤能优化渲染。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342861.webp" alt="更新合成"/></p>
<p>未来,创建图层的工作会放到 paint 之后(slimming paint)</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342862.webp" alt="commit"/></p>
<p><strong>commit</strong></p>
<p>提交一次合成。这里合成线程与主线程都存在 layer tree,需要同步合成线程与主线程的状态。</p>
<h3>3.4 Tilling</h3>
<p>在 rastering 阶段,把 CC layer 分块成 tile。</p>
<p><strong>tile 是 raster 的最小单位</strong>,在专门的 <strong>raster 线程</strong> 进行栅格化。</p>
<p>合成线程有一个 <strong>tile manager</strong> 安排 tile 优先级。</p>
<p>不同分辨率的 tile 策略是不同的。</p>
<h3>3.5 Drawing</h3>
<p>不同 tile 合成为 <strong>Quad</strong>。Quad 引用内存中的 raster output,封装在合成进程中,再提交到浏览器进程。浏览器动画帧的<strong>帧</strong>概念就是 Quad。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342863.webp" alt="Quad"/></p>
<p>不同 commit 有先后顺序,需要从 pending <strong>激活</strong>再绘制。</p>
<h3>3.6 Display</h3>
<p>浏览器进程将 Quad 展示到屏幕上的过程。位于 Viz 组件中,调用 OpenGL 绘制 GPU 进程中的 Quad 资源,和 rastering 的 GL call 一样。</p>
<p>大部分平台的显示合成输出是双倍缓冲(有过游戏画面撕裂经验的应该对这有概念),quad 是在后台缓冲器(GPU的还是Viz?)中绘制的,用 swap 命令让后台的 quad 到前台展示。</p>
<h2>4. 总结</h2>
<p>Blink 引擎严格执行了主线程的步骤。但由于要实现 Web 平台化,是有一些合成线程的权限的。</p>
<p><img src="https://cdn.jsdelivr.net/gh/NamiLing/upic/picgo/202402292342864.webp" alt="总结"/></p>
<h2>其他</h2>
<p>渲染器和浏览器都用到了 GPU,都有向GPU进程的IPC通道。</p>
<p>如果想让滚动的交互产生的动画不在主线程而在合成线程执行,需要强制 will-transform 分层</p>]]></content>
<category label="学习"/>
<published>2024-02-29T23:45:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[白嫖怪的经验]]></title>
<id>https://sansui233.com/posts/白嫖怪的经验</id>
<link href="https://sansui233.com/posts/白嫖怪的经验"/>
<updated>2023-12-29T22:09:00.000Z</updated>
<summary type="html"><![CDATA[降本增效?嗯?]]></summary>
<content type="html"><![CDATA[<p>作为一个合格的白嫖怪,列举一些个人用过的免费/低价云服务。</p>
<blockquote>
<p>注:不要滥用,白嫖在很多时候都是违反 TOS(服务条款)的。</p>
</blockquote>
<p>依据项目结构,主要分类为:</p>
<ol>
<li>免费域名购买</li>
<li>静态前端托管</li>
<li>api 服务托管</li>
<li>数据库服务托管</li>
<li>服务器购买</li>
<li>GPU 平台(AI)</li>
</ol>
<h2>域名相关</h2>
<p>由于国内存在对热门国外服务 ban 域名的情况,先持有个人域名是有必要的。有免费的,付费域名也不贵。但要注意国内域名要走备案,而备案又要求买国内的服务器,这不符合白嫖的认知。所以域名只看国外。</p>
<h3><a href="https://www.freenom.com/">Freenom</a></h3>
<p>可注册免费域名。1 个域名免费 1 年,续费要钱,1 年后想继续免费需要注册新域名。不适合长期持有。通常用于一些不想被人发现的临时服务。</p>
<h3><a href="https://www.namecheap.com/">Namecheap</a></h3>
<p>6 位纯数字 + xyz 域名,一年只要 1 刀,个人开发值得拥有。只要不抢热门,域名普遍不贵。</p>
<h3><a href="https://cloudflare.com/">Cloudflare</a></h3>
<p>著名的慈善 CDN 机构(不是)。在 CF 买域名要钱,但可以转入域名,并进行免费 DNS 解析,免费的防火墙和访问控制,免费的数据统计,免费的 SSL……</p>
<p>我个人非常喜欢 CF 的 dashboard,很直接。对域名进行管理,从输入网址开始只需要点三步,登录(切页面)=> 选域名 => 选功能,全程只切了两个页面。</p>
<p>对比一下阿里云。点登录按钮(切页面)=> 登录(切页面)=> 点控制台(切页面)=> 选域名控制台 => 选域名列表 => 选管理(切页面)。</p>
<h2>静态资源托管</h2>
<h3><a href="https://github.com">Github pages</a></h3>
<p>静态网页托管。hexo + github pages。静态博客,经典搭配,原汁原味。</p>
<p>不过被墙得厉害,即使没有墙,域名也被国内浏览器屏蔽。</p>
<h3><a href="https://www.jsdelivr.com/">Jsdelivr</a></h3>
<p>静态资源托管。Github 的加速网站。很多人拿来当图床。也容易被屏蔽。相当于把 github 当 cms 用,所以管理文件没有那么好用。</p>
<p>如果是目的不是用于开发,是明确违反了 TOS 的,只是量小的话没有人管罢了。Github 本身也不是拿来存二进制的。</p>
<h3><a href="https://vercel.com/">Vercel</a></h3>
<p>静态网页托管(其实可以不静态)。特点是国内 ping 值低,自动绑免费的 SSL。不过有一段时间 vercel 的 ip 也是被墙了的。所有没有在国内备案的服务都不保证直连的可访问性,特别是在量比较大的情况下。</p>
<h3>Cloudflare pages</h3>
<p>静态前端页面部署,类似 Vercel,优点大概是比 vercel 更难被墙。</p>
<h2>网盘,OSS</h2>
<p>嗯……网盘的资源,怎么能不算资源呢?</p>
<p>不过,要获取网盘资源的直链,至少要经过两层的 API,延迟相当高。而且国内的服务防滥用机制相当严格(国内带宽贵啊)</p>
<p>但有一个好处……现在网盘普遍在卷内容管理系统 (CMS),面向用户的产品,管理文件比 OSS 好用。主要稳定性在 API 上。</p>
<h3><a href="https://alist.nn.ci/">Alist</a> 网盘列表程序</h3>
<p>文档必看,这是一个集合了阿里云盘、百度网盘、Onedrive 等的网盘列表程序,利用各个网盘的 API,对各个网盘资源直接下载。看文档直接了解有什么服务可以白嫖,可以白嫖到什么程度。我在这照抄一下常用的不走服务器流量时的网盘:</p>
<ol>
<li>百度网盘:可直接下载 20M 以内的文件,限速。</li>
<li>阿里云盘:可下载所有文件,分享的链接限速,自己的网盘不限速。</li>
<li>Onedrive:可下载所有文件,不限速,但在国外。有 API 调用上限。</li>
</ol>
<p>当然,Alist 本身还是要有服务器的,但还有 paas 可以白嫖。</p>
<h3><a href="https://www.backblaze.com/cloud-backup/personal">BackBlaze</a></h3>
<p>对象存储,有一定的免费额度,cloudflare CDN 下行流量免费,可以说是个人白嫖图床最优选吧。知道这个是因为 rclone。</p>
<h2>API 托管</h2>
<p>主要列举 PaaS 平台。</p>
<h3><a href="https://vercel.com/">Vercel</a></h3>
<p>没错又是 Vercel。Vercel 还可以托管 Node.js 和 Python 脚本等等,拿来托管小的 API 服务是非常适合的。比如 <a href="https://waline.js.org/">Waline</a>。</p>
<blockquote>
<p>支持的语言:nodejs、php、python、ruby、go</p>
</blockquote>
<p>纯读取的 API 只用 Vercel 就可以了。如果需要上传下载动态内容,使用 Vercel + 任意数据库就可以,大部分网页应用的本质就是 CRUD。</p>
<p>Vercel 的免费版 <a href="https://vercel.com/docs/limits/overview">有限制</a>,对于个人站点来讲绰绰有余的限制。付费不便宜。</p>
<h3><a href="https://fly.io/">Fly.io</a></h3>
<p>有很小的免费额度。曾经用过,长期无访问会休眠。休眠不删数据。</p>
<h3>Heroku</h3>
<p>曾经白嫖界的王者,现在没有免费的实例了,只有 Github 学生包还有免费。会休眠,据说现在会删数据。</p>
<h3>国内平台边缘计算</h3>
<p>阿里云函数计算,腾讯云函数计算,都不是很贵。用边缘函数当服务主要是麻烦在不同平台的适配上。还有,国内走公网流量计费,也不适合大带宽的服务。</p>
<h2>数据库,BaaS</h2>
<p>BaaS 这里主要是指是数据库加上部分的后端服务,比如以 restful api 的方式访问数据库,而不是对数据库服务建立连接后写 sql。Headless CMS 也是一种 BaaS。</p>
<ol>
<li><a href="https://leancloud.cn/pricing/">LeanCloud</a> 开发版有一点免费额度。</li>
<li><a href="https://supabase.com/pricing">Supabase</a> 有 10G 免费额度。实例需要每周至少一触发,目前在用。知道的人不多,国内的薅羊毛大军没有进发到这。</li>
<li><a href="https://firebase.google.cn/pricing?hl=zh-cn">Firabase</a> 有一点点免费额度。</li>
</ol>
<p>总体用得不多,可以看文章结尾的参考。</p>
<h2>低价服务器</h2>
<p>常逛 hostloc 会知道几个被大量滥用、不保证在线率、随时可能跑路的商家。主打一个买了买不了吃亏,买了买不了上当。个人用来做实验倒是挺适合吧,多买几个,白嫖一个靠谱的 API 重定向做一下负载均衡还算也 OK。</p>
<ol>
<li><a href="https://www.racknerd.com/">racknerd</a> 12 刀 1 年的小服务器,普遍 DC 02 机房三网直连。</li>
<li><a href="https://virmach.com">virmach</a> 价格同上。有日本的机房,速度啥的挺好的。我是第一批迁过去的,传家宝系列,至今 10 刀一年。但发生过严重宕机,unavailable 了两天。</li>
<li><a href="https://greencloudvps.com/">greencloud</a> 没用过,有一年独服很便宜倒是,记得一年才 22 刀。好像日本和 virmach 是一个机房,和 virmach 一起宕机。</li>
</ol>
<h2>AI 服务</h2>
<ol>
<li><a href="http://colab.google">Colab</a> github 很多项目在这白嫖 demo,跑跑小项目用可以,实例不保存环境,大模型启动很慢。可以充钱,充钱后可能抽到 A100(我抽到过 233)</li>
<li><a href="https://www.autodl.com/">autodl</a> 收费但便宜,分钟级动态租用,环境给得非常方便,接入国内网盘符合国内环境,有时候要抢实例。</li>
<li><a href="https://huggingface.co/">huggingface</a> 有免费的 cpu space,充钱用 gpu。</li>
<li><a href="https://www.kaggle.com/">Kaggle</a> 有一点免费的 gpu 时间,体验用。</li>
</ol>
<h2>参考</h2>
<ol>
<li><a href="https://gist.github.com/imba-tjd/d73258f0817255dbe77d64d40d985e76">☁️ 一些免费的云资源</a></li>
<li><a href="https://blog.lv5.moe/p/website-hosting-and-function-computing-service-selection">Cloudflare or Vercel——网站托管与函数计算服务选择</a></li>
<li><a href="https://github.com/tzhangchi/awesome-free-saas">tzhangchi/awesome-free-saas: an awesome list of free SaaS (software as a service) for you.</a></li>
<li><a href="https://ldo.one/post/backblaze-yes/">愉快的白嫖 Backblaze 的 10G 对象存储 - Hub | ldo.one</a></li>
</ol>
<hr/>
<p>发现我的语言完全丧失了中文原有的简洁性,Sad。</p>]]></content>
<category label="乱七八糟的分享"/>
<published>2023-12-29T22:09:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[Windows 命令行相关配置]]></title>
<id>https://sansui233.com/posts/2023-11-29-windows-shell-configuration</id>
<link href="https://sansui233.com/posts/2023-11-29-windows-shell-configuration"/>
<updated>2023-11-29T04:07:00.000Z</updated>
<content type="html"><![CDATA[<h2>常用 shell</h2>
<p>一直以来 windows 的命令行方案都很多,个人感觉都有不太好用的点,怎么配置也是仁者见仁智者见智的一个事情。先总结一下常用shell 方案</p>
<ul>
<li><code>powershell</code> 官方shell,各种工具库支持最全,缺点自带的命令太长,以至于完全没有日常使用的想法。</li>
<li><code>msys2</code> windows 上的类 unix 环境,基于现代 Cygwin (POSIX兼容层) 和 MinGW-w64(工具包)。确实像 unix,一般命令可以无缝迁移。缺点是兼容性,需要手动配置很多东西,比如是否继承 windows 环境变量,不继承的话不想维护两份环境,继承了又容易冲突。</li>
<li><code>git bash</code> msys2 阉割版,无包管理,多了 git。</li>
<li><code>wsl</code> 完全的 Linux 子系统,但太占内存。</li>
</ul>
<h2>方案选择</h2>
<p>我需求</p>
<ul>
<li>常用命令必须是类 unix 命令</li>
<li>有包管理器,各类命令行工具配置友好且兼容性不错。</li>
<li>不要太占内存</li>
</ul>
<p>结果发现这就是经典的三圈相交,没有任何一个常用方案能满足以上要求。</p>
<p>最后,我决定用 powershell。除了第一条外都满足。后面两条属于难以解决的硬伤,而第一条可以编写脚本,将常用的命令模拟。</p>
<h3>powershell 配置流程</h3>
<p>包含工具包、终端美化。</p>
<ol>
<li>Install the latest Powershell Core</li>
<li>Install <a href="https://gitforwindows.org/">git-bash</a> for basic bash and git tools</li>
<li>Install <a href="https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701?hl=zh-cn&gl=cn&rtc=1">Windows Terminal</a> and open Powershell</li>
<li>Install <a href="https://github.com/PowerShell/PSReadLine">PSReadLine</a></li>
<li>Install <a href="https://github.com/dahlbyk/posh-git">posh-git</a></li>
<li>Install <a href="https://ohmyposh.dev/">oh-my-posh</a> for showing extra info in term.</li>
<li>Install <a href="https://github.com/gerardog/gsudo">gsudo</a> for softlink</li>
<li>Install <a href="https://eza.rocks/">eza</a> for listing</li>
<li>open <code>$PROFILE</code> in powershell, append the contents of <a href="https://gist.github.com/Sansui233/0451b8f7c354d600c4efa74fc284d39c#file-microsoft-powershell_profile-ps1"><strong>Microsoft.PowerShell_profile.ps1</strong></a></li>
</ol>
<p>大致介绍一下用途。</p>
<ul>
<li>git-bash,一系列类 unix 工具,git 一类的</li>
<li>Windows Terminal,微软的终端。我拒绝终端用 electron 去套的……</li>
<li>PSReadLine,改变一系列 powershell 的行为。比如复制粘贴的快捷键。可惜在 vscode 里会没用,只能右键粘贴。</li>
<li>posh-git,显示 git 的状态</li>
<li>oh-my-posh,美化。具体主题可能需要会自己改一下,要么丑,要么不支持提示 conda 环境或者 npm 环境。</li>
<li>gsudo,提权,类似 unix 的 sudo。可能运行时会被杀软报毒,需要加入信任区。</li>
<li>eza,2024年了,终于有了一个像样的 ls 替代……</li>
</ul>
<p>powershell 的用户配置文件输入 <code>$PROFILE</code> 就能找到。</p>
<p>我的配置文件上传到了 <a href="https://gist.github.com/Sansui233/0451b8f7c354d600c4efa74fc284d39c#file-microsoft-powershell_profile-ps1"><strong>Microsoft.PowerShell_profile.ps1</strong></a>。需要挂代理打开。配置文件包含 <code>ls</code> <code>ln</code> <code>open</code> <code>grep</code> <code>which</code> 等命令模拟。powershell 的缩写默认支持了 <code>mv</code> <code>cat</code> <code>rm</code> 等命令,配合起来日常基本够用。</p>
<h2>终端代理</h2>
<p>我在配置文件中设置了<code>proxy</code>和<code>unproxy</code>函数,以快速设置与取消终端的代理连接。自己改下端口就能用。因为我自己习惯上不开系统代理,都是软件内的 http 连接。</p>
<pre><code class="hljs language-powershell"># Proxy Togglers
function proxy {
$portInUse = netstat -ano | findstr "LISTENING" | findstr "7890"
$portInUse2 = netstat -ano | findstr "LISTENING" | findstr "10808"
if ($portInUse -ne $null) {
$env:HTTP_PROXY = "socks5://127.0.0.1:7890"
$env:HTTPS_PROXY = "socks5://127.0.0.1:7890"
Write-Host "Proxy set to socks port 7890"
} elseif ($portInUse2 -ne $null) {
$env:HTTP_PROXY = "socks5://127.0.0.1:10808"
$env:HTTPS_PROXY = "socks5://127.0.0.1:10808"
Write-Host "Proxy set to socks port 10808"
} else {
$env:HTTP_PROXY = "socks5://127.0.0.1:1080"
$env:HTTPS_PROXY = "socks5://127.0.0.1:1080"
Write-Host "Proxy set to socks port "
}
}
function unproxy {
$env:HTTP_PROXY = ""
$env:HTTPS_PROXY = ""
}
</code></pre>
<h2>其他常用工具</h2>
<ul>
<li>
<p>winget:自带的包管理器,命令行工具都是这个装的。部分用的 scoop,非常少。还有的直接用的官网 setup。</p>
</li>
<li>
<p>nvim:命令行编辑器,vim 的替代品。我用的是发行版 AstroNvim。之前也有自己折腾插件,太懒得维护了,算了。</p>
</li>
<li>
<p>nodejs:JS 环境,nvim 的插件要用,开发也要用</p>
</li>
<li>
<p>zoxide:快速跳转目录。最有用的功能没有之一。类似 unix 的 autojump</p>
</li>
<li>
<p>Terminal-Icons:ls 命令加 icon,还能解决 ls 不高亮的问题。但是,颜色很丑。但是,我不也想再配置了,配置真的心好累。</p>
</li>
<li>
<p>ripgrep:类似 grep 的用法。我在模拟 grep 命令时只是单纯替换成了 findstr,真的 grep 建议用 ripgrep (rg) 替代。nvim 的 telescope 一些插件也会用到。</p>
</li>
</ul>
<p>安装脚本汇总:</p>
<pre><code class="hljs language-powershell">winget install conda
winget install neovim
git clone --depth 1 https://github.com/AstroNvim/AstroNvim ~/.config/nvim
winget install gerardog.gsudo
winget install OpenJS.NodeJSLTS
Install-Module -Name Terminal-Icons -Repository PSGallery; Import-Module -Name Terminal-Icons
# z-jump
winget install zoxide # z-jump, see https://github.com/ajeetdsouza/zoxide
winget install BurntSushi.ripgrep.MSVC # grep 的完全替代品
</code></pre>
<h2>ZSH</h2>
<p>有关 zsh 相关的配置,我放在了 <a href="https://sansui233.github.io/posts/windows-zsh-conf">Windows 命令行相关配置之 msys2+zsh+zi</a> 。</p>]]></content>
<category label="工具"/>
<published>2023-11-29T04:07:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[大概是关于五笔打字更慢的一点碎碎念?]]></title>
<id>https://sansui233.com/posts/thoughts-about-wubi-im</id>
<link href="https://sansui233.com/posts/thoughts-about-wubi-im"/>
<updated>2023-11-17T01:59:00.000Z</updated>
<content type="html"><![CDATA[<p>每次看到打字的视频,总是会有人说五笔是最快的。五笔我打了八年。突发奇想去测试了一下五笔打字的输入速度,结果在我意料之内——在不刻意飙手速(以不被室友打)的情况下,大概是 60 字/min,全拼大概是 70 字/min。</p>
<p>虽然拼音我现在已经非常不熟练了,但速度还是比五笔快。而五笔在日常使用也并没有感觉到有什么不顺畅的地方,为什么测速还是会更慢呢?</p>
<h2>五笔更慢的原因</h2>
<p>网上说五笔打得更快大多是指「看打下的极限速度」。这里有两个条件,一个是看打,一个是极限。</p>
<h3>看打和听打</h3>
<p>看打,指看着一段文字打出来,在早期没有各种扫描技术时,录文件就是这样的纯手工录入方式。</p>
<p>看打有利于五笔的拆字输入,而且不论一个人的普通话是否标准,只要认字都能使用。早期学者非常多会看字但念不准的。</p>
<p>早期输入法(智能 ABC)没有云计算,也没有词库,几乎一个字一个字蹦出来,非常非常慢。我小学拼音打冰灯用尽全力的记录也就 55 字/min,不算快的但也不算慢了。但现在五笔随意打初见就 70 字/min,途中还有好几个字不会拆的。想想在当时的那个环境,只靠打单字和少量词组,就能达到百字每分,是多么牛逼的一件事。</p>
<p>但在日常打字的时候,大部分人纯聊天,更多是使用的听打,想到什么说什么,就算口中没有真的发出声音。这明显是利于拼音打字的。另外,拼音打字的韵母键位非常固定,像 ing 这样的三字母韵母,打起来非常连贯,在这瞬间可以一秒按 8 个键,任何人打字多一点都能做到。真正意义上想说什么打什么。</p>
<p>我的名字拼音一共有 (10-15) 个字母,可以在 1.5 秒内打完全拼。拼音的输入速度完全不慢,重码问题也几乎靠技术解决了。在纠错、词库、上下文联想早就发展起来的情况下,五笔在日常使用上真的没有什么优势。</p>
<h3>极限速度?</h3>
<p>这就是一个老生常谈的问题了———学习成本。</p>
<p>如果仅仅靠日常打字,五笔要多久,拆字的顺畅程度可以达到打拼音一年的水平?</p>
<p>我的答案是:除非刻意练习,否则永远达不到。拆字顺畅,不会卡住自己的表达,是一个需要长期刻意练习的技能。</p>
<p>听起来可能有点夸张,但事实如此。</p>
<p>我在日常使用时,对于常用字,五笔输入也已经是条件反射,不太去想字形,和拼音差距也不大。但是测速文章就是另一回事了。各种领域的名词、人名等,总有你不适应的那一款(五笔大佬请无视)。不会拆时那个感觉真的难受,一分钟打一个字。</p>
<p>比如「凿个洞」「凹凸不平」「藏族」一类的词,对于拼音都非常简单且没有重码。但对于五笔,不是常用词且难拆,测速文里这类词很多。我有一个长长的清单,随时记录这类难以练到的字。</p>
<p>注意,以上的前提是「日常打字」。这里可能会有人对「日常」有一点误解,需要再澄清一下,日常不等于简单,而是「日常生活交流中的常用语言」。比如「藏族」,小学生都会念,还会写,但不日常。</p>
<p>五笔变小众的原因正在于高昂的学习成本,有没有不那么痛的学习方法吗?</p>
<p>有。我自己一向不是死记硬背型的人,基本是用什么学什么直接开干。日语没背五十音图,靠记了一首歌词入门,五笔也没有背码表,看了原理后,一个区一个区地打一级简码二级简码入门。遇到不会的就查,会的就越来越多。</p>
<p>但是不那么痛的学习方法问题就是上面所说的,仅靠日常打字,想在遇到任何情况下都拆字顺畅,永远也不可能(记忆超群的五笔大佬当我没说)。</p>
<p>那个「不熟悉的列表」,我专门打了也有七八遍了,里面的所有字能顺利拆出来了,但每个字还是要花时间反应。</p>
<p>同学妈妈打了几十年五笔工作,也只是在她的专业领域得心应手,换到不熟悉的领域同样卡壳。不要看贴子说打得越久越熟悉,这个年头没有几个人是为了打字而打字的,打字说是表达,是个有应用场景的事,有场景就有范围限定,有范围限定就有上限。你平时能练到的字,就这么多。</p>
<p>诚然,五笔的极限是很快,但为此需要付出的刻意练习,并不值得,除非你喜欢。</p>
<h3>软件问题</h3>
<p>86 版编码是经典的五笔编码,但我现在使用的 98 版五笔,因为有一天实在不能忍受 86 版那个莫名其妙的笔顺了,还有一些为了降低重码而设置的不合理末笔码。</p>
<p>但是后来我发现,有很长一段时间,我都在把 98 版的字根表和 86 版弄混——我在学 86 版五笔时从来没有去背过字根表,都是靠肌肉记忆,肌肉和脑袋打架,于是混乱了。</p>
<p>另外,对于不会拆的字,想不起来的字,我会使用拼音反查。自从 ios 有 98 五笔后我就在使用苹果的输入法,因为可以接第三方键盘,还可以输入 emoji。但我反查了很长一段时间后才发现,苹果的编码,可以说是有巨量的错误,把 86 和 98 版混到了一起,一字完全不同的两码什么的,有时候打 86 版的拆法也能出字,反查编码的时候更是灾难。我对 98 版的拆字方式长期处于一种混乱状态。</p>
<p>所以在初期</p>
<h2>输入法推荐</h2>
<p>需求</p>
<ol>
<li>基本词库+方便的自造词功能</li>
<li>精确的拼音反查</li>
<li>打重复字和 z 键特殊符号</li>
<li>良好的中英混输</li>
<li>可以方便地输入日期</li>
</ol>
<p>我觉得还不错的:</p>
<ul>
<li>windows 冰凌五笔,默认设置基本不用改,除了空码需要上屏编码用来中英混输。还有 shift + 空格的快捷键最好是关掉。加自造词非常方便</li>
<li>mac 上清歌五笔,中英之间支持加空格,加自造词非常方便</li>
<li>rime 98五笔,自己再魔改版。我觉得可以满足大部分需要,除了特殊符号不是 z 键没有提示。这个输入法现在是备用来查拆字的,是的,直接是显示的字根而不是编码。</li>
</ul>
<h2>为什么我还要用五笔</h2>
<p>话说回来,既然五笔打得没有拼音快,还费脑子,为什么我还要用五笔呢?</p>
<p>一是,当习惯了不重码后,很难再接受重码的输入法。不论是不是日常用语,99% 的情况下五笔都不需要选字,不需要翻列表。你可以轻易打出「艹」和「卄」,同时也不会影响你正常打「草」。</p>
<p>当然,拆不出字时也会很难受。</p>
<p>二是,永远不需要联网,隐私问题。</p>
<p>三是,好的输入法设计真的好。当时知道 z 键万能键打特殊符号原来这么好用时简直惊呆了。自从用了五笔,我从来都没有使用 -> 打箭头过,从来都是 →。希腊字母、带圈数字、拼音音标也非常好打。当朋友提醒我写的 logseq theme 没有连字箭头时,我才发现压根没有注意到原来 logseq 后来加入了连字字体。</p>
<hr/>
<p>好困😴 睡觉</p>]]></content>
<category label="Diary"/>
<published>2023-11-17T01:59:00.000Z</published>
</entry>
<entry>
<title type="html"><![CDATA[关于 typescript 泛型中返回值类型约束的问题]]></title>
<id>https://sansui233.com/posts/2023-11-11-typescript-generatic-type-proble-ts2322</id>
<link href="https://sansui233.com/posts/2023-11-11-typescript-generatic-type-proble-ts2322"/>
<updated>2023-11-11T22:26:00.000Z</updated>
<content type="html"><![CDATA[<p>最近遇到这么一个需求。</p>
<blockquote>
<p>定义一个函数接口,要求其返回值类型是 type A 的任意超集。</p>
</blockquote>
<p>于是我按直觉写下了:</p>
<pre><code class="hljs language-typescript"><span class="hljs-keyword">type</span> A = { <span class="hljs-attr">a</span>: <span class="hljs-built_in">string</span> }
<span class="hljs-keyword">type</span> <span class="hljs-title class_">FuncA</span> = <T <span class="hljs-keyword">extends</span> A><span class="hljs-function">() =></span> T
<span class="hljs-keyword">const</span> <span class="hljs-attr">f</span>: <span class="hljs-title class_">FuncA</span> = <span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> { <span class="hljs-attr">a</span>: <span class="hljs-string">"ok"</span> }
}
</code></pre>
<p>人来看非常简单知道是什么意思,就是返回值包含所有 a 的属性,其他属性全是可有可无的。</p>
<p>这段代码扔给 GPT,它也看不出什么毛病。但事实上,在 return 时报了一个错:</p>
<pre><code class="hljs language-text">Type '() => A' is not assignable to type 'FuncA'.
Type 'A' is not assignable to type 'T'.
'A' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'A'.ts(2322)
</code></pre>
<p>这个报错非常的不 helpful。因为平时, typescript 可以根据返回值推测出具体函数标注。比如</p>
<pre><code class="hljs language-ts"><span class="hljs-keyword">function</span> <span class="hljs-title function_">foo</span>(<span class="hljs-params"></span>){
<span class="hljs-keyword">return</span> <span class="hljs-string">"1"</span>
} <span class="hljs-comment">// 自动推断出函数的具体签名为 () => string</span>
</code></pre>
<p>那为什么上面的报错例子,不能做这样的推断呢?</p>
<pre><code class="hljs language-ts"><span class="hljs-keyword">type</span> A = { <span class="hljs-attr">a</span>: <span class="hljs-built_in">string</span> }
<span class="hljs-keyword">type</span> <span class="hljs-title class_">FuncA</span> = <T <span class="hljs-keyword">extends</span> A><span class="hljs-function">() =></span> T
<span class="hljs-keyword">const</span> <span class="hljs-attr">f</span>: <span class="hljs-title class_">FuncA</span> = <span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> { <span class="hljs-attr">a</span>: <span class="hljs-string">"ok"</span> }
}
<span class="hljs-comment">/* 推断出具体的签名类似于
() => {
a: string;
[name: string]: any
}
*/</span>
</code></pre>
<p>也就是说,a 是必选属性,其他属性全是 optional。</p>
<p>(先不讨论 Object 的 key 可以是 Symbol,只是为了看起来好理解,我只写了 string。要写全这里又要多写一个类型推断。)</p>
<p>当然这里又引发了另一个问题:你为什么不直接把 type A 定义附加任意可选属性?</p>
<p>好问题,这是一个正常的解决 TS2322 问题的思路。但是我就是想知道为什么泛型推断不能直接做这个……</p>
<p>我查了很多资料,没有人完美解释这个问题。但有一个相似的问题:如何让参数和返回值持有相同的泛型类型?</p>
<p>在 typescript 的 <a href="https://github.com/microsoft/TypeScript/issues/50027">github issue</a> 里有详细的案例说明,务必看看,很好懂,说是故意这么设计的。这里我将理由简短概括如下:</p>
<blockquote>
<p>如果 f 是上有一个额外的属性 prop,编译器如果推导出了返回值类型成 typeof f。之后你调用 f.prop,静态编译不会报错,但实际上有一个 runtime error,因为你的真实的返回值只是一个 <code>()=>{}</code> ,没有prop 属性。</p>
</blockquote>
<p>但个人觉得这里静态编译应该报错,并不是一个 runtime 错误。前面说了,typescript 可以对返回值进行静态的类型的检查。以上面 issue 为例,理想的报错设计是长这样:</p>
<pre><code class="hljs language-ts"><span class="hljs-keyword">type</span> A = <span class="hljs-function">() =></span> <span class="hljs-built_in">void</span>;
<span class="hljs-keyword">type</span> B = <span class="hljs-function">() =></span> <span class="hljs-built_in">void</span>;
<span class="hljs-comment">// 类型签名为 <T extends A | B>(value: T) => T 的实现</span>
<span class="hljs-keyword">function</span> f1<T <span class="hljs-keyword">extends</span> A | B>(<span class="hljs-attr">value</span>: T): T {
<span class="hljs-keyword">return</span> <span class="hljs-function">() =></span> {}; <span class="hljs-comment">// 推断出 T 此时是 typeof ()=>{},也就是 ()=>{}</span>
}
<span class="hljs-keyword">let</span> <span class="hljs-attr">f</span>: <span class="hljs-built_in">any</span>= <span class="hljs-function">()=></span>{}
f.<span class="hljs-property">prop</span> = <span class="hljs-string">"haha"</span>
<span class="hljs-title function_">f1</span>(f) <span class="hljs-comment">// 这里传参报错,因为 typeof f 和 typeof ()=>{} 不一致。本质上就是 ts2322 描述的问题,但不应该在上面报错</span>
</code></pre>
<p>当然上面的例子返回值类型已经定了是 <code>typeof ()=>{}</code>,返回值再标注 T 显得十分多此一举。但是 f1 对只是对这个函数签名的一种实现。完全可以实现对这个函数签名有不同的实现,返回不同的 subtype。</p>
<blockquote>
<p>什么是 subtype?T extends A,T 就是 A 的 subtype</p>
</blockquote>
<p>这又引发了另一个问题:这和函数重载有什么区别?</p>
<p>当然有区别啊,最大的区别就是我能定义一个统一的函数接口,只要返回值满足最基本的约束 <code>A</code>。但可以是返回不同的 subtype,实现也分开写到不同的文件里,类似于 oop 语言中返回所有某基类的派生类。这才是完全体。</p>
<p>但现在的 typescript 完全做不到这一点,返回值只能是一个非常具体的 type,要么就抛出一个毫无说服力的 ts2322 错误。</p>
<p>如果要解决开头的问题,大概是以下三个思路:</p>
<ul>
<li>定义 A 时,把所有可能要用到的属性都写到可选属性里,或直接 <code>[name: string]: any</code>。</li>
<li>考虑业务场景,其他未知属性不留下会影响到什么吗。99% 的场景是没有必要的,也就是说这个需求就是没意义的。剩下的 1% 我没有遇到/想到。</li>
<li>根据输入参数的 T 写一个类型推导,手动将返回的类型设置为 a 的具体扩展类型。类似这样</li>
</ul>
<pre><code class="hljs language-typescript"><span class="hljs-keyword">type</span> <span class="hljs-title class_">Extend</span><T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">object</span>> = {
[<span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">any</span>
} & {
[K <span class="hljs-keyword">in</span> keyof T]: T[K]
}
<span class="hljs-keyword">type</span> A = {<span class="hljs-attr">a</span>: <span class="hljs-built_in">string</span>}
<span class="hljs-keyword">type</span> <span class="hljs-title class_">FuncA</span> = <span class="hljs-function">() =></span> <span class="hljs-title class_">Extend</span><A>
<span class="hljs-keyword">const</span> <span class="hljs-attr">f</span>: <span class="hljs-title class_">FuncA</span> = <span class="hljs-function">() =></span> {
<span class="hljs-keyword">return</span> { <span class="hljs-attr">a</span>: <span class="hljs-string">"ok"</span>, <span class="hljs-attr">b</span>:<span class="hljs-string">"extra"</span>}
}
<span class="hljs-title function_">f</span>().<span class="hljs-property">a</span> <span class="hljs-comment">// a is string</span>
<span class="hljs-title function_">f</span>().<span class="hljs-property">b</span> <span class="hljs-comment">// b is any</span>
</code></pre>
<p>总之,在目前的 typescript 中,<strong>返回值类型不能是泛型</strong>。</p>
<p>当然这样也失去了扩展的类型检查,等于是用了函数的签名来检查的,和返回值的类型一点关系也没有。</p>
<p>现在 typescript 的静态检查器其实已经做了一些运行时的功能,比如条件语句判断以排除属性。但是,这些像运行时一样的检查只在静态类型不明确时才起作用。就这个 if,我已经遇到了好几次无法判断的 bug ,清空缓存并重启才恢复。</p>
<p>说回第二点,既然你允许传了任意值,也就说明在你这个库中,你也不知道其他附加值具体是拿来干什么的,大多无非遍历一下再过滤一下。如果是静态类型检查器来遍历,诶诶扩展属性怎么全是 any。最终还得用 JS 的运行时来做这个事情……所以有拿来做什么的话早就在 A 里增加 optional 属性了。这也是为什么说 99% 的场景这个需求其实不存在。</p>
<p>还有一个更重要的原因,那就是,ts 的类型体操,实在太他妈难写了。</p>
<hr/>
<p>可能没用的参考:</p>
<ul>
<li><a href="https://stackoverflow.com/questions/56505560/how-to-fix-ts2322-could-be-instantiated-with-a-different-subtype-of-constraint">typescript - How to fix TS2322: "could be instantiated with a different subtype of constraint 'object'"? - Stack Overflow</a></li>
<li><a href="https://github.com/microsoft/TypeScript/issues/50027">Could be instantiated with a different subtype of constraint · Issue #50027 · microsoft/TypeScript</a></li>
</ul>]]></content>
<category label="学习"/>
<published>2023-11-11T22:26:00.000Z</published>
</entry>
</feed>