forked from Num142857/alili.tech
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.xml
2298 lines (1988 loc) · 232 KB
/
index.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
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Hello Alili</title>
<link>https://alili.tech/</link>
<description>Recent content on Hello Alili</description>
<generator>Hugo -- gohugo.io</generator>
<language>zh</language>
<lastBuildDate>Fri, 20 Sep 2019 23:15:00 +0000</lastBuildDate>
<atom:link href="https://alili.tech/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>持续集成 - 使用Gilab CI进行前端项目的持续集成</title>
<link>https://alili.tech/archive/tisoqlkd0qa/</link>
<pubDate>Fri, 20 Sep 2019 23:15:00 +0000</pubDate>
<guid>https://alili.tech/archive/tisoqlkd0qa/</guid>
<description>市面上的持续集成平台有很多,今天介绍Gitlab的CI.
从Gitlab 8.0开始,Gitlab CI 就集成在了Gitlab中.
使用方法非常简单,只要我们在项目的根目录创建一个 .gitlab-ci.yml文件,添加一个Runner,就直接接入了Gitlab CI.
接入方式非常的简单便捷.目前我们在前端脚手架中放一个.gitlab-ci.yml文件,后续每一个前端项目都可以按照标准直接接入Gitlab CI.
GitLab Runner 所有的Gitlab任务都会放在Gitlab Runner中执行.
GitLab Runner的安装环境,根据你的需求而定,一个gitlab 可以注册的Runner是没有限制的.
普通的前端项目直接安装在Linux中就可以了,如果是小程序或者RN这种项目,目前我是直接找了一台mac mini来安装Runner.
GitLab Runner安装 安装Runner 非常简单, 这里晒出Gitlab的官方安装教程,你可以根据你的系统环境自行下载.
安装Gitlab Runner 官方文档
注册Runner Runner安装好之后,想要关联到你的Gitlab,需要注册Runner.
这里给大家介绍群组的runner注册方式,个人项目的runner方式注册基本一致
注册Gitlab Runner 官方文档
大致流程为:
打开Gitlab网站,选择群组-&gt; 设置-&gt; CI/CD -&gt; 展开Runner -&gt; 你会看到注册Runner的Token与Url 安装好Runner的机器上,运行 sudo gitlab-runner register 输入 你Gitlab的 URL 输入 Token 输入 Runner 的名字 选择 Runner 的类型,没有特殊需求直接选shell 完成 配置Runner Runner的配置文件会以执行的用户身份不同而不同
当GitLab Runner以root身份执行时 /etc/gitlab-runner/config.toml 当GitLab Runner以非root身份执行时 ~/.gitlab-runner/config.toml Runner的全局配置 这里我只说关键的两点</description>
</item>
<item>
<title>前端微服务化进阶4 - 跨框架共享组件(微件化)</title>
<link>https://alili.tech/archive/vgnhe9tfqnc/</link>
<pubDate>Sat, 22 Jun 2019 22:17:36 +0000</pubDate>
<guid>https://alili.tech/archive/vgnhe9tfqnc/</guid>
<description>在微前端中,我们可以根据自己的业务需求,让子模块使用不同框架技术栈.虽然到了这一步已经很美好了,那这就是微前端的终点吗?
答案是否定的,微前端的边界还可以更进一步的拓宽.
上一篇微前端的文章 https://alili.tech/archive/qh7x5i5szfh/ 给大家介绍了,如何在相同技术栈的子模块之间,相互调用React组件.
那今天要说的就是,如何在不同技术栈之间的子模块相调用不同技术栈的组件.
最终,我们只需要根据我们的需求调用相关功能的组件,我们不需要管他是 react ,vue或者是angular写的.
你只管用,只知道他是一个组件就好了,不用关心太多~ 对于团队的组件积累,是有极大好处的.
场景 一般情况下,一个公司的前端团队的技术栈都是统一的.但也有前端团队使用不统一技术栈的时候. 比如:
时代的变迁,升级技术栈导致内部技术栈不统一 项目众多,因为需求不一致,其他的技术栈对于项目更加有力 &hellip;其他管理原因 当我们已经使用微前端架构来构建我们的项目的时候,我们的子模块有可能因为我们项目的需求导致使用了其他的技术栈,
如果我们使用了其他的技术栈,我们原来封装的组件就不能在新的项目中用了,所以我们需要要求组件可以跨框架共享使用.
我们该怎么做? 这里有提到微件仓库模块,这是一个单独的项目.你可以理解是以前的旧项目,当你需要这个旧项目的某一个组件的时候,可以直接从这个项目里面拿.
你也可以做成一个只提供组件的项目,毕竟在运行时一个子模块挂载到我们的项目中来是没有任何资源消耗的.
我们只要知道我们需要的组件从哪里来就行了,然后根据组件还有之前定义好的路由找到这个组件,调用他,使用他就好了.
基于Web component封装我们的组件 不同框架开发的组件,差异很大.想要串在一起使用,基本上是不可能的. 好在目前所有的框架都支持让组件以webcomponent的形式存在.
react: https://react.docschina.org/docs/web-components.html
vue : https://github.com/vuejs/vue-web-component-wrapper
angular: https://www.angular.cn/guide/elements#transforming-components-to-custom-elements
关于Web Components 的详细介绍 https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
加载性能 如果一个页面依赖了很多跨框架的组件,必然出现网络方面的性能问题.
我们会在请求的中间加一层node服务,当页面请求多个跨框架的组件的时候,我们的node就会合并成单个文件,并且保存在硬盘上.
所以说,当这个页面被请求过之后,页面零散的组件便会合并在一起,第二次其他用户请求就不会有这种合并文件的处理,直接返回静态资源给客户端.
这种方式也不会对nodejs有太多额外的压力,
因为现在的页面结构还是相对静态稳定的,没有太多的动态定制化的东西.这个方案足以应付大多数的应用场景.
尾巴 经过不停的探索,微前端终于走到了微件化的这一步,感慨颇多~
我们从一个窗口只能加载单个页面, 再到多个页面(SPA), 再到现在的多个项目(微前端), 然后再可以控制不同组件在多个项目之间随意组合(微件化).
微前端的应用边界应该还可以拓展的更宽,还可以开发出更多惊喜的操作.
相关系列文章 https://alili.tech/tags/microfrontend/</description>
</item>
<item>
<title>前端微服务化进阶3 - 跨模块共享组件</title>
<link>https://alili.tech/archive/qh7x5i5szfh/</link>
<pubDate>Sun, 12 May 2019 22:17:36 +0000</pubDate>
<guid>https://alili.tech/archive/qh7x5i5szfh/</guid>
<description>前端微服务化之后,我们会面临一个问题: 模块之间重复代码不能复用的问题.
如果使用npm管理我们的重复代码,我们会多出维护npm包的成本. 在子模块更新npm包版本,也是一件很麻烦的事情. 在js文件体积上也没有任何的优化.
组件共享 今天我们就来聊一聊如何在多个模块中同时使用一个组件.
思路 在base模块管理公共组件,将组件封装成动态组件,这样在打包的时候我们就可以将该组件切割成单独文件了. 当其他的子模块需要这个组件的时候,向Base模块动态获取.
实践 动态组件的封装 为了让其他模块可以按需加载我们的公共组件,我们需要对已有的组件封装成动态组件.
我这里使用的是 umi/dynamic,
他是基于https://github.com/jamiebuilds/react-loadable 封装了一层. 有兴趣的小伙伴可以自行了解.
import React from 'react'; import dynamic from 'umi/dynamic'; import PageLoading from '@/components/PageLoading' export const Demo = dynamic(import( `../Demo`), {loading: () =&gt; &lt;PageLoading /&gt;}) export default Demo; 对外提供获取动态组件的方法 在加载Base模块的时候,我们可以在window下暴露一个调用该模块动态组件的方法
window.getDynamicComponent = async function(name) { let component = null; component = await import(`@/components/dynamic/${name}`); return component[name]; }; 子模块调用公共组件 因为base模块提供了一个获取公共组件的全局方法, 我们就可以在任何模块任何需要调用公共组件的地方去是使用它了.
// 获取组件 let component = await window.</description>
</item>
<item>
<title>前端微服务化进阶2 - 本地开发指南</title>
<link>https://alili.tech/archive/3xwbcv1w21i/</link>
<pubDate>Mon, 22 Apr 2019 22:17:36 +0000</pubDate>
<guid>https://alili.tech/archive/3xwbcv1w21i/</guid>
<description>使用single-spa构建我们的微服务化的前端应用之后,其实有一个问题会一直困扰着我们, 就是如何有效的开发?如何与我们平时开发的前端应用一样简单,容易上手. 今天就以umi子模块为例,希望给到大家一个思路
今天我就介绍一种方法,希望对大家有帮助.
模块加载器 是否还记得我之前的模块加载器, https://alili.tech/archive/1a60cede/
我们只需要将原来模块的加载器,封装成npm包.
然后在我们开发子模块项目的时候,运行我们的加载器 // umi src/app.js import bootstrap from '@demo/demo-module-dev-loader' //封装过后的npm包 import store from 'store'; // 我们用于通讯的store文件 export async function render(oldRender) { if (process.env.NODE_ENV === 'development') { const main = oldRender(); const res = await window.fetch('./project.json'); let currentProject = await res.json(); bootstrap({ main, store, prefix: currentProject.prefix }); } else { oldRender(); } } module-dev-loader 我们的demo-module-dev-loader里一样会有一个 Bootstrap.js文件,我们对他进行一些小的修改.
import * as singleSpa from 'single-spa'; import { registerApp,registerLocal } from '.</description>
</item>
<item>
<title>前端微服务化进阶1 - 基于umi的子模块方案</title>
<link>https://alili.tech/archive/9xuojm75d2a/</link>
<pubDate>Sat, 13 Apr 2019 22:17:36 +0000</pubDate>
<guid>https://alili.tech/archive/9xuojm75d2a/</guid>
<description>距离第一篇聊前端微服务的文章已经时隔大半年,很多人对此感兴趣.
今天我们就聊一聊,我们如何基于umi来打造一个更完善的前端微服务的子模块.
如果你用的是react以外的前端技术栈, 我的很多处理做法也可以应用在其他技术栈上.
希望对你也有所帮助.
优秀的umi框架 在前端中后台项目上,前端微服务化的需求相对是比较旺盛一些的.
说到中后台,很多企业都是基于antd的组件来构建自己的项目.
自去年的see conf之后,蚂蚁的一款可插拔的企业级 react 应用框架 umi发布了.
这款框架与antd息息相关,antd结合umi使用那是相当的自然与流畅.
可以说,基于umi与antd构建的项目非常的漂亮.这么优秀的框架,如果让他适用于我们的前端微服务架构,岂不美哉?
umi也有相关的类似微服务方案: https://github.com/umijs/umi-example-monorepo
但是umi提供的方案,有很大的局限性. 如果可以接入single-spa的微服务方案,独立开发,独立部署等等的前端微服务化红利, 会让你的项目日后有更大的发展空间.
基于umi插件机制做到前端微服务化 umi 提供了非常强大的插件机制,正是由于这一点,我们才可以让umi也可以接入到微服务架构中来
umi插件介绍 umi插件的基本介绍:
https://umijs.org/zh/plugin/
umi插件开发 这里介绍了如何开发一个简单的umi插件:
https://umijs.org/zh/plugin/develop.html
接入single-spa的umi插件 export default (api, opts) =&gt; { // 以下的所有代码都写在这里面哦 }; 渲染入口处理方法 定义一个动态的元素,当我们的base app 需要加载子模块的时候,会渲染出子模块需要渲染元素.
我们的子模块找到了自己模块需要渲染的节点的时候,就会渲染出来.
const domElementGetterStr = ` function domElementGetter() { let el = document.getElementById('submodule-page') if (!el) { el = document.createElement('div') el.id = 'submodule-page' } let timer = null timer = setInterval(() =&gt; { if (document.</description>
</item>
<item>
<title>记一次MongoDB迁移 - 备份与恢复</title>
<link>https://alili.tech/archive/7815p445rtf/</link>
<pubDate>Wed, 27 Mar 2019 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/7815p445rtf/</guid>
<description> 最近对自己的的爬虫数据库做了一次迁移,所以在这里记录一下mongodb的备份与恢复
MongoDB数据备份 mongodump -h dbhost -d dbname -o dbdirectory -h: MongDB所在服务器地址,例如:127.0.0.1,如果没有改的话一般是:127.0.0.1:27017
-d: 需要备份的数据库名字,例如:test
-o: 备份的数据存放位置,例如:/home/root/xxx,
MongoDB数据恢复 mongorestore -h &lt;hostname&gt;&lt;:port&gt; -d dbname &lt;path&gt; &ndash;host &lt;:port&gt;, -h &lt;:port&gt;: MongoDB所在服务器地址,默认为: localhost:27017
&ndash;db , -d : 需要备份的数据库名字,例如:test
&ndash;drop: 先删除现有的数据,再恢复数据
: 指定备份文件的目录
&ndash;dir: 指定备份文件的目录,不能同时指定 和 &ndash;dir 选项。
</description>
</item>
<item>
<title>一个两年前.gitattributes文件导致的bug</title>
<link>https://alili.tech/archive/zift8zkisnf/</link>
<pubDate>Thu, 24 Jan 2019 19:33:33 +0000</pubDate>
<guid>https://alili.tech/archive/zift8zkisnf/</guid>
<description>起因 一时兴起,我打开了我两年前写的一个前端项目开始代码审查. 这个项目我一个人写了两年,大概十几万行代码的样子.
发现这个项目的git居然把所有的代码文件都识别成了二进制文件. 这个问题,之前困扰了我很久,却一直找不到原因.导致我的代码没有对比记录.
再顽固的问题也有水落石出的一天
说巧不巧,今天偏偏找到了问题的源头.
.gitattributes 最后发现是因为.gitattributes文件有一行配置因为换行问题.导致所有text的文件都识别成了二进制文件.
.gitattributes的作用 .gitattributes文件是一个简单的text文本文件,它的作用是重新定义指定文件的属性, 指定非文本文件的对比合并方式
编写规则 pattern attr1 attr2 ... 示例 *.ttf binary *.woff binary *.eot binary *.otf binary * text=auto 上面这段代码表示,将一些字体文件指定为二进制文件,当提交代码的时候git不会diff这些文件的变动详情. 他只会告诉你,文件变动了,但是不会告诉你具体哪里变了.</description>
</item>
<item>
<title>LintCode 最长公共前缀</title>
<link>https://alili.tech/archive/an7l200dx1w/</link>
<pubDate>Sat, 19 Jan 2019 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/an7l200dx1w/</guid>
<description>编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 &ldquo;&ldquo;。
示例 1: 输入: [&quot;flower&quot;,&quot;flow&quot;,&quot;flight&quot;] 输出: &quot;fl&quot; 示例 2: 输入: [&quot;dog&quot;,&quot;racecar&quot;,&quot;car&quot;] 输出: &quot;&quot; 解释: 输入不存在公共前缀。 说明:
所有输入只包含小写字母 a-z 。
Javascript /** * @param {string[]} strs * @return {string} */ var longestCommonPrefix = function(strs) { if(strs.length === 0)return &quot;&quot; let current = &quot;&quot; let prefix = &quot;&quot; let index = 0; let isTrue = true; while (strs[0][index]) { //以第一个单词为基准 current = strs[0][index]; // 以第一个单词为基准 for(let i = 0; i &lt; strs.</description>
</item>
<item>
<title>LintCode 买卖股票的最佳时机 II</title>
<link>https://alili.tech/archive/n15zv1hxje/</link>
<pubDate>Sat, 12 Jan 2019 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/n15zv1hxje/</guid>
<description>给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1: 输入: [7,1,5,3,6,4] 输出: 7 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 示例 2: 输入: [1,2,3,4,5] 输出: 4 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 示例 3: 输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 Javascript /** * @param {number[]} prices * @return {number} */ var maxProfit = function(prices) { let n = 0; prices.</description>
</item>
<item>
<title>Canvas 处理跨域图片终极方案</title>
<link>https://alili.tech/archive/g6kghla5ugc/</link>
<pubDate>Thu, 10 Jan 2019 16:14:25 +0000</pubDate>
<guid>https://alili.tech/archive/g6kghla5ugc/</guid>
<description>浏览器因为安全问题,是不允许Canvas使用 getImageDatatoDataURL 处理跨域获取的图片的.
传统解决方法 1.服务器需要配置Access-Control-Allow-Origin 相信这一行代码,大家见过太多,我就赘述了
header(&quot;Access-Control-Allow-Origin: 你的域名&quot;); 2.设置crossOrigin属性 var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); var img = new Image(); img.crossOrigin = 'anonymous'; //就是这行代码 img.onload = function () { context.drawImage(this, 0, 0); context.getImageData(0, 0, this.width, this.height); }; img.src = 'https://avatars3.xxxx.com/u/496048'; 到这里,你的跨域问题已经基本解决. 但是因为一些客观因素后端工程师拒绝帮你设置跨域头,那你该怎么办?
终极解决方案
大致思路是 使用ajax获取到图片,然后使用 FileReader转成base64;再使用canvas处理base64格式的图片就好了.
获取图片的base64 function getBase64(imgUrl) { return new Promise(((resolve, reject) =&gt; { window.URL = window.URL || window.webkitURL; // 声明一个XMLHttpRequest const xhr = new XMLHttpRequest(); // 获取图片 xhr.</description>
</item>
<item>
<title>Git大小写不敏感导致的烦人问题</title>
<link>https://alili.tech/archive/rrc7ngyr5rp/</link>
<pubDate>Wed, 09 Jan 2019 19:33:33 +0000</pubDate>
<guid>https://alili.tech/archive/rrc7ngyr5rp/</guid>
<description>因为同事把一个文件夹的小写改成了大写,导致我本地的提交不能直接push rebase 等一些列操作.恼的很~
error: The following untracked working tree files would be overwritten by checkout: xxx.js Please move or remove them before you can switch branches. Aborting 解决办法 设置为大小写敏感(问题解决后,一定要还原配置)
git config core.ignorecase false 尽管设置大小写敏感之后,始终会影响其他分支的代码,所以不建议一直使用这个配置,当问题解决之后,还是要改回去.
改回默认 git config core.ignorecase true # or git config --unset core.ignorecase 尾巴 平时编码的时候,还是千万不要直接重命名大小写,自己本地看起来没有什么问题.在别人问题上却是大问题.
如果发生了类似问题的,应该在源头解决(谁机器上重命名的,谁改回去).如果不解决的,应该拖出去打~~</description>
</item>
<item>
<title>Visual Studio Code 下的 jsconfig.json</title>
<link>https://alili.tech/archive/ltucv5fyj9/</link>
<pubDate>Tue, 08 Jan 2019 19:33:33 +0000</pubDate>
<guid>https://alili.tech/archive/ltucv5fyj9/</guid>
<description>今天聊聊 Visual Studio Code 的jsconfig.json配置小技巧.
jsconfig.json 是什么? 如果你的项目中有一个 jsconfig.json文件的话,这个文件的配置可以对你的文件所在目录下的所有js代码做出个性化支持.
Tip: 如果你在项目中新加了这个文件,记得重启一下vscode哦~
例子 exclude 属性 当vscode扫描项目代码的时候,如果遇到了node_module的话是会变得很慢的.
如果想要编辑器的性能有一个提升的话,我们应该排除这个文件夹.
{ &quot;exclude&quot;: [ &quot;node_modules&quot; ] } include 属性 当然还有相对的include属性
{ &quot;include&quot;: [ &quot;src/**/*&quot; ] } webpack aliases 的支持 如果我们在我们的webpack里面配置的路径的别名,心细的小朋友就发现了. 我们的vscode不能根据别名路径导入的包跳转文件了.所以我们还需要jsconfig.json的支持.
{ &quot;compilerOptions&quot;: { &quot;baseUrl&quot;: &quot;.&quot;, &quot;paths&quot;: { &quot;@component&quot;: [&quot;./src/component&quot;] } } } jsconfig.json的配置是tsconfig.json的子集,
以后有机会的话聊一聊tsconfig.json.
今天就到这里~</description>
</item>
<item>
<title>幕后英雄Abstract syntax tree抽象语法树</title>
<link>https://alili.tech/archive/9rfliipfkip/</link>
<pubDate>Thu, 03 Jan 2019 17:33:33 +0000</pubDate>
<guid>https://alili.tech/archive/9rfliipfkip/</guid>
<description>抽象语法树 AST 在计算机科学中,抽象语法树,或简称语法树,是源代码语法结构的一种抽象表示.
这里介绍一个网站 https://astexplorer.net ,可以让你清晰的看到一段js,css以及其他语言被转换成语法树的样子.
在我们的浏览器中,也会对我们的js代码解析成抽象语法书然后再进一步的分析以及下一步的操作.
语法树就前端而言,被利用在各种地方,代码语法的检查,代码风格的检查,代码的格式化,代码的高亮,代码错误提示,代码自动补全,比如:
eslint JSHint babel webpack rollup UglifyJS2 等等等等&hellip; 根本数不过来.
举个例子 一段代码被解析成语法树后的样子 目前业界对抽象语法树是有规范的, 感兴趣的朋友可以查看这个网址: SpiderMonkey
let str ='我是字符串'; to AST
{ &quot;type&quot;: &quot;Program&quot;, &quot;start&quot;: 0, &quot;end&quot;: 17, &quot;body&quot;: [ { &quot;type&quot;: &quot;VariableDeclaration&quot;, &quot;start&quot;: 0, &quot;end&quot;: 17, &quot;declarations&quot;: [ { &quot;type&quot;: &quot;VariableDeclarator&quot;, &quot;start&quot;: 4, &quot;end&quot;: 16, &quot;id&quot;: { &quot;type&quot;: &quot;Identifier&quot;, &quot;start&quot;: 4, &quot;end&quot;: 7, &quot;name&quot;: &quot;str&quot; }, &quot;init&quot;: { &quot;type&quot;: &quot;Literal&quot;, &quot;start&quot;: 9, &quot;end&quot;: 16, &quot;value&quot;: &quot;我是字符串&quot;, &quot;raw&quot;: &quot;'我是字符串'&quot; } } ], &quot;kind&quot;: &quot;let&quot; } ], &quot;sourceType&quot;: &quot;module&quot; } Nodejs解析抽象语法树的工具 常用js解析工具 esprima traceur acorn shift 使用esprima举个例子 # node环境 &gt; var esprima = require('esprima'); &gt; var program = 'const answer = 42'; &gt; esprima.</description>
</item>
<item>
<title>2018 年终有感</title>
<link>https://alili.tech/archive/53ogpu5lzuh/</link>
<pubDate>Sat, 29 Dec 2018 21:29:00 +0000</pubDate>
<guid>https://alili.tech/archive/53ogpu5lzuh/</guid>
<description>今天是今年的最后一个工作日,现在我在高铁上.已经习惯在高铁上用电脑折腾点什么. 回想起来,不知道在高铁上发过多少次版本,fix掉了多少个bug.啊哈哈~
回看今年的2018,对于我来说是传奇的,是曲折的,甚至是有点丧的.幸运的是个人成长并没有客观原因而耽误.
我的团队 回想到今年7月份,亲手组建的前端团队因为大环境的原因而解散,确实是很痛心的. 如果按照正常来发展,我想应该可以打造成我心目中的Dream Team了吧.至少各个对技术是那么的有热情.
成长要与时间赛跑 不过一切都没有关系,今年也不过刚满26,以后有的是机会.我经常这样安慰我自己.恐怕再过两年,这就不是自我安慰的理由了. 唯一要做的就是个人成长必须要与时间赛跑.
今年去参加ng china的时候,让我非常有印象的一场演讲是雪狼的. 其中有一段大意是根据我们现在信息爆炸的年代,我们的成长应该古人早十年:
二十而立
三十不惑
四十知天命
五十耳顺
六十从心所欲
对此,我是十份赞同的.
焦虑的一年 2018年对于我来说,是焦虑的一年.因为自身的焦虑,促使自己每天都在不断学习与进步~ 当然今年也错过了很多不错的机会.现在想起来,还是自己太年轻了,没有见过大人物,看到偶像立马就怂了. 不过还是随时整装待发,随时面对新挑战.
关于博客 今年博客可以说是大升级了,界面看起来差不多,但是内部基本上重写了一遍. 还专门做了SEO,甚至还跑到 segmentfault 去打了一个星期的广告,哈哈哈~ 虽然宣传效果没有达到预期~
以前没有专门的做统计,自10月上线统计以来,看了一下网站的总访问量已经到达了10W+. 我不知道其他的博客主的网站数据是怎么样的,但是按照现在趋势. 访问量还是在缓慢的增加.每天看到那些统计数据,还是非常有意思的.
从之前每周强制写一篇,到现在的每周强制自己写三篇.写一些自己正在做的,看到的,有意思的技术总结.有时候是一些很小的技术点,有一些也是我研究了很久,有一定系统性的东西.写博客对我来说是一种非常有效率的学习方式.以后应该还会坚持.不过也说不上坚持吧,渐渐的已经成为了一种爱好与习惯. 希望这种习惯,可以让自己的技能可以有发挥的地方.有一个组织与自己互利互惠,相互成长,得到各自想要的东西.
关于家庭 关于家庭,今年1月份我儿子小可乐出生了,直到小可乐出生很久,我都没能让自己非常喜欢小孩. 不知道是因为自己是独生子或者从来没有跟自己年龄小的人相处的原因. 现在看,我身边的朋友大多都比我大个五六七八岁的. 但是现在,相处的越久发现这种与儿子的羁绊越来越深.希望以后可以跟他成为好朋友,甚至是好兄弟,好导师.
至少我们现在看到的世界,比我们父辈的那一代要大很多. 我们要学习父辈的智慧,重新看待与审视这个世界. 智慧这个东西,很有意思~ 不管放在哪个时代都是可以直接复用的.
关于技术 今年我有听到一些话,让我深深的陷入思考.我一同事跟我说: &ldquo;我对技术没有你那么高的热情,我只是为了谋生&rdquo;. 我很排斥这种说法,但是又不得不承认很多人是这样. 这是不是很多时候面试,别人问你是不是计算机专业出身的一样.
我问自己,我学习这么多的知识是谋生吗? 最终我想了想,得到了答案: 学习这些技术是一个让我理解这个世界的途径. 我想我能有一个这样的理解,是因为我比较幸运吧~ 虽然生活压力还是有的,但也没有那么大~是吧? (突然脑子想到那个段子~)
我一直觉得我有一个问题,我眼中总是只能看到比我优秀的人,看着他们如此优秀,让自己无比焦虑.
有时候我对自己说,我是不是偶尔也向后看看? 可以自己释怀很多~ 但是很多时候又觉得自己办不到? 这算不算习惯性见贤思齐的一种表现~ 我觉得这是病,时间久了多多少少还是会有一些问题的.
关于2019 2019我觉得没有什么可计划的,要是真有计划那也是把2018年一直坚持的事情继续做下去.</description>
</item>
<item>
<title>聊聊HTTP的X-Forwarded-For 和 X-Real-IP</title>
<link>https://alili.tech/archive/izbidk3gu3s/</link>
<pubDate>Sat, 29 Dec 2018 16:14:25 +0000</pubDate>
<guid>https://alili.tech/archive/izbidk3gu3s/</guid>
<description>最近在看网易云音乐API nodejs这个项目的文档的时候.
发现调用须知里,有一段是这样的说的:
由于网易限制,此项目在国外服务器上使用会受到限制,如需解决 , 可使用大陆服务器或者使用代理 , 感谢 @hiyangguo提出的解决方法: 在 &lsquo;util.js&rsquo; 的 &lsquo;headers&rsquo; 处增加 X-Real-IP&rsquo;:&lsquo;211.161.244.70&rsquo; // 任意国内 IP 即可解决
网易云音乐的接口调用对国外加了限制,想要跳过这样的限制的话,就必须在headers里修改X-Real-IP 就可以解决.
那X-Real-IP是什么?是干什么用的?
X-Real-IP X-Real-IP,这是一个自定义头部字段。X-Real-IP 通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端。需要注意的是,X-Real-IP 目前并不属于任何标准,
跟他非常相关的,还有一个X-Forwarded-For的自定义头部字段.
X-Forwarded-For X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。
格式:
X-Forwarded-For: client, proxy1, proxy2 如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:
X-Forwarded-For: IP0, IP1, IP2 X-Forwarded-For 会记录用户ip与每次转发用的代理服务器ip.</description>
</item>
<item>
<title>Angular路径别名配置</title>
<link>https://alili.tech/archive/3u54dxnerfn/</link>
<pubDate>Thu, 27 Dec 2018 22:17:36 +0000</pubDate>
<guid>https://alili.tech/archive/3u54dxnerfn/</guid>
<description>angular cli 内置了 webpack,所以也是可以配置路径别名的. 而且配置的方式几乎是一样的.
配置路径别名 找到你的项目根目录的 tsconfig.json 文件.
注意: 如果你的配置不生效,需要查看你的baseUrl是否配置正确.
{ &quot;compilerOptions&quot;: { &quot;baseUrl&quot;: &quot;./src/&quot;, &quot;paths&quot;: { &quot;@app/*&quot;: [&quot;app/*&quot;], &quot;@services/*&quot;: [&quot;app/services/*&quot;] } } } 配置之前 import { Api } from '../../../../../services/api.service'; import { xxx } from '../../../../../services/api.xxx'; 配置之后 import { Api } from '@services/api.service'; import { xxx } from '@services/api.xxx'; 一些开发中的小技巧,希望可以帮到你.</description>
</item>
<item>
<title>Typescript的福音:Json To Interface</title>
<link>https://alili.tech/archive/ijfdh4ry66c/</link>
<pubDate>Tue, 25 Dec 2018 19:33:33 +0000</pubDate>
<guid>https://alili.tech/archive/ijfdh4ry66c/</guid>
<description> 在我们使用ts的时候,我们需要写大量的 Interface.
但是我们一条json数据的字段实在是太多了,一个一个写的话不仅会花费大量的时间.
在团队内部推广Typescript,因为使用问题导致推广层层阻碍,最后放弃使用屡见不鲜.
今天推荐的这个插件,希望可以帮到你.
JSON to TS 插件 安装 ext install json-to-ts 复制到剪贴板后 运行快捷键 (Ctrl + Alt + V) 鼠标选中后 运行快捷键 (Ctrl + Alt + S) 已知问题 linux 已知问题 Command failed: xclip -selection clipboard -o 解决方法 sudo apt-get install xclip </description>
</item>
<item>
<title>Centos7 如何使用yum升级git到最新版本</title>
<link>https://alili.tech/archive/cue4m2rioxl/</link>
<pubDate>Mon, 24 Dec 2018 20:32:05 +0000</pubDate>
<guid>https://alili.tech/archive/cue4m2rioxl/</guid>
<description> yum upgrade 并不能升级git到最新版本 在centos7 默认的git版本是1.8.x
查看本机git版本 git --version git version 1.8.3.1 如果你想使用yum升级到2.0+的版本
直接yum升级并不会升级到最新版本 yum -y upgrade git git version 1.8.3.1 但是我又不想下载源码包,在本机编译然后输出环境变量那种方式. 还是太麻烦了.
yum升级git版本到2.0+ Git第三方仓库安装(IUS) # 安装使用里面说的自动化安装脚本 curl https://setup.ius.io | sh yum search git # 删除本机git,安装git2u yum remove -y git | yum -y install git2u # 查看当前版本 git --version # 成功升级 &gt; git version 2.16.4 </description>
</item>
<item>
<title>推荐一个Angular Electron 开箱即用的项目工程模板</title>
<link>https://alili.tech/archive/cr8ze8vvvbw/</link>
<pubDate>Thu, 20 Dec 2018 19:02:36 +0000</pubDate>
<guid>https://alili.tech/archive/cr8ze8vvvbw/</guid>
<description>在angular官网是有提供官方的 electron 的angular版本的模板. 但是版本是2.0的实在是太旧了.估计也不会再有人维护了吧. 但是至今还挂载官网上. 让很多新手,至少让我刚开始的时候误以为没有一个比较新的好用的electron的模板,可以快速的创建项目.
Angular-electron 这里推荐一个完成度非常高的模板,开箱即用
https://github.com/maximegris/angular-electron</description>
</item>
<item>
<title>Angular7 + Electron主进程与渲染进程通讯问题</title>
<link>https://alili.tech/archive/pw9ygknqvso/</link>
<pubDate>Wed, 19 Dec 2018 19:02:36 +0000</pubDate>
<guid>https://alili.tech/archive/pw9ygknqvso/</guid>
<description>Electron 中的进程分类 在 Electron 中,存在两种进程:主进程和渲染进程。
渲染进程你可以理解为view层,也就是我们非常熟悉的显示页面的进程. 在这里你可以调用nodejs接口的能力,也可以做我们已经非常熟悉的浏览器操作. 但是你想要调用主进程才能做的一些操作的时候,就需要一个通讯机制,告诉主进程你要干嘛干嘛.
IPC通讯 渲染层向主进程发送通知 //index.html,渲染进程发送通知 onst electron = require('electron') const ipcRenderer = electron.ipcRenderer ipcRenderer.send('main-process-messages','hellow') // main.js 主进程接收通知 const { ipcMain } = require('electron'); ipcMain.on('main-process-messages', function(event, message) { console.log(message) }); 主进程向渲染进程发送通知 // main.js mainWindow.webContents.send('main-process-messages', 'main-process-messages show') //index.html,渲染进程中接收消息 const electron = require('electron') const ipcRenderer = electron.ipcRenderer ipcRenderer.on('main-process-messages', function(event, message){ alert(message) }) 在Angular工程中如何使用 当你在angular工程中直接require('electron')是会直接报错的.
ERROR in ./node_modules/electron/index.js Module not found: Error: Can't resolve 'fs' in '###/node_modules/electron' ERROR in .</description>
</item>
<item>
<title>从零搭建 Angular7 + Electron 桌面应用</title>
<link>https://alili.tech/archive/i15aswl1v4s/</link>
<pubDate>Tue, 18 Dec 2018 19:02:36 +0000</pubDate>
<guid>https://alili.tech/archive/i15aswl1v4s/</guid>
<description>Electron 是什么? Electron 是一个可以用 JavaScript、HTML 和 CSS 构建桌面应用程序的库。这些应用程序能打包到 Mac、Windows 和 Linux 系统上运行,也能上架到 Mac 和 Windows 的 App Store。 意思就是说,你只要拥有前端开发的能力,也可以轻松开发跨平台的桌面应用.
Electron的『主进程』和『渲染进程』 Electron 有两种进程:『主进程』和『渲染进程』。部分模块只能在两者之一上运行,而有些则无限制。主进程更多地充当幕后角色,而渲染进程则是应用程序的各个窗口。
主进程 主进程,通常是一个命名为 main.js 的文件,该文件是每个 Electron 应用的入口。它控制了应用的生命周期(从打开到关闭)。它既能调用原生元素,也能创建新的(多个)渲染进程。另外,Node API 是内置其中的。
渲染进程 渲染进程是应用的一个浏览器窗口。与主进程不同,它能存在多个(注:一个 Electron 应用只能存在一个主进程)并且相互独立(它也能是隐藏的)。
主窗口通常被命名为 index.html。它们就像典型的 HTML 文件,但 Electron 赋予了它们完整的 Node API。因此,这也是它与浏览器的区别。
进程之间的通讯 (IPC) 想要再网页里调用主进程的功能,比如关闭窗口,最小化全屏等主线程才能控制的功能. Electron提供了通讯的机制,这就是IPC.后续会慢慢介绍IPC的使用.
Angular7 + Electron 介绍完Electron的一些基础概念之后, 这里教大家徒手搭建一个基于ng7的桌面应用工程.
1. 安装最新angular-cli npm i -g @angular/cli 2. 生成一个angular工程 ng new electro-angular7 3. 安装最新版electron cd electro-angular7 npm install --save-dev electron@latest 4.</description>
</item>
<item>
<title>记2018年最后一次前端分享(提供Slides)</title>
<link>https://alili.tech/archive/unui11c01ml/</link>
<pubDate>Thu, 13 Dec 2018 21:32:05 +0000</pubDate>
<guid>https://alili.tech/archive/unui11c01ml/</guid>
<description> $(function(){ let str = "" for(var i = 2;i=10){ count = "0"+ i; } str = str + '' } $('.imageBox').html(str) var images = document.querySelectorAll(".lazyload"); lazyload(images); }) </description>
</item>
<item>
<title>使用husky提升Code Review的效率</title>
<link>https://alili.tech/archive/i9t0x2tvleo/</link>
<pubDate>Tue, 04 Dec 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/i9t0x2tvleo/</guid>
<description>在code review的时候,代码风格是其中审查的指标之一.在审查代码风格其实是有一定工作量的.
为了减少代码审查的工作量,我们何不把代码风格在提交代码之前就规范掉?
这样我们就可以在代码审查中节约出很多时间,来做更多的其他更有意义的事情.
git hooks 在git中提供了hook,就是在触发代码提交,push等一系列操作的时候,提供了触发其他程序的钩子.
如何操作,本文不多赘述.
有兴趣的同学可以查看文档: https://git-scm.com/docs/githooks
husky 如果看过githooks的文档,是不是觉得会有一点繁琐?
这里介绍一个工具 husky 可以解决你的问题.
安装 npm install husky --save-dev 然后修改 package.json,增加配置:
{ &quot;husky&quot;: { &quot;hooks&quot;: { &quot;pre-commit&quot;: &quot;eslint .&quot; } }, } 如果你只是局部安装了 eslint,请使用以下配置
{ &quot;lint-staged&quot;: { &quot;src/**/*.js&quot;: [ &quot;node_modules/.bin/eslint&quot; ] }, } 最后尝试 Git 提交,你就会很快收到反馈:
git commit -m &quot;this is a commit&quot; 这样,我们就可以在代码提交之前验证一下我们的代码lint是否通过.
对于一些以前从来没有用过eslint的项目来说.突然引入这种工具.
你可能面临的是把所有文件都按照eslint都格式化一遍.那不是疯了吗?
lint-staged 这里再安利一个工具,可以实现 eslint只检查本次提交的文件. 这样我们就可以做到渐进式的改善我们的代码质量.
安装 npm install lint-staged --save-dev 修改 package.</description>
</item>
<item>
<title>让团队保持Code Review习惯的三大法宝</title>
<link>https://alili.tech/archive/1479pecm0mbo/</link>
<pubDate>Fri, 30 Nov 2018 14:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/1479pecm0mbo/</guid>
<description>之前跟大家聊过代码审查,想要在团队中保持团队代码审查习惯,是相当困难的. 我们必须要有合理的流程,工具与制度的支持,才能基本保证我们代码审查效率与质量.
流程支持:Gitflow 之前有介绍Gitflow的工作流.
大致如下:
开发者在本地仓库中新建一个专门的分支开发功能。 开发者push分支修改到公开的Git仓库中。 开发者通过Git发起一个Merge Request。 团队的其它成员代码审查,讨论并修改。 项目维护者合并功能到官方仓库中并关闭Merge Request。 工具支持 强制使用eslint 强制使用eslint,在代码未提交之前,是用husky等工具做强制eslint. 保证提交之后的代码,必须先过一遍eslint.
规范提交代码的类型 我们自己内部开发了一款简单的命令行工具,可以在我们提交代码的时候,定义本次提交的类型.
方便我们后续在代码审查的时候,更加容易的理解修改的内容.
类型如下 bug修复 新特性 样式修复 代码重构 测试代码 代码回滚 bug修复 文档更新 临时提交 命令行使用方式 ? What do you want to do? 代码提交 ? 请选择Git提交类型? (Use arrow keys) ❯ * fixed : bug修复 * feature : 新特性 * style : 样式修复 * refactor : 代码重构 * test : 测试代码 * revert : 代码回滚 * doc : 文档更新 (Move up and down to reveal more choices) Code Climate Code Climate是一款代码测试工具,它可以帮助你进行代码冗余检测、质量评估,同时支持多种语言,如PHP, Ruby, JavaScript, CSS, Golang, Python 等。</description>
</item>
<item>
<title>cheeriojs加载html时中文会默认解析成unicode的问题</title>
<link>https://alili.tech/archive/lbpnt17e1sc/</link>
<pubDate>Thu, 29 Nov 2018 20:32:05 +0000</pubDate>
<guid>https://alili.tech/archive/lbpnt17e1sc/</guid>
<description> cheeriojs 解析中文为unicode问题 在使用cheeriojs的时候我发现,每当使用html方法,中文会默认解析成 unicode.
使用方式如下:
var cheerio = require('cheerio'); var $ = cheerio.load('&lt;title&gt;我是中文,我将会被解析成unicode&lt;/title&gt;'); console.log($('title').html()); 当使用text方法的时候,并不会出现以上问题
var cheerio = require('cheerio'); var $ = cheerio.load('&lt;title&gt;我是中文,我将会被解析成unicode&lt;/title&gt;'); $('title').text() 解决 默认配置 当我们load html内容的时候,其实cheerio是有默认配置的. html解析是使用的htmlparser2这个库,所以htmlparser2的配置在cheerio也是适用的.
var cheerio = require('cheerio'); var $ = cheerio.load('&lt;title&gt;我是中文,我将会被解析成unicode&lt;/title&gt;',{ withDomLvl1: true, normalizeWhitespace: false, xmlMode: false, decodeEntities: true }); 修改默认配置 我们只需要将decodeEntities修改成 false,就可以解决我们的问题.
{ decodeEntities: false } 像这样
var cheerio = require('cheerio'); var $ = cheerio.load('&lt;title&gt;我是中文,我将不会被解析成unicode&lt;/title&gt;',{ decodeEntities: false }); </description>
</item>
<item>
<title>从前端角度来看声明式编程与命令式编程</title>
<link>https://alili.tech/archive/sdwn0mwjjj8/</link>
<pubDate>Mon, 26 Nov 2018 11:46:35 +0000</pubDate>
<guid>https://alili.tech/archive/sdwn0mwjjj8/</guid>
<description>引入概念 声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。 命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。 怎么去解释以上两句话呢?
我们带着这两个概念,用我们最熟悉的技术来解释两种编程范式
声明式编程 (Declarative Programming) 告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。
...more code &lt;/head&gt; &lt;body&gt; &lt;div id=&quot;box&quot;&gt;声明式编程&lt;/div&gt; &lt;/body&gt; &lt;/html&gt; #box { width: 100px; height: 100px; color: #fff; background: #000; } 命令式编程 (Imperative Programming) 命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。
var oDIv = document.createElement(&quot;div&quot;); var text = document.createTextNode(&quot;命令式编程&quot;); oDIv.appendChild(text); oDIv.id = &quot;box&quot;; oDIv.style.width = 100 + &quot;px&quot;; oDIv.style.height = 100 + &quot;px&quot;; oDIv.style.color = &quot;#FFF&quot;; oDIv.style.background = &quot;#000&quot;; document.body.appendChild(oDIv); 总结 以上两个例子,得到的结果是一模一样的.
在我看来,声明式的背后是代码实现的高度抽象,声明式会让工作得到简化.</description>
</item>
<item>
<title>Angular模板的安全导航( ?. )</title>
<link>https://alili.tech/archive/f16eaj0p4la/</link>
<pubDate>Sun, 25 Nov 2018 22:17:36 +0000</pubDate>
<guid>https://alili.tech/archive/f16eaj0p4la/</guid>
<description>这是非常实用,也是在Angular开发中经常要使用的操作符. 而在react于vue中原生并不自带这样的特性.
安全导航操作符 ( ?. ) 在我们日常开发中,在访问属性路径的时候.
如果因为一些客观原因导致了路径中出现了 null,undefined,再往下取值,整个程序就会直接报错.导致程序不能往下运行.
举个例子
var obj ={ a:1, b:{ // 有时候,有可能这个属性不存在 c:2, d:3 } } obj.a //正常取值 obj.b //如果这个属性有时候不存在,这样取值的话,也只是取到一个 undefined,并不会报错 obj.b.c //当b属性不存在的时候,在undefined下取值,就绝对会造成程序崩溃 安全导航就是要解决以上都问题,我们只要在不确定的属性前的 .改成 ?.就可以不需要报错了,当没有取到值的时候,会默认为空.
{{ obj?.b?.c }} 在写模板的时候是不是很方便呢? 简直不能太棒了好伐~
妈妈再也不用担心后台给的数据很奇怪导致我前端报错了~~~~~</description>
</item>
<item>
<title>使用Travis CI自动化部署你的Hugo,Hexo博客</title>
<link>https://alili.tech/archive/oj8dtatmwzg/</link>
<pubDate>Tue, 20 Nov 2018 16:14:25 +0000</pubDate>
<guid>https://alili.tech/archive/oj8dtatmwzg/</guid>
<description>Travis CI是什么? Travis CI是在线托管的CI服务,用Travis来进行持续集成,不需要自己搭服务器。最重要的是,它对开源项目是免费的。 如果公司是用的是 gitlab,也有提供相应的持续集成服务.这里就过多赘述.
Travis CI 配置文件 Travis 要求项目的根目录下面,必须有一个.travis.yml文件。
当你的仓库有提交的时候,travis会自动执行你下面配置的行为.
Travis CI 的钩子与生命周期 Travis的钩子 Travis 有不同的阶段,他提供了7个钩子。
before_install:install 阶段之前执行 before_script:script 阶段之前执行 after_failure:script 阶段失败时执行 after_success:script 阶段成功时执行 before_deploy:deploy 步骤之前执行 after_deploy:deploy 步骤之后执行 after_script:script 阶段之后执行 生命周期 before_install install before_script script aftersuccess or afterfailure [OPTIONAL] before_deploy [OPTIONAL] deploy [OPTIONAL] after_deploy after_script .travis.yml 下面是我的博客部署配置,也是我项目.travis.yml文件的内容.
hugo 这是我的hugo部署配置,仅供参考
language: node_js node_js: 10.13.0 install: - wget https://github.com/gohugoio/hugo/releases/download/v0.51/hugo_0.51_Linux-64bit.deb - sudo dpkg -i hugo*.deb - hugo version - rm -rf public - npm install script: - hugo --buildFuture - gulp - echo 'Build done!</description>
</item>
<item>
<title>让你的Hugo博客支持echarts图表</title>
<link>https://alili.tech/archive/r5ibcpo557h/</link>
<pubDate>Mon, 19 Nov 2018 16:14:25 +0000</pubDate>
<guid>https://alili.tech/archive/r5ibcpo557h/</guid>
<description>在之前hexo构建的博客里,有使用到图表,但是现在迁移到hugo之后,就没有相关的插件支持了.
所以自己动手丰衣足食.
在hugo中有支持一种特性叫做 Shortcodes.简单的来说就是一个可以传参的小模板.
创建Shortcodes 创建 ./layouts/Shortcodes/echarts.html文件
&lt;div id=&quot;echarts{{ .Get `height` }}&quot; style=&quot;width: 100%;height: {{.Get `height`}}px;margin: 0 auto&quot;&gt;&lt;/div&gt; &lt;script src=&quot;https://cdn.bootcss.com/echarts/3.8.0/echarts.common.min.js&quot;&gt;&lt;/script&gt; &lt;script type=&quot;text/javascript&quot;&gt; // 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('echarts{{ .Get `height` }}')); // 指定图表的配置项和数据 var option = JSON.parse({{ .Inner }}) // 使用刚指定的配置项和数据显示图表。 myChart.setOption(option); &lt;/script&gt; 使用 在 Shortcodes 插入echarts的配置数据,这样你就可以再页面中看到一个完整的图表了
Hello Alili | 前端大爆炸! - WEB BANG! BANG!! BANG!!! 前端大爆炸,一个前端技术博客.每天碰到那么多问题,终归还是需要一个记录的地方. 本文资源来源互联网,仅供学习研究使用,版权归该资源的合法拥有者所有, Hello Alili, 前端大爆炸, WEB BANG BANG BANG, web前端博客, 前端模块化, 前端工程化, 前端数据监控, 性能优化, 网页制作, 前端, js, html5, css, 踩坑小报告, 微前端, 树莓派, 前端开发, 区块链, 网络, Mongodb, Vue.</description>
</item>
<item>
<title>Hugo平台博文指定时间之后不显示?</title>
<link>https://alili.tech/archive/yqufemb0c1m/</link>
<pubDate>Sun, 18 Nov 2018 16:14:25 +0000</pubDate>
<guid>https://alili.tech/archive/yqufemb0c1m/</guid>
<description> 自从博客切换到Hugo之后,是遇到了一些坑.
明明正确添加到文章,页面时间调整到今天,或者是今天之后缺不能显示在文章列表里.
原因是Hugo模板在循环遍历文件的时候,只要超过当前时间的文章都不会出现.
时区问题 如果你的文章时间没有指定时区的话.
像这样2018-11-19 16:14:25,很有可能文章不会显示.
Hugo时间统一为格林威治时间,因为中国的时间比格林威治时间早8个小时. 格林威治时间没有到你配置的时间的时候,文章是不会出现在文章列表里的.
解决方案 本地服务
hugo server --buildFuture 页面生成
hugo --buildFuture </description>
</item>
<item>
<title>Hugo博客百度SEO终极优化,熊掌号自动推送</title>
<link>https://alili.tech/archive/0xh05yxhj3yq/</link>
<pubDate>Sat, 17 Nov 2018 16:14:25 +0000</pubDate>
<guid>https://alili.tech/archive/0xh05yxhj3yq/</guid>
<description>在切换到Hugo平台之后,比较头疼的是之前hexo很多seo的插件不能使用了. 下面跟大家说一下我的seo优化方案.
Meta标签优化 Description meta description,被认为是最有用的meta标签,是网站的简介信息。 content控制在100个字符以内比较好。
&lt;meta name='description' itemprop=&quot;description&quot; content=&quot;{{ if .Description }}{{ .Description }}{{ else }}{{if .IsPage}}{{substr .Summary 0 100}}{{ end }}{{ end }}&quot;&gt; Keywords {{ if .Keywords }} &lt;meta name=&quot;keywords&quot; content=&quot;{{ delimit .Keywords &quot;, &quot; }}&quot; &gt; {{else}} &lt;meta name=&quot;keywords&quot; content=&quot;{{ delimit .Site.Params.Keywords &quot;, &quot; }}&quot; &gt; {{ end }} 百度熊掌号推送 说到seo熊掌号是必不可少的了,他可以做到24小时之内收录.所以这个必须不能放过.
gulp 在这里我要使用gulp来做我的自动化任务管理工具
安装gulp需要的模块 npm init npm install gulp --save npm install xml2js --save npm install xmlhttprequest --save 在项目根目录创建一个gulpfile.</description>
</item>
<item>
<title>博客构建工具Hugo的基本使用</title>
<link>https://alili.tech/archive/obvozmdf/</link>
<pubDate>Thu, 15 Nov 2018 16:14:25 +0000</pubDate>
<guid>https://alili.tech/archive/obvozmdf/</guid>
<description>最终还是把博客迁移到了Hugo,当初最纠结的是这套主题在Hugo平台上没有. 但是脑子一热,花了两三天时间。这套主题。全部迁移到了Hugo平台。 接下来就给大家介绍一下Hugo的使用以及踩到的坑,以及解决方案.
Hugo的性能 正是因为hexo的性能不能满足,在生成静态文件的时候极其不稳定.而且时间也相对比较长一些. 在相同页面数量的情况下,处理速度hugo是hexo20倍及以上.这才是我换Hugo的原因.
配置文件 两个平台有很多共通的地方,迁移起来有很多工作是非常顺其自然的. 在配置文件上hugo也是可以使用yaml的,所以从hexo迁移过来会相对好很多. 其次hugo还可以使用json作为配置文件,为用户提供了很多选择.
Hugo的基本使用 Mac平台下 Mac下Hugo提供了homebrew安装的方式,非常简便。
brew install hugo Debian and Ubuntu平台下
sudo apt-get install hugo Windows平台下 Windows下Hugo提供了Chocolatey方式的安装,通过如下命令即可。
choco install hugo -confirm 验证安装
安转完成后,我们打开终端,输入如下命令进行验证是否安装成功
hugo version 创建一个站点 hugo new site quickstart 添加一个主题 cd quickstart;\ git init;\ git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke;\ # 编辑你的 config.toml 配置文件 # 添加一个叫 Ananke 的主题 echo 'theme = &quot;ananke&quot;' &gt;&gt; config.toml 新建一篇文章 hugo new posts/my-first-post.</description>
</item>
<item>
<title>Hexo Process Out of Memory 内存溢出问题</title>
<link>https://alili.tech/archive/c38d0045/</link>
<pubDate>Tue, 13 Nov 2018 21:32:05 +0000</pubDate>
<guid>https://alili.tech/archive/c38d0045/</guid>
<description>hexo内存溢出问题 当hexo生成文章大概在1000左右的时候,便有可能出现该问题.
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory 解决方法: # 找到hexo 命令的位置 which hexo 编辑hexo命令的bin文件的第一行为以下内容.
#!/usr/bin/env node --max_old_space_size=8192 便暂时解决内存溢出的问题.
hexo的性能 hexo的性能相对hugo确实差太多,同样1000+的页面,用hugo却只用了不到2s. 这让我开始开始犹豫是否要放弃使用hexo.</description>
</item>
<item>
<title>Code Review工具推荐以及使用报告</title>
<link>https://alili.tech/archive/cf2c83a/</link>
<pubDate>Mon, 12 Nov 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/cf2c83a/</guid>
<description>随之团队的扩大,统一编码规范,提高编码质量,变得尤为重要。代码审查作为可以有效提高代码质量的方式之一,有必要在公司推行代码审查制度. 让团队养成代码审查的习惯,提高代码质量,提前规避不必要的问题.
为了更加高效的代码审核,需要一款代码审查工具.所以才有了这份使用报告.
下面是我在使用中,尝试使用的一些工具.以及一些使用上的评价与总结.
1) CodeStriker CodeStriker免费和开源的web应用程序,可以帮助开发人员基于web的代码审查。开发者canensures问题,评论和决策是记录在一个数据库,并提供一个舒适的工作空间实际执行代码检查。
价格: 免费 UI交互: ★ 安装维护 :★★★ 易学程度: ★★★★★ 总结: CodeStriker 对于一个代码审查工具来说,功能上已经可以基本满足.但是因为开发时间太过久远,已经很长时间没有人在维护了,而且UI比较有历史的味道.
2) RhodeCode RhodeCode也是一个很好的工具,回顾你的代码并找出代码中的bug和问题并删除后检查代码。
价格: 社区版本免费,企业版本收费 UI交互: ★★★★ 安装维护 :★★★ 易学程度: ★★★★★ 总结: RhodeCode在使用使用过程中,还是比较优秀的.工具的安装部署使用docker也比较方便.使用上比较顺畅,可以作为使用的备选软件.
3) Code Brag Codebrag是一个简单的和轻量级的工具,代码审查,让这一过程为您的团队工作。它有助于解决一些问题像非阻塞的代码评审,智能电子邮件通知,内联注释,喜欢得多。
价格: 免费 UI交互: ★★★★ 安装维护 :★★★★ 易学程度: ★★★★★ 总结: Codebrag 是一款开源工具,安装起来不算难.也有一定程度上的社交属性.在使用期间官网在国内打不开,软件的安装资源不是很好获取.
4) Phabricator Phabricator是一个开源软件和web应用程序包括代码评审,主持GIT / Hg / SVN,发现错误时,浏览源代码和审计等</description>
</item>
<item>
<title>如何通过 Code Review 帮助团队提升代码质量</title>
<link>https://alili.tech/archive/bbaf6d07/</link>
<pubDate>Thu, 08 Nov 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/bbaf6d07/</guid>
<description>代码审查解决方案 最近在推进公司的代码审查. 经过几天的研究之后,整理出一些问题与解决方案.
当前面临的问题 没有一个好的工具方便代码审查 没有一个好的代码标准代码审查 没有一个流程强制执行代码审查 没有一个固定职责的人来代码审查 代码审查之后的修改跟踪问题 代码审查者与代码修复者鼓励机制 跨团队资源调配的时候,容易造成过多的代码 解决方案 加入Merge Request工作流 在Gitlab上做代码审查,我们需要在我们现有的git工作流上加入Merge Request.
工作方式 Merge Request可以和功能分支工作流、Gitflow工作流或Forking工作流一起使用。过程是这样的:
开发者在本地仓库中新建一个专门的分支开发功能。 开发者push分支修改到公开的Git仓库中。 开发者通过Git发起一个Merge Request。 团队的其它成员代码审查,讨论并修改。 项目维护者合并功能到官方仓库中并关闭Merge Request。 结合到我们现有工作流当中 我们现在代码管理的工作流叫: Gitflow工作流
Gitflow工作流和功能分支工作流类似,但围绕项目发布定义一个严格的分支模型。
在Gitflow工作流中使用Merge Request让开发者在发布分支或是维护分支上工作时,可以有个方便的地方对关于发布分支或是维护分支的问题进行交流。
Gitflow工作流中Merge Request的使用过程:当一个功能、发布或是热修复分支需要Review时,开发者简单发起一个Merge Request,团队的其它成员会通过Bitbucket收到通知。
新功能一般合并到develop分支,而发布和热修复则要同时合并到develop分支和master分支上。Merge Request可能用做所有合并的正式管理。
审查流程 开始=&gt;start: 代码作者通过git 克隆代码到本地 结束=&gt;end: 结束代码审查 修改代码=&gt;operation: 修改代码并且提交 pr=&gt;operation: 发起 Merge Request 通知=&gt;operation: gitlab 通知相关审核人员 审核=&gt;operation: 审核人员开始审核代码 关闭=&gt;operation: 关闭Merge Request 合并=&gt;operation: 合并代码 代码审核中=&gt;condition: 是否过审 开始-&gt;修改代码-&gt;pr-&gt;通知-&gt;审核-&gt;代码审核中 关闭-&gt;合并-&gt;结束 代码审核中(yes)-&gt;关闭 代码审核中(no)-&gt;修改代码 结合GitLab做代码审查 项目角色介绍 角色 描述 Owner Git 系统管理员 Master Git 项目开发人员 Reporter Git 项目测试人员 Guest 访客 角色权限 我们可以看到Master跟 Owner才有权利把代码合并到受保护的分支上,对于Master角色的分配需要谨慎.</description>
</item>
<item>
<title>升级Mac 10.14 mojave后辅助功能空白无法添加问题</title>
<link>https://alili.tech/archive/b8bdc73c/</link>
<pubDate>Sun, 04 Nov 2018 22:30:05 +0000</pubDate>
<guid>https://alili.tech/archive/b8bdc73c/</guid>
<description> 最近系统升级到Mac mojave 10.14后发现安全性与隐私中的辅助功能是空白的,而且App无论如何都添加不了。 我的macbook pro正常,但是我的mac mini 出现了该问题.让人很是头疼.
问题原因 应该是升级导致/Library/Application\ Support/com.apple.TCC损坏或权限异常,出现了问题.
解决方法 执行下面两行命令后重启系统,就可以恢复正常.
sudo chmod 777 /Library/Application\ Support/com.apple.TCC sudo rm -rf /Library/Application\ Support/com.apple.TCC/TCC.db # 重启系统 </description>
</item>
<item>
<title>2018年11月国内浏览器数据统计</title>
<link>https://alili.tech/archive/44b730cc/</link>
<pubDate>Thu, 01 Nov 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/44b730cc/</guid>
<description> var myChart = echarts.init(document.getElementById('echarts400')); var option = JSON.parse("\n {\"textStyle\":{\"color\":\"#fff\"},\"title\":{\"text\":\"2018年11月国内浏览器数据统计\",\"subtext\":\"浏览器数据分析\",\"x\":\"center\",\"textStyle\":{\"color\":\"#fff\"}},\"tooltip\":{\"trigger\":\"item\",\"formatter\":\"{a} \u003cbr/\u003e{b} : {c} ({d}%)\"},\"legend\":{\"type\":\"scroll\",\"orient\":\"vertical\",\"right\":10,\"top\":120,\"bottom\":20,\"data\":[\"Chrome\",\"IE 9.0\",\"IE 11.0\",\"QQ\",\"IE 8.0\",\"2345\",\"搜狗高速\",\"Firefox\",\"Safari\",\"其他\"],\"textStyle\":{\"color\":\"#fff\"}},\"series\":[{\"name\":\"浏览器用户比例\",\"type\":\"pie\",\"radius\":\"55%\",\"center\":[\"50%\",\"60%\"],\"data\":[{\"name\":\"Chrome\",\"value\":46.88},{\"name\":\"IE 9.0\",\"value\":7.4},{\"name\":\"IE 11.0\",\"value\":6.21},{\"name\":\"QQ\",\"value\":5.75},{\"name\":\"IE 8.0\",\"value\":5.74},{\"name\":\"2345\",\"value\":5.68},{\"name\":\"搜狗高速\",\"value\":4.74},{\"name\":\"Firefox\",\"value\":2.54},{\"name\":\"Safari\",\"value\":2.48},{\"name\":\"其他\",\"value\":12.59}],\"itemStyle\":{\"emphasis\":{\"shadowBlur\":10,\"shadowOffsetX\":0,\"shadowColor\":\"rgba(0, 0, 0, 0.5)\"}}}]}\n") myChart.setOption(option); </description>
</item>
<item>
<title>在Webpack与Systemjs中构建你的Single-SPA微前端应用</title>
<link>https://alili.tech/archive/1a4f2dcf/</link>
<pubDate>Wed, 31 Oct 2018 01:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/1a4f2dcf/</guid>
<description>这里给大家介绍一下基于Single-SPA编写的微前端应用在各种当下流行的构建工具中的使用方法.
Webpack 2+ 在Webpack 2+版本中,支持import()做代码分片. 在其他项目中 webpack2+的使用已经相当的广泛,这里就不做过多赘述.
import {registerApplication} from 'single-spa'; registerApplication('app-name', () =&gt; import('./my-app.js'), activeWhen); function activeWhen() { return window.location.pathname.indexOf('/my-app') === 0; } SystemJS 在之前我们的项目中使用的就是SystemJS,方便部署应用后的二次构建.用起来页非常的方便.
import {registerApplication} from 'single-spa'; // Import the registered application with a SystemJS.import call registerApplication('app-name-1', () =&gt; SystemJS.import('./my-app.js'), activeWhen); // Alternatively, use the more out-of-date System.import (instead of SystemJS.import) registerApplication('app-name-2', () =&gt; System.import('./my-other-app.js'), activeWhen); function activeWhen() { return window.location.pathname.indexOf('/my-app') === 0; } Webpack 1 Webpack 1 不支持基于Promise的代码拆分.</description>
</item>
<item>
<title>Single-SPA微前端框架的使用Demo汇总</title>
<link>https://alili.tech/archive/22975f44/</link>
<pubDate>Wed, 31 Oct 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/22975f44/</guid>
<description>这些是在github能找到的single-spa微前端的Demo:
single-spa-examples 这是一个single-spa做的官方例子,这是在线demo.
simple-single-spa-webpack-example 这是基于webpack构建的使用例子,webpakc版本可能有点低,但是思想是一样的.
single-spa-angular-cli-examples 基于angular-cli做的angular例子,适用于angular 2.0+ 的版本.
single-spa-es5-angularjs angularjs的例子,也就是angularjs1.0的版本.
single-spa-portal-example 这已经是一个非常完整的多技术栈用例了,里面集成了多技术栈与模块之间通讯的思路,非常值得研究.
microfrontend-base-demo 这是在我们项目中萃取的base模块demo
microfrontend-submodule-demo 这是在我们项目中萃取的子模块demo</description>
</item>
<item>
<title>Git删除所有提交记录解决方案</title>
<link>https://alili.tech/archive/ed854758/</link>
<pubDate>Tue, 30 Oct 2018 19:33:33 +0000</pubDate>
<guid>https://alili.tech/archive/ed854758/</guid>
<description>如果你之前的项目提交了一些敏感数据,或者要清除以前提交的记录,给出下面解决方案.
# 1. 检出一个新的分支 git checkout --orphan latest_branch # 2. 暂存所有文件 git add -A # 3. 提交刚刚暂存的文件 git commit -am &quot;commit message&quot; # 4. 删除最原始的分支 git branch -D master # 5. 重命名当的第分支 git branch -m master # 6. 提交你的记录到远程仓库 git push -f origin master </description>
</item>
<item>
<title>让你的Hexo博客支持熊掌号URL自动推送,百度24小时收录</title>
<link>https://alili.tech/archive/9d64fe09/</link>
<pubDate>Wed, 24 Oct 2018 21:32:05 +0000</pubDate>
<guid>https://alili.tech/archive/9d64fe09/</guid>
<description> 百度推出熊掌号,为了让hexo支持熊掌号推送,我在 hexo-baidu-url-submit 这个插件的基础上加上了熊掌号推送功能. 当天推送的24小时内会直接收录. 用这个,百度的收录速度是非常快的.
以后再也不用等百度收录等到死也不会理你了.
熊掌号支持 package.json 里面的内容改为
&quot;hexo-baidu-url-submit&quot;: &quot;https://github.com/Fantasy9527/hexo-baidu-url-submit&quot;, baidu_url_submit 配置 baidu_url_submit: count: 1000 ## 提交最新的一个链接 host: alili.tech ## 在百度站长平台中注册的域名 token: xxxxx ## 请注意这是您的秘钥, 所以请不要把博客源代码发布在公众仓库里! path: baidu_urls.txt ## 文本文档的地址, 新链接会保存在此文本文档里 xz_appid: 'xxxxxx' ## 你的熊掌号 appid xz_token: 'xxxxxx' ## 你的熊掌号 token xz_count: 10 ## 从所有的提交的数据当中选取最新的10条,该数量跟你的熊掌号而定 deploy 配置 deploy: - type: baidu_url_submitter # 百度 - type: baidu_xz_url_submitter # 百度熊掌号 </description>
</item>
<item>
<title>Nodejs爬虫技巧-使用Puppeteer下载图片或文件</title>
<link>https://alili.tech/archive/84622ce5/</link>
<pubDate>Tue, 23 Oct 2018 20:32:05 +0000</pubDate>
<guid>https://alili.tech/archive/84622ce5/</guid>
<description> 一些网站的图片不允许外链,我们想要下载这些网站的图片通过Puppeteer是比较好解决的. 今天就给大家介绍一个爬虫技巧,通过Puppeteer下载你想要的图片或者文件.
怎么通过Puppeteer下载? 我们需要额外依赖的库 fs-extra
代码很简单,主要代码可以简化到两三行
const fse = require('fs-extra'); // 需要依赖的库,你想用原生fs也是没有问题的 // 主要代码 var viewSource = await page.goto(url); await fse.outputFile(`path`, await viewSource.buffer()) //下载到你想要的路径 </description>
</item>
<item>
<title>任天堂Switch 6.0+ 系统菜单汉化</title>
<link>https://alili.tech/archive/b3ccb586/</link>
<pubDate>Mon, 15 Oct 2018 19:02:36 +0000</pubDate>
<guid>https://alili.tech/archive/b3ccb586/</guid>
<description>任天堂Switch汉化补丁 仅支持6.0 和6.0.1系统 简体中文/繁体中文 支持大气层、ReiNX、RajNX、SXOS(TXOS) 下载地址 汉化安装器 汉化安装器:https://share.weiyun.com/5HNlw1J (强烈推荐)
覆盖版:(当安装器闪退时使用,覆盖前要把原来的文件删干净。) 简体中文:https://share.weiyun.com/59MqPxr 繁体中文:https://share.weiyun.com/52w0vp8 ReiNX汉化专用版本: 完整支持汉化,已经修复DOOM和2K19的问题 https://share.weiyun.com/58azYtc
源码来自https://github.com/Reisyukaku/ReiNX
地址覆盖 大气层覆盖到atmosphere/titles ReiNX覆盖到ReiNX/titles SXOS覆盖到sxos/titles 汉化安装器教程: 首先,用读卡器把SD卡插入电脑。 打开SD卡的盘。 把Nintendo Switch系统汉化补丁.exe 放入卡内。 运行Nintendo Switch系统汉化补丁.exe 看提示选择。 FAQ 汉化影响游戏吗? 一般汉化导致游戏崩溃是文本出错的原因,新的汉化已经修复大部分的问题。当然实际效果仍需测试。
5.1系统能用吗? 虽然5.1系统安装6.0的汉化可以开机。但不保证稳定性。也不保证能用。
安装程序打不开怎么办? 安装 Visual C++ Redistributable for Visual Studio 2015 安装程序不支持32位系统,所以用覆盖版就行。
安装汉化后无法开机怎么办? 别急,卸载汉化即可,不会影响原系统。
部分游戏崩溃的问题 如果你的游戏本身打了汉化补丁,是有可能崩溃的(目前已知龙珠超宇宙2)。
部分游戏崩溃是破解工具本身的问题。比如SXOS2.0极不稳定。大气层某些游戏无法运行与存档。如果你用的是SXOS 2.xx ,运行XCI游戏有很大几率崩溃,应该与汉化无关。
SXOS (2.0, 2.0.1, 2.1) XCI游戏待机死机的问题如果你的游戏本身使用了汉化,待机很大几率死机。与系统汉化无关。
关于6.0.1系统 根据测试,6.0.1系统没有对文本做改动,所以6.0的汉化是完全可以兼容的。
注意事项 文件拷贝不建议使用mac系统!!! 文件拷贝不建议使用mac系统!</description>
</item>
<item>
<title>Switch的NSP和XCI什么区别?</title>
<link>https://alili.tech/archive/150b3ba6/</link>
<pubDate>Sun, 14 Oct 2018 19:02:36 +0000</pubDate>
<guid>https://alili.tech/archive/150b3ba6/</guid>
<description>最近在折腾Switch, 在游戏安装中出现了两种游戏格式,分别是
xci nsp 他们之间到底有什么区别? 在实际使用中: xci,扔到内存卡里就可以使用, nsp,需要安装之后才能使用 简单理解就是,xci是绿色版软件(正确说应该是ISO),nsp是安装版软件。
因为xci相当于卡带,不需要安装,需要切换. nsp相当于数字版,需要安装,安装完直接能玩
所有的DLC或者更新包之类的都是nsp格式.
当我们使用xci格式的软件的时候,想要安装更新升级包的时候,其实都是nsp格式的,直接安装nsp效果都是一样的.
平常使用中,我喜欢nsp,安装过后就可以直接打开软件了,不需要再切换一次.个人觉得使用nsp是一劳永逸的.
关于汉化 其实都是可以汉化的.两种格式只有使用上的差别,其他的并没有差别.</description>
</item>
<item>
<title>Nintendo Switch破解原理</title>
<link>https://alili.tech/archive/33fa548c/</link>
<pubDate>Thu, 11 Oct 2018 19:02:36 +0000</pubDate>
<guid>https://alili.tech/archive/33fa548c/</guid>
<description>Nintendo Switch Nintendo Switch ,是任天堂出品的电子游戏机 ,于2017年3月3日在日本、北美、欧洲和香港发售,同年12月1日在韩国与台湾发售。 拥有可拆卸控制器和可分离式主机,游戏载体使用了专用卡匣 。 主机处理器使用了NVIDIA定制的Tegra X1系统芯片 ,这是任天堂首次采用NVIDIA的系统芯片。 任天堂Switch主机的内置存储空间为32GB,可使用microSD进行扩充,最高支持microSDXC标准,最大支持2TB容量; 主机在初始系统1.0.0时只能支持到microSD标准,发售同日提供的系统2.0 .0更新使其可支持microSDXC标准。
破解原理 Nintendo Switch(任天堂switch) 的CPU使用的是Nvidia X1 T210的处理器,存在一个可进入的工程模式(Recovery Mode),简称RCM, Nintendo Switch的右joycon连接口中隐藏着一个特殊金属引脚(pin10)。如果在开机时,按住音量键+,并且将这个引脚接地(pin1,7,9),Nintendo Switch就能进入工程模式(RCM),从而设法运行自制代码。
你可以在淘宝上轻易买到这个短接器。也可以通过锡纸,别针或者3D打印等很方便的制作。短接器的作用就是将这个特殊引脚接地。 由上可知, Nintendo Switch破解依赖的是基于Nvidia X1 T210的处理器的工程模式。注入(发射)特殊代码引导自制系统或程序。达成破解。
这个方法不会被封堵,普通的系统更新补并不会影响破解。无法通过软件层面封堵。因为工程模式启动的优先级高于系统。不论以后更新什么系统,进入RCM(工程模式是没有问题的),在即将到来的6.0版本,也只是更改了游戏文件的存储方式,变相的防范破解,目前TX1.9版本已经加入了破解。
正因为破解是基于开机短接进入工程模式的原理,在任意一次关机后,破解就会失效,需要重新进行破解。
破解后可做什么,有没有什么问题 Nintendo Switch 的系统本质上可以看作是一个改版的LINUX的操作系统,.通过破解后,编译新的程序,可以Dump你手中的实体卡带游戏,导出存档,甚至可以看小说,听音乐,作为其他游戏主机的模拟器。玩破解游戏只是其中的一个功能。 所以,在放入存储卡时候,因为系统格式化的不同,也会存在一次升级的情况,这是由于不同系统对于文件存储分区的逻辑不同导致的。
扩展阅读:破解后您可以安装一个真正的发行版的Linux系统Lakka,
着力推荐国内开发者的Lakka系统,这是独立于国外的一个项目,让我们感谢他。 最强模拟器系统 lakka修改模拟游戏分辨率和纹理和安装教程 https://www.91wii.com/thread-96053-1-1.html
关于BAN机 由于任天堂在联网时会验证游戏文件头(每个游戏的文件头都是唯一的),所以玩破解游戏,修改存档等,都会导致被Ban,目前主要体现为两种, 普通BAN:具体的表现为无法联机游戏,无法进Eshop(商店),同时会由错误代码出现,但是目前游戏正常更新(例如更新中文语言)并不受影响。您可以理解为Ban机是限制了网络功能。 更为严厉的ban机措施,大家称之为Super Ban,具体的表现为联网后出现错误代码2137-7403,同时主机无法更新,游戏和dlc也无法更新,也就说,任天堂将你的主机序列号加入黑名单,直接断开所有同任天堂的联系。
您可以破解之后,进行系统备份。但目前已经出现有朋友因为不熟悉备份恢复流程变砖,所以这里不放链接,如果您要做这个事情, 记得“一机一码”,自己的备份文件只能自己用,不能用别人的。同时恢复分区的时候,要留意不要恢复错的文件,一旦误操作,是不可恢复的变砖。
我更建议,破解后断开网络,等要联网之前,重置主机再联网,可以大概率从正。这个风险较小。
破解方式 目前,Nintendo Switch的破解存在两个大的分支。 一类是免费的大气层/REI/破解TX安装器等。此类只能支持NSP格式游戏安装。略微复杂 一类是收费的TX OS。此类支持卡带DUPM出来的XCI格式,同时支持NSP安装。
因为代码公开,所以破解方式也变得逐渐多样化,希望您了解具体原理,而不是纠结于具体哪种破解方式,大致来说,论坛中简单热门的就是最好的破解方式。论坛中有不少不错的整合包,您可以任选其一进行安装。
参考资料: https://www.91wii.com/thread-93105-1-1.html</description>
</item>
<item>
<title>使用Eggjs(koa) & web3.js开发你的以太坊Dapp</title>
<link>https://alili.tech/archive/69a6fd18/</link>
<pubDate>Wed, 10 Oct 2018 19:33:33 +0000</pubDate>
<guid>https://alili.tech/archive/69a6fd18/</guid>
<description>Eggjs Eggjs 是阿里开源的企业级基于Koa2的Node.js框架. eggjs基本上是开箱即用,奉行『约定优于配置』.在日常开发中,用起来非常顺畅. 而且生态也比较完善,koa2的插件都可以对接到框架中来.
Egg.js 目录结构 egg-project ├── package.json ├── app.js (可选) ├── agent.js (可选) ├── app | ├── router.js │ ├── controller │ | └── home.js │ ├── service (可选) │ | └── user.js │ ├── middleware (可选) │ | └── response_time.js │ ├── schedule (可选) │ | └── my_task.js │ ├── public (可选) │ | └── reset.css │ ├── view (可选) │ | └── home.tpl │ └── extend (可选) │ ├── helper.</description>
</item>
<item>
<title>2018年10月国内浏览器数据统计</title>
<link>https://alili.tech/archive/4a50d81d/</link>
<pubDate>Mon, 01 Oct 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/4a50d81d/</guid>
<description> var myChart = echarts.init(document.getElementById('echarts400')); var option = JSON.parse("\n {\"textStyle\":{\"color\":\"#fff\"},\"title\":{\"text\":\"2018年10月国内浏览器数据统计\",\"subtext\":\"浏览器数据分析\",\"x\":\"center\",\"textStyle\":{\"color\":\"#fff\"}},\"tooltip\":{\"trigger\":\"item\",\"formatter\":\"{a} \u003cbr/\u003e{b} : {c} ({d}%)\"},\"legend\":{\"type\":\"scroll\",\"orient\":\"vertical\",\"right\":10,\"top\":120,\"bottom\":20,\"data\":[\"Chrome\",\"IE 9.0\",\"IE 11.0\",\"2345\",\"QQ\",\"IE 8.0\",\"搜狗高速\",\"Safari\",\"Firefox\",\"其他\"],\"textStyle\":{\"color\":\"#fff\"}},\"series\":[{\"name\":\"浏览器用户比例\",\"type\":\"pie\",\"radius\":\"55%\",\"center\":[\"50%\",\"60%\"],\"data\":[{\"name\":\"Chrome\",\"value\":47.08},{\"name\":\"IE 9.0\",\"value\":7.89},{\"name\":\"IE 11.0\",\"value\":5.97},{\"name\":\"2345\",\"value\":5.9},{\"name\":\"QQ\",\"value\":5.88},{\"name\":\"IE 8.0\",\"value\":5.59},{\"name\":\"搜狗高速\",\"value\":4.68},{\"name\":\"Safari\",\"value\":2.43},{\"name\":\"Firefox\",\"value\":2.42},{\"name\":\"其他\",\"value\":12.16}],\"itemStyle\":{\"emphasis\":{\"shadowBlur\":10,\"shadowOffsetX\":0,\"shadowColor\":\"rgba(0, 0, 0, 0.5)\"}}}]}\n") myChart.setOption(option); </description>
</item>
<item>
<title>Centos7环境下启动Upsource失败解决办法</title>
<link>https://alili.tech/archive/66c1c154/</link>
<pubDate>Sat, 29 Sep 2018 19:33:33 +0000</pubDate>
<guid>https://alili.tech/archive/66c1c154/</guid>
<description>报错 Centos7环境下启动Upsource的时候出现以下报错,我在Mac上启动upsource的时候一切正常.
[Upsource Error] Failed to start JetBrains Upsource 2018.2 due to unexpected exception: Native random generator does not seem to have enough entropy for JetBrains Upsource 2018.2 to start. [Upsource Error] You can fix it by switching to PRNG (with -Djava.security.egd=/dev/zrandom) or by reconfiguring your operation system to provide more random bits.12 解决办法 复制 upsource.jvmoptions.dist ==&gt; upsource.jvmoptions cp $upsource_path/conf/upsource.jvmoptions.dist $upsource_path/conf/upsource.jvmoptions 编辑 $upsource_path/conf/upsource.jvmoptions文件,最后一行加上: -Djava.</description>
</item>
<item>
<title>利用ngrok给你的机器打个洞 - 内网穿透</title>
<link>https://alili.tech/archive/df8d5e8d/</link>
<pubDate>Wed, 12 Sep 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/df8d5e8d/</guid>
<description>我有很多自己的个人代码是跑在家里的服务器中的.一般来说都是自动化的处理我的一些生活问题,与数据收集等相关活动. 所以一般没有客户端访问家里服务器的需求. 但是很多时候脑子突发奇想.有一些小点子,一些小的bug或者小的优化,代码修改完成之后,有一个部署到需求. 因为家里服务器没有一个稳定的外网IP的,外网不能直接连接服务器. 所以我们需要 内网穿透.
内网穿透 家里用的是小米路由器,小米路由器里面集成了花生壳,理论上是可以做到内网穿透的.无奈的是,一直都没有配置成功过.
网上找过很多内网穿透的工具: * 花生壳 * NAT * frp * ngrok * localtunnel
ngrok 选择ngrok的原因很简单,配置方便,并且支持tcp协议. 支持tcp协议代表,我可以直接在外面用SSH来访问家里的机器.
用法 首先你需要去官网注册一个账号 下载ngrok,并且解压到一个你喜欢的目录下面 去官网复制你的授权码 授权ngrok ngrok authtoken 授权码 http ngrok http 8080 tcp ngrok tcp 22 最终你会得到,一个外网可以访问的地址. 用这个地址就可以直接访问到你本机的端口了.
当我们拥有这样一个公网地址之后,我们就可以ssh来控制家里的机器 或者使用github的webhook来做一切你想要做的事情.</description>
</item>
<item>
<title>前端微服务化解决方案8 - 二次构建</title>
<link>https://alili.tech/archive/ce685b9f/</link>
<pubDate>Fri, 07 Sep 2018 01:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/ce685b9f/</guid>
<description>二次构建 进一步优化我们的微前端性能
在微前端这种形势的架构,每个模块都会输出固定的文件,比如之前说的:
项目配置文件 Store.js 文件 main.js 渲染入口文件 这三个,是微前端架构中每个模块必要的三个文件.
在模块加载器启动整个项目的时候,都必须要加载所有模块的配置文件与Store.js文件. 在前面的文章中有说 配置自动化的问题,这其实就是一种简单的二次构建. 虽然每一个模块的配置文件体积不是很大,但是每一个文件都会加载,是项目启动的必要文件. 每一个文件都会占一个http请求,每一个文件的阻塞都会影响项目的启动时间.
所以,我们的Store.js也必须是要优化的. 当然如果我们的模块数量不是很多的话,我们没有优化的必要.但是一旦项目变得更加庞大,有好几十个模块. 我们不可能一次加载几十个文件,我们必须要在项目部署之后,还要对整个项目重新再次构建来优化与整合我们的项目.
我们的Store.js 是一个amd模块,所以我们需要一个合并amd模块的工具.
Grunt or Gulp 像这样的场景,用grunt,gulp这样的任务管理工具再合适不过了. 不管这两个工具好像已经是上个世纪的东西了,但是他的生态还是非常完善的.用在微前端的二次构建中非常合适.
例如Gulp:
const gulp = require('gulp'); const concat = require('gulp-concat'); gulp.task('storeConcat', function () { gulp.src('project/**/Store.js') .pipe(concat('Store.js')) //合并后的文件名 .pipe(gulp.dest('project/')); }); 像这样的优化点还有非常多,在项目发布之后,在二次构建与优化代码. 在后期庞大的项目中,是有很多空间来提升我们项目的性能的.
未完待续 &hellip;
相关文章 前端微服务化解决方案1 - 思考
前端微服务化解决方案2 - Single-SPA
前端微服务化解决方案3 - 模块加载器
前端微服务化解决方案4 - 消息总线
前端微服务化解决方案5 - 路由分发</description>
</item>
<item>
<title>前端微服务化解决方案7 - 静态数据共享</title>
<link>https://alili.tech/archive/5e00e43d/</link>
<pubDate>Thu, 06 Sep 2018 01:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/5e00e43d/</guid>
<description>在前面的一些介绍,相信你对微前端已经有了一个相对完整的认知. 下面介绍一下,再开发过程中我的一些小技巧与处理方法.
动态入口 当有新的子模块会挂载到项目中的时候,在UI中肯定需要一个新的入口进入子模块的UI. 而这样一个入口,是需要动态生成的.
例如:图中左边的菜单,不应该是代码写死的.而是根据每个模块提供的数据自动生成的.
不然每次发布新的模块,我们都需要在最外面的这个框架修改代码.这样就谈不上什么独立部署了.
静态数据共享 想要达到上面所的效果,我们可以这样做.
// ~/common/menu.js import { isUrl } from '../utils/utils' let menuData = [ { name: '模块1', icon: 'table', path: 'module1', rank: 1, children: [ { name: 'Page1', path: 'page1', }, { name: 'Page2', path: 'page2', }, { name: 'Page3', path: 'page3', }, ], } ] let originParentPath = '/' function formatter(data, parentPath = originParentPath, parentAuthority) { ... } // 在这里,我们对外导出 这个模块的菜单数据 export default menuData // Store.</description>
</item>
<item>
<title>前端微服务化解决方案6 - 构建与部署</title>
<link>https://alili.tech/archive/ffb0c5ab/</link>
<pubDate>Wed, 05 Sep 2018 01:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/ffb0c5ab/</guid>
<description>微前端打包构建 微前端项目的打包,是有一些需要注意的点 以webpack为例:
amd模块 在之前的文章,我们有提到我们的加载器,是基于System.js来做的. 所以我们微前端的模块最终打包,是要符合模块规范的. 我们使用的是amd模块规范来构建我们的模块.
指定基础路径 因为模块打包后,调用模块出口文件的,是模块加载器. 为了清晰的管理每个模块,并且正确的加载到我们每一个模块的资源, 我们给模块的资源都指定一个publicPath.
下面给出一个简单的 webpack 配置,这些配置我只是列出一些必要选项. 并不是一个完整的webpack配置,后续我会提供完整的微前端的Demo,提供大家参考 这些配置都是基于 create-react-app 的配置做的修改. 只要明白了配置的意图,明白我们打包出来的最终是一个什么样的包, 不管打包工具以后怎么变,技术栈怎么变,最后都是可以对接到微前端中来.
这里给出 project.json 的内容,便于后面的配置文件的阅读
// project.json { &quot;name&quot;: &quot;name&quot;, //模块名称 &quot;path&quot;: &quot;/project&quot;, //模块url前缀 &quot;prefix&quot;: &quot;/module-prefix/&quot;, //模块文件路径前缀 &quot;main&quot;: &quot;/module-prefix/main.js&quot;, //模块渲染出口文件 &quot;store&quot;: &quot;/module-prefix/store.js&quot;,//模块对外接口 &quot;base&quot;: true // 是否为baseapp } // 引入项目配置文件,也是前面说的 模块加载器必要文件之一 const projectConfig = require('./project.json') let config = { entry: { main: paths.appIndexJs, //出口文件,模块加载器必要文件之一 store: paths.store // 对外api的reducer文件,模块加载器必要文件之一 }, output: { path: paths.</description>
</item>
<item>
<title>前端微服务化解决方案5 - 路由分发</title>
<link>https://alili.tech/archive/5ff0b366/</link>
<pubDate>Tue, 04 Sep 2018 01:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/5ff0b366/</guid>
<description>路由分发式微前端 从应用分发路由到路由分发应用 用这句话来解释,微前端的路由,再合适不过来.
路由分发式微前端,即通过路由将不同的业务分发到不同的、独立前端应用上。其通常可以通过 HTTP 服务器的反向代理来实现,又或者是应用框架自带的路由来解决。 就当前而言,通过路由分发式的微前端架构应该是采用最多、最易采用的 “微前端” 方案。但是这种方式看上去更像是多个前端应用的聚合,即我们只是将这些不同的前端应用拼凑到一起,使他们看起来像是一个完整的整体。但是它们并不是,每次用户从 A 应用到 B 应用的时候,往往需要刷新一下页面。 &ndash; 引用自phodal 微前端的那些事儿
在模块加载器那一章的示例代码,已经非常充分了展示了路由分发应用的步骤.
在单页面前端的路由,目前有两种形式, 一种是所有主流浏览器都兼容多hash路由, 基本原理为url的hash值的改变,触发了浏览器onhashchange事件,来触发组件的更新
还有一种是高级浏览器才支持的 History API, 在 window.history.pushState(null, null, &quot;/profile/&quot;);的时候触发组件的更新
// hash 模式,项目路由用的是hash模式会用到该函数 export function hashPrefix(app) { return function (location) { let isShow = false //如果该应用 有多个需要匹配的路劲 if(isArray(app.path)){ app.path.forEach(path =&gt; { if(location.hash.startsWith(`#${path}`)){ isShow = true } }); } // 普通情况 else if(location.hash.startsWith(`#${app.path || app.url}`)){ isShow = true } return isShow; } } // pushState 模式 export function pathPrefix(app) { return function (location) { let isShow = false //如果该模块 有多个需要匹配的路径 if(isArray(app.</description>
</item>
<item>
<title>前端微服务化解决方案4 - 消息总线</title>
<link>https://alili.tech/archive/a9a1f81b/</link>
<pubDate>Mon, 03 Sep 2018 01:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/a9a1f81b/</guid>
<description>微前端的消息总线,主要的功能是搭建模块与模块之间通讯的桥梁.
黑盒子 问题1: 应用微服务化之后,每一个单独的模块都是一个黑盒子, 里面发生了什么,状态改变了什么,外面的模块是无从得知的. 比如模块A想要根据模块B的某一个内部状态进行下一步行为的时候,黑盒子之间没有办法通信.这是一个大麻烦.
问题2 每一个模块之间都是有生命周期的.当模块被卸载的时候,如何才能保持后续的正常的通信?
ps. 我们必须要解决这些问题,模块与模块之间的通讯太有必要了.
打破壁垒 在github上single-spa-portal-example,给出来一解决方案.
基于Redux实现前端微服务的消息总线(不会影响在编写代码的时候使用其他的状态管理工具).
大概思路是这样的: 每一个模块,会对外提供一个 Store.js.
这个文件里面的内容,大致是这样的.
import { createStore, combineReducers } from 'redux' const initialState = { refresh: 0 } function render(state = initialState, action) { switch (action.type) { case 'REFRESH': return { ...state, refresh: state.refresh + 1 } default: return state } } // 向外输出 Store export const storeInstance = createStore(combineReducers({ namespace: () =&gt; 'base', render })) 对于这样的代码,有没有很熟悉?</description>
</item>
<item>
<title>前端微服务化解决方案3 - 模块加载器</title>
<link>https://alili.tech/archive/1a60cede/</link>
<pubDate>Mon, 03 Sep 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/1a60cede/</guid>
<description>微前端的模块加载器,主要功能为: * 项目配置文件的加载 * 项目对外接口文件的加载(消息总线会用到,后续会提) * 项目入口文件的加载
以上也是每一个单模块,不可缺少的三部分
配置文件 我们实践微前端的过程中,我们对每个模块项目,都有一个对外的配置文件. 是模块在注册到singe-spa时候所用到的信息.
{ &quot;name&quot;: &quot;name&quot;, //模块名称 &quot;path&quot;: &quot;/project&quot;, //模块url前缀 &quot;prefix&quot;: &quot;/module-prefix/&quot;, //模块文件路径前缀 &quot;main&quot;: &quot;/module-prefix/main.js&quot;, //模块渲染出口文件 &quot;store&quot;: &quot;/module-prefix/store.js&quot;,//模块对外接口 &quot;base&quot;: true // 当模块被定性为baseApp的时候, // 不管url怎么变化,项目也是会被渲染的, // 使用场景为,模块职责主要为整个框架的布局或者一直被渲染,不会改变的部分 } 当我们的模块,有多种url前缀的时候,path也可以为数组形式
{ &quot;path&quot;: [&quot;/project-url-path1/&quot;,&quot;/project-url-path2/&quot;], //项目url前缀 } 配置自动化 我们每个模块都有上面所描述的配置文件,当我们的项目多个模块的时候,我们需要把所有模块的配置文件聚合起来. 我这里也有写一个脚本.
micro-auto-config
使用方法:
npm install micro-auto-config -g # 在项目根目录,用pm2启动该脚本,便可启动这个项目的配置自动化 pm2 start micro-auto-config 大概思路是:当模块部署,服务器检测到项目文件发生改变,便开始找出所有模块的配置文件,把他们合并到一起. 以数组包对象的形式输出一个总体的新配置文件 project.config.js. 当我们一个模块配置有更新,部署到线上的时候,项目配置文件会自动更新.
模块加载器 这个文件直接引入到html中,也就是上一篇文章中的single-spa-config.js 升级版. 在加载模块的时候,我们使用SystemJS作为我们的模块加载工具.</description>
</item>
<item>
<title>前端微服务化解决方案2 - Single-SPA</title>
<link>https://alili.tech/archive/11052bf4/</link>
<pubDate>Sun, 02 Sep 2018 22:17:36 +0000</pubDate>
<guid>https://alili.tech/archive/11052bf4/</guid>
<description>技术选型 经过各种技术调研我们最终选择的方案是基于 Single-SPA 来实现我们的前端微服务化.
你的浏览器不支持视频 Single-SPA 一个用于前端微服务化的JavaScript前端解决方案
使用Single-SPA之后,你可以这样做:
(兼容各种技术栈)在同一个页面中使用多种技术框架(React, Vue, AngularJS, Angular, Ember等任意技术框架),并且不需要刷新页面. (无需重构现有代码)使用新的技术框架编写代码,现有项目中的代码无需重构. (更优的性能)每个独立模块的代码可做到按需加载,不浪费额外资源. 每个独立模块可独立运行. 下面是一个微前端的演示页面 (你可能需要科学的上网) https://single-spa.surge.sh/ &gt; 以上是官方例子,但是官方例子中并没有解决一个问题.就是各种技术栈的路由实现方式大相径庭,如何做到路由之间的协同? 后续文章会讲解,如何解决这样的问题.
单体应用对比前端微服务化 普通的前端单体应用 微前端架构 Single-SPA的简单用法 1.创建一个HTML文件 &lt;html&gt; &lt;body&gt; &lt;div id=&quot;root&quot;&gt;&lt;/div&gt; &lt;script src=&quot;single-spa-config.js&quot;&gt;&lt;/script&gt; &lt;/body&gt; &lt;/html&gt; 2.创建single-spa-config.js 文件 // single-spa-config.js import * as singleSpa from 'single-spa'; // 加载react 项目的入口js文件 (模块加载) const loadingFunction = () =&gt; import('./react/app.js'); // 当url前缀为 /react的时候.返回 true (底层路由) const activityFunction = location =&gt; location.</description>
</item>
<item>
<title>前端微服务化解决方案1 - 思考</title>
<link>https://alili.tech/archive/ea599f7c/</link>
<pubDate>Sat, 01 Sep 2018 22:17:36 +0000</pubDate>
<guid>https://alili.tech/archive/ea599f7c/</guid>
<description>近几年,微服务架构在后端技术社区大红大紫,它被认为是IT软件架构的未来技术方向.我们如何借鉴后端微服务的思想来构建一个现代化前端应用? 在这里我提供一个可以在产品中真正可以落地的前端微服务解决方案.
微服务化后端前后端对比 后端微服务化的优势: 复杂度可控: 体积小、复杂度低,每个微服务可由一个小规模开发团队完全掌控,易于保持高可维护性和开发效率。 独立部署: 由于微服务具备独立的运行进程,所以每个微服务也可以独立部署。 技术选型灵活: 微服务架构下,技术选型是去中心化的。每个团队可以根据自身服务的需求和行业发展的现状,自由选择最适合的技术栈。 容错: 当某一组建发生故障时,在单一进程的传统架构下,故障很有可能在进程内扩散,形成应用全局性的不可用。 扩展: 单块架构应用也可以实现横向扩展,就是将整个应用完整的复制到不同的节点。 前端微服务化后的优势: 复杂度可控: 每一个UI业务模块由独立的前端团队开发,避免代码巨无霸,保持开发时的高速编译,保持较低的复杂度,便于维护与开发效率。 独立部署: 每一个模块可单独部署,颗粒度可小到单个组件的UI独立部署,不对其他模块有任何影响。 技术选型灵活: 也是最具吸引力的,在同一项目下可以使用如今市面上所有前端技术栈,也包括未来的前端技术栈。 容错: 单个模块发生错误,不影响全局。 扩展: 每一个服务可以独立横向扩展以满足业务伸缩性,与资源的不必要消耗; 我们何时需要前端微服务化? 项目技术栈过于老旧,相关技能的开发人员少,功能扩展吃力,重构成本高,维护成本高. 项目过于庞大,代码编译慢,开发体差,需要一种更高维度的解耦方案. 单一技术栈无法满足你的业务需求 其中面临的问题与挑战 我们即将面临以下问题:
我们如何实现在一个页面里渲染多种技术栈? 不同技术栈的独立模块之间如何通讯? 如何通过路由渲染到正确的模块? 在不同技术栈之间的路由该如何正确触发? 项目代码别切割之后,通过何种方式合并到一起? 我们的每一个模块项目如何打包? 前端微服务化后我们该如何编写我们的代码? 独立团队之间该如何协作? 后续的文章我会一一解答以上问题,一起挖掘前端微服务的潜力. 跳出概念,实实在在的落地到你的项目中. 未完待续 &hellip;
相关文章 前端微服务化解决方案1 - 思考
前端微服务化解决方案2 - Single-SPA
前端微服务化解决方案3 - 模块加载器
前端微服务化解决方案4 - 消息总线
前端微服务化解决方案5 - 路由分发</description>
</item>
<item>
<title>2018年09月国内浏览器数据统计</title>
<link>https://alili.tech/archive/c25273ee/</link>
<pubDate>Sat, 01 Sep 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/c25273ee/</guid>
<description> var myChart = echarts.init(document.getElementById('echarts400')); var option = JSON.parse("\n{\"textStyle\":{\"color\":\"#fff\"},\"title\":{\"text\":\"2018年11月国内浏览器数据统计\",\"subtext\":\"浏览器数据分析\",\"x\":\"center\",\"textStyle\":{\"color\":\"#fff\"}},\"tooltip\":{\"trigger\":\"item\",\"formatter\":\"{a} \u003cbr/\u003e{b} : {c} ({d}%)\"},\"legend\":{\"type\":\"scroll\",\"orient\":\"vertical\",\"right\":10,\"top\":120,\"bottom\":20,\"data\":[\"Chrome\",\"IE 9.0\",\"IE 11.0\",\"QQ\",\"IE 8.0\",\"2345\",\"搜狗高速\",\"Firefox\",\"Safari\",\"其他\"],\"textStyle\":{\"color\":\"#fff\"}},\"series\":[{\"name\":\"浏览器用户比例\",\"type\":\"pie\",\"radius\":\"55%\",\"center\":[\"50%\",\"60%\"],\"data\":[{\"name\":\"Chrome\",\"value\":46.88},{\"name\":\"IE 9.0\",\"value\":7.4},{\"name\":\"IE 11.0\",\"value\":6.21},{\"name\":\"QQ\",\"value\":5.75},{\"name\":\"IE 8.0\",\"value\":5.74},{\"name\":\"2345\",\"value\":5.68},{\"name\":\"搜狗高速\",\"value\":4.74},{\"name\":\"Firefox\",\"value\":2.54},{\"name\":\"Safari\",\"value\":2.48},{\"name\":\"其他\",\"value\":12.59}],\"itemStyle\":{\"emphasis\":{\"shadowBlur\":10,\"shadowOffsetX\":0,\"shadowColor\":\"rgba(0, 0, 0, 0.5)\"}}}]}\n") myChart.setOption(option); </description>
</item>
<item>
<title>Network笔记整理 - 网络协议与网络分层</title>
<link>https://alili.tech/archive/ef96a5b6/</link>
<pubDate>Thu, 30 Aug 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/ef96a5b6/</guid>
<description>《圣经》中有一个通天塔的故事,上帝为了阻止人类联合起来,就让人类说不同的语言。人类没法儿沟通,达不成“协议”,通天塔的计划就失败了。
千年之后,一群工程师为了解决这一问题,制定了各种协议与标准,让各种设备可以通过协议通信,进而通过互联网实现了让世界互联.
就像我们现在写的代码,用着通用的程序语言,世界也就随之打通了.我们的计算机语言也算是一种协议.
想要让世界互联,让计算机们都联合起来,就必须要用到网络协议让他们相互协作,来完成共同的目标.
协议三要素 (1) 语义。每一段内容需要代表某种意义 (2) 语法。每一段内容符合一定规则的格式, (3) 时序。每一段任务的执行顺序.
网络分层 网络分层就是将网络节点所要完成的数据的发送或转发、打包或拆包,控制信息的加载或拆出等工作,分别由不同的硬件和软件模块去完成。
简单的来说一个完整的HTTP请求,途中需要经过数次传送,期间需要不通的都软件与硬件模块去完成相应的工作. 我们对相应的阶段的不通特性做出来相应的分类.每种网络分层,都有相应的协议标准做数据传送.
就像是一家公司,不通层级的人会用着不通的沟通方式来打交道.网络也大概如此.
我们常用的网络协议有哪些? 我们的网络在通讯过程中,要通过哪些设备,哪些协议才能做到一次完整的通讯?
网络层次可划分为五层因特网协议栈和七层因特网协议栈
五层模型 因特网协议栈共有五层:应用层、传输层、网络层、链路层和物理层。不同于OSI七层模型这也是实际使用中使用的分层方式。 (1)应用层 支持网络应用,应用协议仅仅是网络应用的一个组成部分,运行在不同主机上的进程则使用应用层协议进行通信。 (2)传输层 负责为信源和信宿提供应用程序进程间的数据传输服务,这一层上主要定义了两个传输协议,传输控制协议即TCP和用户数据报协议UDP。 (3)网络层 负责将数据报独立地从信源发送到信宿,主要解决路由选择、拥塞控制和网络互联等问题。 (4)数据链路层 负责将IP数据报封装成合适在物理网络上传输的帧格式并传输,或将从物理网络接收到的帧解封,取出IP数据报交给网络层。 (5)物理层 负责将比特流在结点间传输,即负责物理传输。该层的协议既与链路有关也与传输介质有关
五层模型对应的协议 物理层:以太网 · 调制解调器 · 电力线通信(PLC) · SONET/SDH · G.709 · 光导纤维 · 同轴电缆 · 双绞线等
数据链路层:Wi-Fi(IEEE 802.11) · WiMAX(IEEE 802.16) ·ATM · DTM · 令牌环 · 以太网 ·FDDI · 帧中继 · GPRS · EVDO ·HSPA · HDLC · PPP · L2TP ·PPTP · ISDN·STP 等</description>
</item>
<item>
<title>Linux - Centos 时区设置</title>
<link>https://alili.tech/archive/3f6742b1/</link>
<pubDate>Mon, 30 Jul 2018 20:32:05 +0000</pubDate>
<guid>https://alili.tech/archive/3f6742b1/</guid>
<description> timedatectl 命令 查看当前时区状态 $ timedatectl status Local time: Fri 2018-08-31 13:42:42 CST Universal time: Fri 2018-08-31 05:42:42 UTC RTC time: n/a Time zone: Asia/Shanghai (CST, +0800) NTP enabled: n/a NTP synchronized: yes RTC in local TZ: no DST active: n/a 设置时区为上海 $ timedatectl set-timezone Asia/Shanghai # 设置系统时区为上海 其他操作 $ timedatectl list-timezones # 列出所有时区 $ timedatectl set-local-rtc 1 # 将硬件时钟调整为与本地时钟一致, 0 为设置为 UTC 时间 </description>
</item>
<item>
<title>MongoDB - 在Egg中使用MondoDB</title>
<link>https://alili.tech/archive/c165a1d9/</link>
<pubDate>Fri, 18 May 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/c165a1d9/</guid>
<description>MongoDB官方有提供node操作数据库的 driver 及 API : node-mongodb-native
在egg社区也有基于该插件二次封装的egg插件 egg-mongo-native
对一些方法做了一些二次封装,也可以调用原版的方法.
配置 官方文档也有相关的配置说明,但是我在实际使用中碰到了一些问题. 下面我给出正确的配置方法,供大家使用.其他相关知识请参照该插件都官方文档.
// {app_root}/config/config.default.js export default (appInfo) =&gt; { const config = {}; config.mongo = { client: { host: '127.0.0.1', port: '27017', name: 'dandelion' }, } return config; }; 开启插件 // config/plugin.js const plugin = { mongo :{ enable: true, package: 'egg-mongo-native', } }; 要跟以上配置一样,才能正确使用该插件.
其他复杂配置请参照该插件的官方文档. egg-mongo-native</description>
</item>
<item>
<title>MongoDB - 文档的基本操作 (二)</title>
<link>https://alili.tech/archive/311875a2/</link>
<pubDate>Sun, 13 May 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/311875a2/</guid>
<description>文档更新 语法: update(, , )
#更新rank字段 &gt; db.posts.update({&quot;title&quot;:&quot;怪物猎人世界评测&quot;}, {$set: {&quot;rank&quot;: 10} }); # 更新整条数据为:{&quot;rank&quot;: 99} &gt; db.posts.update({&quot;title&quot;:&quot;怪物猎人世界评测&quot;}, {&quot;rank&quot;: 99}); # 更新多条记录multi: true,如果为false,则是更新查询到的第一条记录 &gt; db.posts.update({&quot;tag&quot;:&quot;it&quot;}, {$set: {&quot;rank&quot;: 60}}, {multi: true}); 操作文档字段的函数 $inc:递加 $mul:相乘 $rename:改名 $set:新增or修改 $unset:字段删除 # 字段值递增,结果为: 字段值 + 1 &gt; db.posts.update({title:&quot;怪物猎人世界评测&quot;}, {$inc: {rank: 1}}); # 字段值相乘操作,结果为: 字段值 * 2 &gt; db.posts.update({title:&quot;怪物猎人世界评测&quot;}, {$mul: {rank: 2}}); # 字段重命名 &gt; db.posts.update({title:&quot;怪物猎人世界评测&quot;}, {$rename: {&quot;rank&quot;: &quot;score&quot;}}); # 设置或者添加字段 &gt; db.</description>
</item>
<item>
<title>MongoDB - 文档的基本操作 (一)</title>
<link>https://alili.tech/archive/9e29eec0/</link>
<pubDate>Sat, 12 May 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/9e29eec0/</guid>
<description>文档增删 # 创建集合 &gt; db.createCollection(&quot;posts&quot;); # 插入一条数据 &gt; db.posts.insert( ... { ... title: &quot;我的第一篇博客&quot;, ... content: &quot;已经开始写博客了,太激动了。&quot; ... } ... ); # 查询数据 &gt; db.posts.find(); # 插入另一条数据 &gt; db.posts.insert( ... { ... title: &quot;我的第二篇博客&quot;, ... content: &quot;写点什么好呢?&quot;, ... tag: [&quot;未分类&quot;] ... } ... ); # 使用js for 来循环插入数据 &gt; for(var i = 3; i &lt;=10; i++ ) { ... db.posts.insert({ ... title: &quot;我的第&quot; + i + &quot;篇博客&quot; ... }); .</description>
</item>
<item>
<title>MongoDB - 数据库与集合的基本操作</title>
<link>https://alili.tech/archive/3a26a4b/</link>
<pubDate>Fri, 11 May 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/3a26a4b/</guid>
<description> 数据库基本操作 # 进入命令行 $ mongo #帮助 &gt; help #退出 &gt; exit #显示所有数据库 &gt; show dbs; #进入或者创建集合 &gt; use aliliblog; #查看当前数据库状态 &gt; db.stats(); # 删除数据库 &gt; db.dropDatabase(); 操作集合(Collection) # 查看集合 &gt; show collections; # 创建集合 &gt; db.createCollection(&quot;users&quot;); # 集合重命名 &gt; db.users.renameCollection(&quot;staff&quot;); // users -&gt; staff # 集合删除 &gt; db.staff.drop(); </description>
</item>
<item>
<title>MongoDB - 基本概念与其他数据库对比</title>
<link>https://alili.tech/archive/1f77f611/</link>
<pubDate>Thu, 10 May 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/1f77f611/</guid>
<description> 基本概念 NoSql 在NoSql的数据库中,操作数据都是通过指令或程序语言完成的。
在MongoDB中使用过Javascript和JSON数据结构,来操作和管理数据的。
MongoDB数据库与关系型数据库对比 MongoDB 关系型数据库 数据库(Database) 数据库(Database) 集合(Collection) 数据表(Table) 文档(Document) 记录(Record) MongoDB与RDBMS对应的术语 MongoDB RDBMS 数据库 数据库 集合 表格 文档 行 字段 列 嵌入文档 表联合 主键 (MongoDB 提供了 key 为 _id ) 主键 MongoDB 数据类型 数据类型 描述 String 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 Integer 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 Boolean 布尔值。用于存储布尔值(真/假)。 Double 双精度浮点值。用于存储浮点值。 Min/Max keys 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 Array 用于将数组或列表或多个值存储为一个键。 Timestamp 时间戳。记录文档修改或添加的具体时间。 Object 用于内嵌文档。 Null 用于创建空值。 Symbol 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 Date 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 Object ID 对象 ID。用于创建文档的 ID。 Binary Data 二进制数据。用于存储二进制数据。 Code 代码类型。用于在文档中存储 JavaScript 代码。 Regular expression 正则表达式类型。用于存储正则表达式。 </description>
</item>
<item>
<title>MongoDB - 安装与启动</title>
<link>https://alili.tech/archive/f82d8042/</link>
<pubDate>Wed, 09 May 2018 00:00:00 +0000</pubDate>
<guid>https://alili.tech/archive/f82d8042/</guid>