Docker Dockerfile

什么是 Dockerfile?
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

使用 Dockerfile 定制镜像
这里仅讲解如何运行 Dockerfile 文件来定制一个镜像,具体 Dockerfile 文件内指令详解,将在下一节中介绍,这里你只要知道构建的流程即可。

1、下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)

在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:

FROM nginx
RUN echo ‘这是一个本地构建的nginx镜像’ > /usr/share/nginx/html/index.html

2、FROM 和 RUN 指令的作用

FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。

RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

shell 格式:

RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
exec 格式:

RUN [“可执行文件”, “参数1”, “参数2”]
# 例如:
# RUN [“./test.php”, “dev”, “offline”] 等价于 RUN ./test.php dev offline
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz “http://download.redis.io/releases/redis-5.0.3.tar.gz”
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:

FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz “http://download.redis.io/releases/redis-5.0.3.tar.gz” \
&& tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

开始构建镜像
在 Dockerfile 文件的存放目录下,执行构建动作。

以下示例,通过目录下的 Dockerfile 构建一个 nginx:v3(镜像名称:镜像标签)。

注:最后的 . 代表本次执行的上下文路径,下一节会介绍。

$ docker build -t nginx:v3 .

以上显示,说明已经构建成功。

上下文路径
上一节中,有提到指令最后一个 . 是上下文路径,那么什么是上下文路径呢?

$ docker build -t nginx:v3 .
上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。

如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。

注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

指令详解
COPY
复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

格式:

COPY [–chown=:] <源路径1>… <目标路径>
COPY [–chown=:] [“<源路径1>”,… “<目标路径>”]
[–chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。

<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD
ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

CMD 在docker run 时运行。
RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

CMD
CMD [“<可执行文件或命令>”,””,””,…]
CMD [“”,””,…] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了 –entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

格式:

ENTRYPOINT [“”,””,””,…]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx

ENTRYPOINT [“nginx”, “-c”] # 定参
CMD [“/etc/nginx/nginx.conf”] # 变参
1、不传参运行

$ docker run nginx:test
容器内会默认运行以下命令,启动主进程。

nginx -c /etc/nginx/nginx.conf
2、传参运行

$ docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

格式:

ENV
ENV = =…
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

ENV NODE_VERSION 7.2.0

RUN curl -SLO “https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz” \
&& curl -SLO “https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc”
ARG
构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 –build-arg <参数名>=<值> 来覆盖。

格式:

ARG <参数名>[=<默认值>]
VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

作用:

避免重要的数据,因容器重启而丢失,这是非常致命的。
避免容器不断变大。
格式:

VOLUME [“<路径1>”, “<路径2>”…]
VOLUME <路径>
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

EXPOSE
仅仅只是声明端口。

作用:

帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:

EXPOSE <端口1> [<端口2>…]
WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

格式:

WORKDIR <工作目录路径>
USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

格式:

USER <用户名>[:<用户组>]
HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

格式:

HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:

ONBUILD <其它指令>
LABEL
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:

LABEL = = = …
比如我们可以添加镜像的作者:

LABEL org.opencontainers.image.authors=”StrongYuen”

OpenWRT下安装和配置shadowsocks

本文主要记录在openWRT下安装和配置shadowsocks的简要过程,便于日后查找和备忘。成功安装后可以实现透明代理,分流和防DNS污染。

Environment

  • 路由器型号:YouHua WR1200JS
  • 固件版本:OpenWrt 19.07.4 r11208-ce6496d796 / LuCI openwrt-19.07 branch git-21.054.03371-3b137b5

拓扑图+工作原理

topology map

  1. dnsmasq是openwrt自带的一个软件,提供dns缓存,dhcp等功能。dnsmasq会将dns查询数据包转发给chinadns。
  2. chinadns的上游DNS服务器有两个,一个是国内DNS,一个是可信DNS(国外DNS)。
    • chinadns会同时向上游的DNS发送请求
    • 如果可信DNS先返回, 则直接采用可信DNS的结果
    • 如果国内DNS先返回, 分两种情况: 如果返回的结果是国内IP,则采用;否则丢弃并等待采用可信DNS的结果

3.dns-forwarder 支持DNS TCP查询, 如果ISP的UDP不稳定, 丢包严重,可以使用dns-forwarder来代替ss-tunnel来进行DNS查询.

4.shadowsocks 用于转发数据包, 科学上网. 关于shadowsocks的科普文章可查看这里: https://www.css3er.com/p/107.html

相关的ipk软件包下载地址

ipk软件包集合, 不同的CPU架构需要使用不同的软件包, CPU架构是mipsel_24kc的话, 可以集中从这里下载.
链接: https://pan.baidu.com/s/14QDoTLqw-SEBZvQVQeVgvA 提取码: ugsc
其它的CPU架构, 可以去GitHub主页 -> Releases下载别人已经编译好的软件包, 如果没有, 只能自己下载openWRT的SDK, 自己进行编译.

  • shadowsocks-libev_3.3.5-1_mipsel_24kc.ipk
  • shadowsocks-libev-server_3.3.5-1_mipsel_24kc.ipk
  • ChinaDNS_1.3.3-1_mipsel_24kc.ipk
  • dns-forwarder_1.2.1-2_mipsel_24kc.ipk
  • luci-compat
  • luci-app-shadowsocks-without-ipset_1.9.1-1_all.ipk
  • luci-app-chinadns_1.6.2-1_all.ipk
  • luci-app-dns-forwarder_1.6.2-1_all.ipk

链接: https://pan.baidu.com/s/14QDoTLqw-SEBZvQVQeVgvA 提取码: ugsc

openwrt-shadowsocks

GitHubhttps://github.com/shadowsocks/openwrt-shadowsocks
luci-app-shadowsockshttps://github.com/shadowsocks/luci-app-shadowsocks

  • shadowsocks-libev
     客户端/
     └── usr/
         └── bin/
             ├── ss-local       // 提供 SOCKS 正向代理, 在透明代理工作模式下用不到这个.
             ├── ss-redir       // 提供透明代理, 从 v2.2.0 开始支持 UDP
             └── ss-tunnel      // 提供端口转发, 可用于 DNS 查询
    
  • shadowsocks-libev-server
    服务端/
    └── usr/
        └── bin/
            └── ss-server      // 服务端可执行文件
    

ChinaDNS

GitHubhttps://github.com/aa65535/openwrt-chinadns
原版ChinaDNS地址, 被请喝茶后已不再维护:https://github.com/shadowsocks/ChinaDNS
luci-app-chinadnshttps://github.com/aa65535/openwrt-dist-luci

更新 /etc/chinadns_chnroute.txt

1
 wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | awk -F\| '/CN\|ipv4/ { printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > /etc/chinadns_chnroute.txt

dns-forwarder

GitHubhttps://github.com/aa65535/openwrt-dns-forwarder
luci-app-dns-forwarderhttps://github.com/aa65535/openwrt-dist-luci

dnsmasq

openWRT自带, 无需自行下载安装.
GitHubhttps://github.com/aa65535/openwrt-dnsmasq

Install

去软件项目的GitHub主页 -> Releases下面下载编译好的ipk, 如果没有符合的自己CPU架构的包, 则需要自己下载openWRT的SDK进行编译, 具体的教程各个主页上有.
查看CPU架构的命令 opkg print-architecture:

1
2
3
4
5
root@OpenWrt:~# opkg print-architecture
arch all 1
arch noarch 1
arch mipsel_24kc 10
root@OpenWrt:~#

下载完成有两种方式安装
方式一(建议): 通过web使用luci安装: 路径: 系统 -> Software -> Upload Package… -> Install

方式二: 直接在线通过opkg命令来安装(注意使用方式需要提前更新好软件源, opkg update):

1
opkg install luci-compat

Config

方式一, 使用luci来配置

登录luci.

  1. 配置ss-server
    服务 -> 影梭 -> 服务器管理, 添加自己的shadowsocks server
  2. 配置dnsmasq
    • 网络 -> DHCP/DNS -> 常规设置 -> 本地服务器, 设置为 127.0.0.1#5353
    • 网络 -> DHCP/DNS -> HOSTS和解析文件, 勾选: 忽略解析文件
  3. 配置ChinaDNS
    服务 -> ChinaDNS
    监听端口: 5353
    上游服务器修改为: 114.114.114.114,127.0.0.1#5300
    这样国内DNS114.114.114.114可信DNS127.0.0.1#5353, 勾选 启用, 保存设置
  4. 配置dns-forwarder
    服务 -> DNS转发
    监听端口: 5300 监听地址: 0.0.0.0
    上游 DNS: 8.8.8.8 勾选, 启用 保存
  5. 配置shadowsocks 透明代理 + 访问控制
    服务 -> 影梭 -> 常规设置 -> 透明代理
    主服务器, 选择setp1中配置的ss-server, 保存.
    服务-> 影梭 -> 常规设置 -> 访问控制-> 外网区域
    被忽略IP列表, 选择 ChinaDNS路由表, 保存设置. 注意这里的优先级: (走代理IP列表 = 强制走代理IP) > (额外被忽略IP = 被忽略IP列表)
  6. 保存并应用 所有配置, reboot openWRT

方式二, 直接编辑/etc/config目录下的文件

课外阅读: UCI System UCI system

The abbreviation UCI stands for Unified Configuration Interface and is intended to centralize the configuration of OpenWrt.

/etc/config/shadowsocks

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
root@OpenWrt:~# cat /etc/config/shadowsocks

config general
  option startup_delay '0'

config transparent_proxy
  option udp_relay_server 'nil'
  option local_port '1234'
  option mtu '1492'
  list main_server 'cfg054a8f'

config socks5_proxy
  option local_port '1080'
  option mtu '1492'
  list server 'nil'

config port_forward
  option local_port '5300'
  option mtu '1492'
  option destination '8.8.8.8:53'
  list server 'nil'

config servers
  option fast_open '0'
  option no_delay '0'
  option timeout '60'
  option server '服务器地址,注意luci下这里只能是ip'
  option server_port '端口'
  option password '密码'
  option encrypt_method '加密方式'
  option alias 'ss服务别名'

config access_control
  option self_proxy '1'
  option lan_target 'SS_SPEC_WAN_AC'
  option wan_bp_list '/etc/chinadns_chnroute.txt'

 

/etc/config/dhcp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
root@OpenWrt:~# cat /etc/config/dhcp

config dnsmasq
  option domainneeded '1'
  option localise_queries '1'
  option rebind_protection '1'
  option rebind_localhost '1'
  option domain 'lan'
  option expandhosts '1'
  option authoritative '1'
  option readethers '1'
  option leasefile '/tmp/dhcp.leases'
  option localservice '1'
  option local '127.0.0.1#5353'
  option noresolv '1'
...

/etc/config/chinadns

1
2
3
4
5
6
7
8
9
root@OpenWrt:~# cat /etc/config/chinadns

config chinadns
  option chnroute '/etc/chinadns_chnroute.txt'
  option addr '0.0.0.0'
  option port '5353'
  option bidirectional '1'
  option server '114.114.114.114,127.0.0.1#5300'
  option enable '1'

/etc/config/dns-forwarder

1
2
3
4
5
6
7
root@OpenWrt:~# cat /etc/config/dns-forwarder

config dns-forwarder
  option listen_addr '0.0.0.0'
  option listen_port '5300'
  option enable '1'
  option dns_servers '8.8.8.8'

验证配置是否生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@OpenWrt:~# netstat -lpn | grep ss
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:1234            0.0.0.0:*               LISTEN      13469/ss-redir
root@OpenWrt:~# netstat -lpn | grep 5353
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           1438/chinadns
root@OpenWrt:~# netstat -lpn | grep 5300
udp        0      0 0.0.0.0:5300            0.0.0.0:*                           12993/dns-forwarder
root@OpenWrt:~# netstat -lpn | grep 53
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      2254/dnsmasq
...

root@OpenWrt:~# nslookup google.com 127.0.0.1#5353
Server:       127.0.0.1
Address:  127.0.0.1#5353

Name:      google.com
Address 1: 142.250.72.238
Address 2: 2607:f8b0:4007:80d::200e
root@OpenWrt:~#

Issues

  • luci-app-shadowsocks 不支持domain的方式配置ss-server, 需要使用IP地址

Link

https://www.youtube.com/watch?v=2SPQYsMmltE&t=317s – 十年老程 openwrt shadowsocks安装配置对应的视频教程 http://snlcw.com/305.html – 上述教程对应的blog地址. https://www.youtube.com/channel/UCgo7XWK6MQBgKt0gBI6x3CA/videos – 十年老程的Youtube专栏,里面有各种科学上网的视频教程. https://openwrt.org/docs/guide-user/base-system/dhcp_configuration

penWRT 结合 tinc 组自己的 SDLAN(Step by Step)

本文主要实现在OpenWRT路由器以及不同系统下通过tinc switch mode搭建SDLAN内网服务器方便远程连接,

Switch Mode相对来说配置比较简单,各节点均在同一广播域内,方便调控,tinc节点本身通过DNAT+SNAT可以实现对不同网间端口的调通,

同时Switch Mode中各节点的hosts文件只需保证在公网地址的节点中全部拥有维护即可,其他节点只需维护本节点以及公网节点的hosts文件

下面主要分三步:

(1)公网节点的部署(Master节点)

(2)其他节点的部署(Slave节点)

(3)节点的NAT配置

本次搭建的拓扑以下为例,两个Master节点,若干个Slave节点(以3个不同操作系统的为例)

(0)tinc的安装

各大Linux发行版基本都可以通过包管理对tinc进行安装

sudo yum install tinc
sudo apt install tinc 

OpenWRT也可通过opkg安装tinc

opkg update
opkg install tinc

Windows可在官网下载

Windows中自带的TAP-Windwos版本比较低,建议可以考虑另外安装版本较新的TAP-Windows新建虚拟网卡而不是用tinc-vpn安装包中自带的TAP-Windows

(1)公网节点的部署(Master节点)

需要预先定义定义一个网络名 本次以tincnet为例NETNAME = tincnet

每个节点均需要以以下目录结构创建好配置文件夹

/etc/tinc/tincnet

 % ls -la
total 24
drwxr-xr-x 3 root root 4096 Mar  4 15:07 .
drwxr-xr-x 4 root root 4096 Mar  4 15:06 ..
drwxr-xr-x 2 root root 4096 Mar  4 15:06 hosts
-rwxr-xr-x 1 root root  198 Mar  4 15:06 tinc.conf
-rwxr-xr-x 1 root root   72 Mar  4 15:06 tinc-down
-rwxr-xr-x 1 root root   81 Mar  4 15:06 tinc-up

tinc.conf为tinc的配置文件,tinc-down,tinc-up为启动tinc时执行的脚本,一般用作启动网络,hosts文件夹中存的是各个结点的连接交换信息。

下面先说其中一个节点Linux_Public_Node(2.2.2.2)

各个文件配置情况:

tinc.conf

 % cat tinc.conf 
Name = Linux_Public_Node #此节点名称为Linux_Public_Node
AddressFamily = ipv4 #Internet走IPv4协议
BindToAddress = * 11001 #监听端口
Interface = tinctun0 #tincnet虚拟网卡
Device = /dev/net/tun 
#Mode = <router|switch|hub> (router)
Mode = switch #设置使用Swtich模式 默认为router
ConnectTo = OpenWRT_Public_Node  #连接另一公网Master节点保持双活
Cipher = aes-128-cbc #对称加密算法

tinc-up tinc启动脚本,给对应网卡加IP

 % cat tinc-up
#!/bin/sh
ip link set $INTERFACE up
ip addr add 192.168.212.8/24 dev $INTERFACE

tinc-down tinc停止脚本,关停对应网卡

#!/bin/sh
ip addr del 192.168.212.8/24 dev $INTERFACE
ip link set $INTERFACE down

hosts文件夹 主要保存各节点的交换信息,由于是第一次创建,里面应该是空文件夹,需要先创建一个自己节点的链接信息

 cd hosts
 touch Linux_Public_Node
 % cat Linux_Public_Node 
Address = 2.2.2.2 #公网地址
Subnet = 192.168.212.8/32 #tincnetIP信息
Port = 11001 #公网监听端口

创建完成后通过tincd生成非对称密钥信息

 % sudo tincd -n tincnet -K
Generating 2048 bits keys:
.............+++++ p
........................+++++ q
Done.
Please enter a file to save private RSA key to [/etc/tinc/tincnet/rsa_key.priv]: 
Please enter a file to save public RSA key to [/etc/tinc/tincnet/hosts/Linux_Public_Node]: 

现在tincnet文件夹中会生成私钥,对应的公钥信息会补全到host/Linux_Public_Node中

 % ls /etc/tinc/tincnet                    
hosts  rsa_key.priv  tinc.conf	tinc-down  tinc-up

 % cat /etc/tinc/tincnet/hosts/Linux_Public_Node 
Address = 2.2.2.2 
Subnet = 192.168.212.8/32
Port = 11001
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAp7F+8s8lukRv0qaE5hzrQmuy2MPb8hlte/G0pcfnBCVjIL5foJ7P
LZQrTGTsKjRbPzJ9gfZUXiZRkaA+G6Q4DBOVEt41cTceZTgAzL3ief3H6MNXQ0xW
1Wo8kDNlg6g+QJq8iV5j7adJnEPivrDm4CWl8MRmVOckisnQbseKXeuzIYDhpZLA
nlIIGMzhk3OZoPn2xpdMbJqbR0K6SrPvYq7sT3eLn0NVUbyo9D1dmtwtOJy8wmaf
oYdwTvrMdXhNNUmemnswJt8T2j8rAerqnjqz5itN8dk9mZMTKLFZ44CNnJ8jl5pE
ma8lfUnAA/Qq7i9t74pVEvWcLg8HIry16QIDAQAB
-----END RSA PUBLIC KEY-----

至此,节点Linux_Public_Node(2.2.2.2)中的配置已经完成,

下面配置另外一个节点OpenWRT_Public_Node(1.1.1.1)

主要的配置文件生成过程节点Linux_Public_Node类似

生成后如下:

ls -la /etc/tinc/tincnet/
drwxr-xr-x    3 root     root          4096 Mar  4 15:32 .
drwxr-xr-x    4 root     root          4096 Mar  4 15:29 ..
drwxr-xr-x    2 root     root          4096 Mar  4 15:32 hosts
-rw-------    1 root     root          1680 Mar  4 15:32 rsa_key.priv
-rwxr-xr-x    1 root     root            72 Mar  4 15:30 tinc-down
-rwxr-xr-x    1 root     root            80 Mar  4 15:30 tinc-up
-rw-r--r--    1 root     root           218 Mar  4 15:31 tinc.conf

ls -la /etc/tinc/tincnet/hosts
drwxr-xr-x    2 root     root          4096 Mar  4 15:32 .
drwxr-xr-x    3 root     root          4096 Mar  4 15:32 ..
-rw-r--r--    1 root     root           484 Mar  4 15:32 OpenWRT_Public_Node

cat /etc/tinc/tincnet/tinc.conf 
Name = OpenWRT_Public_Node
AddressFamily = ipv4
BindToAddress = * 11001
Interface = tinctun0
Device = /dev/net/tun
#Mode = <router|switch|hub> (router)
Mode = switch
ConnectTo = Linux_Public_Node
Cipher = aes-128-cbc

cat /etc/tinc/tincnet/tinc-up
#!/bin/sh
ip link set $INTERFACE up
ip addr add 192.168.212.6/24 dev $INTERFACE

cat /etc/tinc/tincnet/tinc-down
ip addr del 192.168.212.6/24 dev $INTERFACE
ip link set $INTERFACE down

cat /etc/tinc/tincnet/hosts/OpenWRT_Public_Node 
Address = 1.1.1.1
Subnet = 192.168.212.6/32
Port = 11001
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA6Tzot1eXupi+NRCfr29iKbgiXEMW1Ol327WOrAwRtiwGgQIx8LcL
iy9m+sZEWVzlfvhMub6RVM4xlZ39ghYn2OFP4x9K4D6O/HTZHbamuLOEG5zRyVGK
EN+tTStIeEaiHad04QR+6ZFB+UO7WFcBzwVh/rysOL96KaUoU9VeYHVAIkubNsvA
aNSFbmqGYpl5FrXv+sJjMyGRXjc9Lb3q/FWmPApvo/9FTElHx0xH7wvAZnc7mTCH
DB6DN62A1McgydGpn7NLnuFFEeVQf3SI9TqvajcA3vXS8P9RWuRoF5HivZIL5Ebn
FJg0UkyJcWXHUNRczdfTACF6ha0ewk8T9QIDAQAB
-----END RSA PUBLIC KEY-----

OpenWRT下需要再对/etc/config/tinc进行以下修改

cat /etc/config/tinc 
config tinc-net tincnet
	option enabled 1
	option Name OpenWRT_Public_Node

config tinc-host OpenWRT_Public_Node
	option enabled 1
	option net tincnet

下面要做的就是先将两个Master节点的hosts文件夹各自补充对方的节点信息,简单来说就是复制自己那份过去对面,保证两个节点的hosts文件夹都有全部节点的hosts信息

% ls -la /etc/tinc/tincnet/hosts 
total 16
drwxr-xr-x 2 root root 4096 Mar  4 15:37 .
drwxr-xr-x 3 root root 4096 Mar  4 15:25 ..
-rw-r--r-- 1 root root  486 Mar  4 15:25 Linux_Public_Node
-rw-r--r-- 1 root root  485 Mar  4 15:37 OpenWRT_Public_Node

% cat Linux_Public_Node 
Address = 2.2.2.2 
Subnet = 192.168.212.8/32
Port = 11001
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAp7F+8s8lukRv0qaE5hzrQmuy2MPb8hlte/G0pcfnBCVjIL5foJ7P
LZQrTGTsKjRbPzJ9gfZUXiZRkaA+G6Q4DBOVEt41cTceZTgAzL3ief3H6MNXQ0xW
1Wo8kDNlg6g+QJq8iV5j7adJnEPivrDm4CWl8MRmVOckisnQbseKXeuzIYDhpZLA
nlIIGMzhk3OZoPn2xpdMbJqbR0K6SrPvYq7sT3eLn0NVUbyo9D1dmtwtOJy8wmaf
oYdwTvrMdXhNNUmemnswJt8T2j8rAerqnjqz5itN8dk9mZMTKLFZ44CNnJ8jl5pE
ma8lfUnAA/Qq7i9t74pVEvWcLg8HIry16QIDAQAB

% cat OpenWRT_Public_Node 
Address = 1.1.1.1
Subnet = 192.168.212.6/32
Port = 11001
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA6Tzot1eXupi+NRCfr29iKbgiXEMW1Ol327WOrAwRtiwGgQIx8LcL
iy9m+sZEWVzlfvhMub6RVM4xlZ39ghYn2OFP4x9K4D6O/HTZHbamuLOEG5zRyVGK
EN+tTStIeEaiHad04QR+6ZFB+UO7WFcBzwVh/rysOL96KaUoU9VeYHVAIkubNsvA
aNSFbmqGYpl5FrXv+sJjMyGRXjc9Lb3q/FWmPApvo/9FTElHx0xH7wvAZnc7mTCH
DB6DN62A1McgydGpn7NLnuFFEeVQf3SI9TqvajcA3vXS8P9RWuRoF5HivZIL5Ebn
FJg0UkyJcWXHUNRczdfTACF6ha0ewk8T9QIDAQAB
-----END RSA PUBLIC KEY-----

最后通过systemctl,OpenWRT通过RC启动tinc, 并互ping测试一下

#Linux_Public_Node systemctl
systemctl start tinc@tincnet
#OpenWRT_Public_Node rc
/etc/init.d/tinc start

ping from Linux_Public_Node(192.168.212.8) to OpenWRT_Public_Node(192.168.212.6)

ping from OpenWRT_Public_Node(192.168.212.6) to Linux_Public_Node(192.168.212.8)

(2)其他节点的部署(Slave节点)

Linux系统以节点OpenWRT_Internal_Node(192.168.212.12)为例

同样,先按照之前的文件夹结构创建好对应目录,并复制两个Master节点hosts信息到hosts文件夹,

ls -la /etc/tinc/tincnet/
drwxr-xr-x    3 root     root             0 Mar  4 16:01 .
drwxr-xr-x    4 root     root             0 Mar  4 15:52 ..
drwxr-xr-x    2 root     root             0 Mar  4 16:01 hosts
-rw-------    1 root     root          1676 Mar  4 16:01 rsa_key.priv
-rwxr-xr-x    1 root     root            74 Mar  4 15:58 tinc-down
-rwxr-xr-x    1 root     root            82 Mar  4 15:58 tinc-up
-rw-r--r--    1 root     root           209 Mar  4 16:00 tinc.conf

ls -la /etc/tinc/tincnet/hosts/
drwxr-xr-x    2 root     root             0 Mar  4 16:01 .
drwxr-xr-x    3 root     root             0 Mar  4 16:01 ..
-rw-r--r--    1 root     root             0 Mar  4 15:58 Linux_Public_Node
-rw-r--r--    1 root     root           454 Mar  4 16:01 OpenWRT_Internal_Node
-rw-r--r--    1 root     root             0 Mar  4 15:58 OpenWRT_Public_Node

cat /etc/tinc/tincnet/
hosts/        rsa_key.priv  tinc-down     tinc-up       tinc.conf

cat /etc/tinc/tincnet/tinc.conf 
Name = OpenWRT_Internal_Node 
Interface = tinctun0
Device = /dev/net/tun
#Mode = <router|switch|hub> (router)
Mode = switch
ConnectTo = Linux_Public_Node #此处需要配置链接到两个主节点
ConnectTo = OpenWRT_Public_Node #此处需要配置链接到两个主节点
Cipher = aes-128-cbc

cat /etc/tinc/tincnet/tinc-up
#!/bin/sh
ip link set $INTERFACE up
ip addr add 192.168.212.12/24 dev $INTERFACE

cat /etc/tinc/tincnet/tinc-down
ip addr del 192.168.212.12/24 dev $INTERFACE
ip link set $INTERFACE down

cat /etc/tinc/tincnet/hosts/OpenWRT_Internal_Node 
Subnet = 192.168.212.21/32 #只需要配置Subnet参数

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAnU1maDEvbyC2XJLC8aiiwixR+einVu9gyJ4Pi1uhNMSJuVHB0HLQ
s16eOJvoEeJ4q6x0YLwjVJLlcLRW46wUAr1eMLjiovGKcYL8fZCg+Agms3+0y2SM
MaKi5fgBKjXLhdeBx4pvLaBlgYz4BP7pcVLgI0/NHBR6K1PClUtYDN1xCt5SOpiF
XIwyIawwIs6mxLknm7M0a68j7e3ovIsBOW7nLVL0GpLXVJBjAbs5z00uNOVaNJkz
tvttShGgaa+B6o1Xy8gLwB84wKNUXZbmkLobOK7h0qYgEmnQscR8Rhw5G9UJfU8G
8nrPdRRCZnDR5xRpuy0rRJG7gAzpEJ9kHwIDAQAB
-----END RSA PUBLIC KEY-----

#以下为OpenWRT系统需要配置
cat /etc/config/tinc 
config tinc-net tincnet
	option enabled 1
	option Name OpenWRT_Internal_Node

config tinc-host OpenWRT_Internal_Node
	option enabled 1
	option net tincnet

然后需要复制hosts文件夹的本节点信息host\OpenWRT_Internal_Node到Master节点的hosts文件夹中,重启tinc服务即可通,

ping 192.168.212.8
PING 192.168.212.8 (192.168.212.8): 56 data bytes
64 bytes from 192.168.212.8: seq=0 ttl=64 time=25.108 ms
64 bytes from 192.168.212.8: seq=1 ttl=64 time=8.567 ms
64 bytes from 192.168.212.8: seq=2 ttl=64 time=8.891 ms
64 bytes from 192.168.212.8: seq=3 ttl=64 time=8.745 ms
^C
--- 192.168.212.8 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 8.567/12.827/25.108 ms

ping 192.168.212.6
PING 192.168.212.6 (192.168.212.6): 56 data bytes
64 bytes from 192.168.212.6: seq=0 ttl=64 time=7.328 ms
64 bytes from 192.168.212.6: seq=1 ttl=64 time=6.871 ms
64 bytes from 192.168.212.6: seq=2 ttl=64 time=7.205 ms
64 bytes from 192.168.212.6: seq=3 ttl=64 time=7.130 ms
^C
--- 192.168.212.6 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 6.871/7.133/7.328 ms

再配置一个Windows系统的,

首先需要新增一个TAP-Windows的虚拟网卡,以另外安装的新版本TAP-Windows驱动为例,管理员权限运行CMD

C:\Users\k>cd C:\Program Files\TAP-Windows\bin

C:\Program Files\TAP-Windows\bin>.\addtap.bat

C:\Program Files\TAP-Windows\bin>rem Add a new TAP virtual ethernet adapter

C:\Program Files\TAP-Windows\bin>"C:\Program Files\TAP-Windows\bin\tapinstall.exe" install "C:\Program Files\TAP-Windows\driver\OemVista.inf" tap0901
Device node created. Install is complete when drivers are installed...
Updating drivers for tap0901 from C:\Program Files\TAP-Windows\driver\OemVista.inf.
Drivers installed successfully.

C:\Program Files\TAP-Windows\bin>pause
请按任意键继续. . .

到网络连接管理中重命名网卡名称并手动配置IP地址

然后创建好文件目录

C:\Program Files\tinc\tincnet 的目录

2020/03/04  16:14    <DIR>          .
2020/03/04  16:14    <DIR>          ..
2020/03/04  16:16    <DIR>          hosts
2020/03/04  16:17               167 tinc.conf
               1 个文件            167 字节
               3 个目录 144,868,106,240 可用字节
               
C:\Program Files\tinc\tincnet\hosts 的目录

2020/03/04  16:16    <DIR>          .
2020/03/04  16:16    <DIR>          ..
2020/03/04  16:16               499 Linux_Public_Node
2020/03/04  16:16               496 OpenWRT_Public_Node
2020/03/04  16:16                27 Windows_Internal_Node
               3 个文件          1,022 字节
               2 个目录 144,864,964,608 可用字节

C:\Program Files\tinc\tincnet\tinc.conf

Name = Windows_Internal_Node
Interface = tinctun0
#Mode = <router|switch|hub> (router)
Mode = switch
ConnectTo = OpenWRT_Public_Node
ConnectTo = Linux_Public_Node

C:\Program Files\tinc\tincnet\hosts\Windows_Internal_Node

Subnet = 192.168.212.116/32

生成密钥

C:\Program Files\tinc>.\tinc.exe -n tincnet
tinc.tincnet> generate-rsa-keys
Generating 2048 bits keys:
...................................................+++ p
......................+++ q
Done.
Please enter a file to save private RSA key to [C:/Program Files\tinc\tincnet\rsa_key.priv]:
Please enter a file to save public RSA key to [C:/Program Files\tinc\tincnet\hosts\Windows_Internal_Node]:
tinc.tincnet> quit

C:\Program Files\tinc>

然后将带公钥信息的Windows_Internal_Node复制到两个Master节点上面重启节点

通过Windows计算机管理中的服务启动tinc

PING其他Slave节点测试

C:\Program Files\tinc>ping 192.168.212.12

正在 Ping 192.168.212.12 具有 32 字节的数据:
来自 192.168.212.12 的回复: 字节=32 时间=12ms TTL=64
来自 192.168.212.12 的回复: 字节=32 时间=11ms TTL=64
来自 192.168.212.12 的回复: 字节=32 时间=12ms TTL=64
来自 192.168.212.12 的回复: 字节=32 时间=11ms TTL=64

192.168.212.12 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 11ms,最长 = 12ms,平均 = 11ms

如果还有新增节点,那么只需在节点本地创建好配置文件以及hosts信息,然后将本节点的hosts信息复制到Master节点上面即可。

(3)节点的NAT配置

这个是补充内容,比如Slave节点OpenWRT_Internal_Node的br-lan网卡有另一网段192.168.1.0/24的地址192.168.1.1,那么如果我想在Windows_Internal_Node通过OpenWRT_Internal_Node的 tincnet地址192.168.212.12:8080直接访问OpenWRT_Internal_Node 192.168.1.0/24网段中的192.168.1.20:80,那么可以可以通过NAT直接实现。

具体iptables配置如下:

iptables -A input_rule -i tinctun+ -j ACCEPT
iptables -A forwarding_rule -i tinctun+ -j ACCEPT
iptables -A forwarding_rule -o tinctun+ -j ACCEPT
iptables -A output_rule -o tinctun+ -j ACCEPT

iptables -t nat -A PREROUTING -i tinctun0 -p tcp -d 192.168.212.12 --dport 8080 -j DNAT --to-destination 192.168.1.20:80
iptables -t nat -A POSTROUTING -s 192.168.212.0/24 -o br-lan -j SNAT --to 192.168.1.1

refer: https://vnf.cc/2020/03/openwrt-tinc/

Docker OpenWrt Builder

Docker OpenWrt Builder

Build OpenWrt images in a Docker container. This is sometimes necessary when building OpenWrt on the host system fails, e.g. when some dependency is too new. The docker image is based on Debian 10 (Buster).

Build tested:

  • OpenWrt-21.02.2
  • OpenWrt-19.07.8
  • OpenWrt-18.06.9

A smaller container based on Alpine Linux is available in the alpine branch. But it does not build the old LEDE images.

Prerequisites

  • Docker installed
  • running Docker daemon
  • build Docker image:
git clone https://github.com/strongkill/docker-openwrt-builder.git
cd docker-openwrt-builder
docker build -t openwrt_builder .

Now the docker image is available. These steps only need to be done once.

Usage GNU/Linux

Create a build folder and link it into a new docker container:

mkdir ~/mybuild
docker run -v ~/mybuild:/home/user -it openwrt_builder /bin/bash

In the container console, enter:

git clone https://git.openwrt.org/openwrt/openwrt.git
cd openwrt
./scripts/feeds update -a
./scripts/feeds install -a
make menuconfig
make -j4

After the build, the images will be inside ~/mybuild/openwrt/bin/target/.

Usage MacOSX

OpenWrt requires a case-sensitive filesystem while MacOSX uses a case-insensitive filesystem by default.

Create a disk image:

hdiutil create -size 20g -fs "Case-sensitive HFS+" -volname OpenWrt OpenWrt.dmg 
hdiutil attach OpenWrt.dmg

Then run:

docker run -v /volumes/openwrt:/home/user -it openwrt_builder /bin/bash

(Source)

Usage Windows

TODO

Other Projects

Other, but very similar projects:

IAR for STM8的簡介、下載、安裝及註冊教程

一、簡介

1.關於IAR for STM8

IAR for STM8 是一個嵌入式工作平台,主要應用於STM8 系列芯片的開發,現在(2018年3.10版本)能夠支持市面上所有的STM8芯片。

個人認為,IAR for STM8和Keil差別並不是很大,只要熟悉Keil的使用,那上手IAR for STM8並不是什麼難事,網絡上也有許多相關資料可以查詢。

2.關於該篇博客

這一篇博客主要來講解一下IAR的下載、安裝、註冊的步驟,

雖然說的是IAR for STM8的教程,

但其實ARM跟其他的下載、安裝步驟類似的。

大家可以從我的百度雲下載IAR for STM8(3.10版本)和註冊機!!!

鏈接:https://pan.baidu.com/s/16UHwCZkgONEeLwiwBawAhg
提取碼:gvj9 

二、下載IAR for STM8軟件(以下兩種下載方法均可)

1.從官網下載

網址:https://www.iar.com/iar-embedded-workbench/#!?architecture=STM8

2.百度雲下載

鏈接:https://pan.baidu.com/s/1KU6QKuLZXysiwo9J_b0fPQ
提取碼:3nf0 

 

 

三、安裝IAR for STM8軟件

軟件安裝就比較簡單了,這裡就沒什麼難的地方~

只要從一開始的這個界面,一直點“next”、“yes”、“是”……就能順利安裝完成~

安裝完成後進入軟件界面,如下:

 

 

 四、軟件註冊

1.打開軟件IAR Embedded Workbench IDE:License Manager ->“取消”->“確定”

License Manager:

 

“取消”:

 

“確定”:

2.許可管理License Manager:“License”->“Offline Activation”(離線激活) ->“License Wizard”

License Manager:

 

點擊“License”->“Offline Activation” :

 

License Wizard:

3.打開註冊機: 選STM8->生成許可碼->複製

 

選擇STM8:

 

生成(Generate):

 

複製:

4.激活界面:黏貼->下一步->……

 

選擇“No” :

 

選擇存儲路徑:

 

放在此路徑下:

 

請求激活信息界面:

5.註冊機:選擇剛才存儲的文件->

 

點擊後生成新的文件:

 

 

再選取新生成的文件:

 

點擊下一步:

6.檢查註冊狀況:

雙擊: 

 

顯示狀態都是“ok”,那就恭喜註冊成功!!!

事到如今,IAR for STM8 已經完全可以使用了。

希望能幫助到有需要的朋友~

 

移動端H5真機調試方案

今年入職了一家做直播的公司,主要是負責APP中內嵌webview頁面的開發,之前移動端兼容經驗比較少,對於我來說最大的困擾就是網頁兼容性問題。

在Chrome瀏覽器的模擬器進行開發調試已經完美完成了需求之後,一到驗收或者上線,就出現各種兼容引起的bug,要解決還特別曲折,不僅要探索Android和iOS手機的不同調試方式,還要支持在不同瀏覽器或者APP上調試,極大的影響了開發的效率。

雖然我們也可以通過模擬器進行開發調試,但模擬終究是模擬,在某些場景下真機還是不可或缺,尤其是特定機型版本的問題。

一般情況下,真機Web調試要怎麼做呢?

一、vConsole

npm地址: github.com/Tencent/vCo…

介紹: vConsole插件是一個移動端輕量可擴展的工具,其功能和電腦端的控制台基本一致,能運行JS代碼、查看cookie、抓包等

使用: 在head中添加如下代碼即可

<script src="https://cdn.bootcss.com/vConsole/3.3.4/vconsole.min.js"></script>
<script>
   // 初始化
   var vConsole = new VConsole();
   console.log("hello vconsole");
</script>
复制代码

如果是想通過npm安裝或者對於TypeScript的使用方式請去倉庫查看!

調試: vConsole

面板: 報錯

其實和console控制台一樣,打開一個頁面的時候,下方會出現一個綠色的“vConsole”按鈕,點擊按鈕即可打開控制台,在“log”頁面中輸入JS代碼,即可執行腳本,“Network”頁面為分析網絡會話列表,“System”頁面顯示協議頭User-Agent、系統信息網絡狀態等信息,“Storage”頁面為cookie信息等

二、Eruda

npm地址: github.com/liriliri/er…

介紹: Eruda 是一個專為前端移動端、移動端設計的調試面板,類似Chrome DevTools 的迷你版(沒有chrome強大這個是可以肯定的),其主要功能包括:捕獲console 日誌、檢查元素狀態、顯示性能指標、捕獲XHR請求、顯示本地存儲和Cookie信息、瀏覽器特性檢測等等。

使用: 在head中添加如下代碼即可

<script src="//cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script>
复制代码

Eruda 的使用方法和麵板跟vConsole差不多,更詳細的使用方法可去官方倉庫查看!

三、Fildder

下載地址: www.telerik.com/fiddler

介紹: Fiddler是最強大最好用的Web調試工具之一,它能記錄所有客戶端和服務器的http和https請求,允許你監視,設置斷點,甚至修改輸入輸出數據,Fiddler無論對開發人員或者測試人員來說,都是非常有用的工具

使用: 1、下載安裝並配置好fillder工具 fildder工具

2、手機和fildder鏈接同一個網絡,然後手機開啟手動代理並安裝證書

a.配置手動代理 配置代理

b.下載證書手機瀏覽器地址輸入代理的主機名和端口(10.0,5.155::8888) 下載證書

c.安裝證書 安裝

上面步驟完成後然後打開H5頁面,如果能在fildder抓到頁面資源表示抓包成功

3、然後線上或則測試環境有問題的相關文件或者頁面代理到本地調試 抓包代理步驟

AutoResponder不僅可以代理文件,還能代理接口返回等,代理成功後就可以在本地文件中debugger斷點一步步調試,找出線上真機出現的問題

四、調試本地Vue項目步驟

1、手机和fildder软件同一个网络

2、手机网络设置手动代理,ip为电脑网络的ipv4地址,端口为fiddler设置的端口默认8080

3、手机浏览器输入代理的地址+端口,安装证书

4、本地项目跑起来,如果是域名访问的,则需要配置hosts

5、手机打开访问的地址就可以debugger调试了
复制代码

 

作者:Liben
链接:https://juejin.cn/post/6907546374422659079
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

micropython ESP32 SOLO-1 firmware binary

E (469) cpu_start: Running on single core chip, but application is built with dual core support.
E (478) cpu_start: Please enable CONFIG_FREERTOS_UNICORE option in menuconfig.
microPython Enable dual core support by default.
Single core is still supported, just by adding CONFIG_FREERTOS_UNICORE=y to
a custom sdkconfig file.

for ESP32 SOLO-1 you may do this.

modify file ports/esp32/boards/sdkconfig.base and add:

# FreeRTOS
CONFIG_FREERTOS_UNICORE=y

it should be ok to run in unicore mode on a dual core.

or Download this binary file.

build-GENERIC.zip

#esptool.py -p {PORT} -b 460800 --before default_reset --after hard_reset --chip esp32 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 build-GENERIC/bootloader/bootloader.bin 0x8000 build-GENERIC/partition_table/partition-table.bin 0x10000 build-GENERIC/micropython.bin

我的第一個STM32程式,使用Arduino IDE 介面

rduino已經用了很長的一段時間,有些與 Arduino 相容開發板的延伸應用,如 NodeMCU、ESP32 等,實作了一些相關的控制。當時覺得 STM32 可能與 Arduino 類似,就沒特別想買一個來練習。這次在看了 STM32 的規格後,覺得比 Arduino 強很多,也可以使用 Arduino IDE 來撰寫 STM32 程式,利用購買一批電子零件的機會,順便買了一片 STM32F103C8T6 開發板,來測試一下這片開發板的功能。

我整理一下 Arduino Uno 的 ATmega328 與 Mega 使用的 ATmega2560 以及 STM32 三個微控制器的比較,可以看到 STM32 的 32bit 處理器及其他規格都比 Arduino Uno 或 Mega 要強很多。一般如果是用在做玩具或啟蒙電子教育功能,Arduino 比較適合,如果是要做成工業或商用產品,那 STM32 會更好。

編號 規格 STM32F103C8 ATMEGA328 ATMEGA2560
1 CPU 32 Bit 8 Bit 8 Bit
2 CPU clock [MHz] 72 16 16
3 Flash [KB] 64 / 128 32 256
4 RAM [KB] 20 2 8
5 ADC Channels 10 8 16
6 ADC Resolution [bits] 12 10 10
7 ADC Sampling Frequency [KHz] 1000 10 / 15.38 max 15
8 PWM Channels 20 6 15
9 SPI 2 2 5
10 I2C 2 1 1
11 USB 1 0 0
這是 STM32 的引腳排列資料:

剛開始使用 STM32 時,我以為連接的方式會跟 Arduino 一樣,直接拉一條 USB 線連接電腦跟STM32,看一下裝置管理員,無法正常安裝驅動程式,Google一下網路上的方法,是要用 TTL轉 USB 來連接電腦,於是拿出先前購買來設定 ESP01 的 CP2102,找了網路的說明,試著上傳第一個 LED 燈閃爍程式,試了幾次錯誤後,終於成功了。以下就記錄一下實際安裝的過程。

[材料]

  • USB轉TTL序列傳輸線 CP2102
  • STM32F103C8T6開發板
  • 排線 x4 條

[接線圖]

CP2102 STM32F103C8T6
GND GND
3V3 3.3V
RX PA9
TX PA10

[安裝STM32程式庫及設定]

要在Arduino IDE撰寫STM32程式,需要安裝STM32程式庫,這個設定方法跟ESP8266很像。開啟Arduino IDE,選擇 [檔案 File] → [偏好設定 Preferences ],在 [額外的開板管理員網址:] 輸入以下網址:

http://dan.drown.org/stm32duino/package_STM32duino_index.json

如下圖:

接著在Arduino IDE畫面選擇 [工具 Tools] → [開發板 Board] → [開發板管理員 Boards manager…],在搜尋的地方輸入「STM32」,如以下畫面:

在STM32F1xx/GD32F1xx Boards選項右下方按 [安裝 Install]進行程式庫安裝。

完成後,回到主畫面設定開發板:選擇 [工具 Tools] → [開發板 Board] → [STM32F1 Board(STM32duino)] → [Generic STM32F103C6 / fake STM32F103C8] 。

接著設定 CP2102 連線埠,可以先看一下裝置管理員的驅動程式是否正常,並取得連線埠資訊,如下圖紅框處:

回到 Arduino IDE 設定:選擇 [工具 Tools] → [Upload method:”Serial”] → [Serial]。

繼續設定連接序列埠:選擇 [工具 Tools] → [序列埠: Port] → [COM6]。這裡的COM6,依每台電腦不同的連線埠而更改。

設定完成後,還有個地方要調整,就是主板上有兩個Jump,其中一個 Boot0 要調整 Jump 設定為DFU模式,從預設的0位置,改到1。如下圖紅框處。而 BOOT Jump 設定具有不同的模式,等之後比較熟悉 STM32 後,再另外解釋其功能。

我要上傳程式時,發現會卡在這個地方時,只要重新按上圖黃色框處的白色 RESRT按鍵,重新起動,即可順利上傳。

上傳程式成功的畫面如下:

[程式]

這個程式會讓LED燈每秒閃爍一次,串列埠視窗會印出”Hello World”。

#define pinLED PC13

void setup() {
  Serial.begin(9600);
  pinMode(pinLED, OUTPUT);
}

void loop() {
  digitalWrite(pinLED, HIGH);
  delay(1000);
  digitalWrite(pinLED, LOW);
  delay(1000);
  Serial.println("Hello World");  
}

[實作結果]

執行的影片如下:

開啟串列埠的視窗:

2021 大前端技術回顧及未來展望

總結2021 年度趨勢

1、 TypeScript 穩健增長

回顧2021,官方的 Roadmap 闡明了TypeScript 的目標是繼續完善其類型系統、實現強大的工具提高生產力、提高使用體驗、提高社區參與程度、改進基礎設施和工程化系統。提出目標後,這一年TypeScript 團隊還是非常給力的發了4 個版本,目前最新版本4.5,其中許多新特性確實使用起來更香了,比如:

  • 更好的元組類型支持,允許任意位置的剩餘類型以及可選類型。
  • 更好的模板字符串字面量類型支持。
  • 更智能的條件分支域的類型推斷。
  • 索引類型支持Symbol 和模板字符串模式。
  • Awaited 類型和Promise 類型改進。
  • 等等。

除了特性,它還完善了許多使用體驗,比如:

  • 性能優化如更快的類型生成、增量編譯和Sourcemap 生成。
  • 更智能的IDE 補全。
  • 非Javascript 源文件定位。
  • 等等。

另外, TypeScript 新官網在8 月上線了,全新的文檔查閱起來也更加方便。

目前TypeScript 已經是IMWeb 團隊的標配。無論是Web 前端、Node.js 項目還是公共模塊,從腳手架模板就默認支持TypeScript,其中公共模塊體係不僅僅使用TypeScript 編寫代碼和類型檢查,同時利用ESLint 實現TS 語言標準AST 的特定校驗來實現公共模塊規範,還結合TypeDoc 生成使用文檔等等。

展望

TypeScript 在未來將提供更多激動人心的特性,例如:

  • 扁平化聲明文件(Flattening declarations),只輸出一份總的d.ts 文件,而不是一個模塊一個d.ts 文件。
  • 環境裝飾器(Ambient decorators),用來聲明一些環境信息,例如API 是否是deprecated。不影響輸出的運行時代碼,只在d.ts 聲明文件中體現。
  • 條件編譯(Conditional compilation),有點類似C++ 中的#if 宏定義,可以在編譯前預處理代碼並保留符合條件的代碼分支。
  • 函數表達式以及箭頭函數的裝飾器(Decorators for function expressions/arrow functions),目前TypeScript 中裝飾器只能用於class 中,未來將可能支持類外的函數表達式以及箭頭函數使用裝飾器。
  • 等等。

正如其Roadmap 所說,TypeScript 正在朝正確的方向前進,提高生產力還有很多的類型特性、性能優化、體驗優化、配套工具可以做,正努力成為JS 語言的標準類型系統。隨著TypeScript 的日益發展和完善,未來,TypeScript 是否能得到瀏覽器和Node.js 原生支持呢?我們一起期待吧。

2、React 一馬當先且持續創新

React 18 在2021 年下半年完成了Alpha、Beta 和Release Candidate 版本的發布,將於2022 年初發布正式版本。

當React 18 發佈時,它將包含開箱即用的改進(如Automatic batching),全新的API(如startTransition)以及內置支持了React.lazy 的全新SSR 架構。

這些功能之所以能夠實現,要歸功於在React 18 中新加入的可選的“並發渲染(concurrent rendering)” 機制,它為React 解鎖了非常多新的可能性,來幫助你提高你應用程序的實際與感知性能。

React 18 採用循序漸進的策略,由於React 18 中的並發性是可選功能,所以並不會立刻對組件行為帶來任何明顯的破壞性變化。你幾乎不需要對應用程序中的代碼進行任何改動就可以直接升級到React 18,且可以根據自己的節奏和需要來嘗試新特性。

總的來說,React 18 帶來了以下3 個方面的更新:

➢ Automatic batching

➢ SSR for Suspense

➢ New APIs for app and library developers

● Automatic batching

React 18 通過默認執行更多batching (批處理) 來增加開箱即用的性能改進,無需在應用程序或庫代碼中手動批處理更新。

batching 是指,React 可以將回調函數中多個setState 事件合併為一次渲染。

React 17 只在事件回調中batching,React 18 則會對任何來源的setState 做盡可能多的batching, 即使在promise、timeout 或者event 回調中調用多次setState,也都會合併為一次渲染。

將ReactDOM.render 替換為ReactDOM.createRoot 調用方式,即可開啟這些新特性。

● SSR for Suspense

完整名稱是:Streaming SSR with selective hydration。

即像水流一樣,打造一個從服務端到客戶端持續不斷的渲染管線,而不是renderToString 那樣一次性渲染機制。selective hydration 表示選擇性水合,水合指的是後端內容打到前端后,JS 需要將事件綁定其上,才能響應用戶交互或者DOM 更新行為,而在React 18 之前,這個操作必須是整體性的,而水合過程可能比較慢,會引起全局的卡頓,所以選擇性水合可以按需優先進行水合。

● New APIs for app and library developers

Concurrent APIs:

Concurrent Rendering 相關的變動是React 18 的主要變動之一,簡而言之,這個能力會讓React 應用保持更好的響應性。這是一種可中斷渲染的設計架構。什麼時候中斷渲染呢?當一個更高優先級渲染到來時,通過放棄當前的渲染,立即執行更高優先級的渲染,換來視覺上更快的響應速度。

  • useTransition:允許組件在切換到下一個界面之前等待內容加載,從而避免不必要的加載狀態。
  • startTransition:被startTransition 回調包裹的setState 觸發的渲染被標記為不緊急的渲染,這些渲染可能被其他緊急渲染所搶占。
  • useDeferredValue:返回一個延遲響應的值,例如一個選擇輸入框過濾列表的場景,我們可以針對列表使用useDeferredValue 傳入選擇器對應的值。

新的startTransition 與useDeferredValue API,本質上都是允許你將UI 的一部分標記為較低的更新優先級。

其他APIs:

  • useSyncExternalStore:useSyncExternalStore 將替代useMutableSource 用於訂閱外部源,解決Concurrent Rendering 可能導致的數據不一致的問題,也是庫作者可能需要,一般開發者不太能用到。
  • useId:useId 用於在客戶端與服務端之間產生唯一ID ,避免SSR hydrate 時元素不匹配。
  • useInsertionEffect:用於插入全局DOM 節點。

React 18 將在明年與新的React Native 架構(可用React 18 特性)一起發布。

3、Svelte 前端框架戰局中的黑馬

前端領域風起雲湧,框架層出不窮,前端三大馬車React、Vue、Angular 始終穩居前三甲。同時我們也注意到在眾多前端框架中,由Rich Harris (Ractive, Rollup 和Bubble 的作者) 開發的Svelte 有望成為一批黑馬,在前端框架中脫穎而出。

在《 Stack Overflow 於2021 年準備的最新調查》中,71.47% 的受訪者將Svelte 選為最受歡迎的框架,領先於React.js 的69.28% 和Vue 的64.41%。而在 JS 現狀2020 調查 中,Svelte 在用戶滿意度89%、興趣度66% 均取得了第一的成績表現。Svelte 從一誕生,就用來對標React/Vue 等框架,我們也看到了關於 Svelte 與React 的爭論,看到了19 年尤大回复的《如何看待Svelte 這個前端框架》以及21 年 vue-Svelte-size-analysis 評測,足見Svelte 的發展態勢。

 

前端戰局中的黑馬

我們調查發現,開發者喜愛Svelte,主要源於以下幾點:

1、更高的開發效率。Svelte 有著極其簡潔的語法,交互式教程讓其有較低的學習曲線和上手成本,熟悉vue 語法的基本上很快能夠上手。

2、更小的體積。Svelte 的核心思想在於通過靜態編譯減少框架運行時的代碼量,這在小型應用中,優勢相當明顯,React 的壓縮版本大小為42.2KB,Svelte 的壓縮版本大小為1.6KB。但是在中大型應用中,這個優勢會被慢慢縮小,甚至成為劣勢。

3、更高的性能。Svelte 沒有採用現在普遍使用的Virtual Dom,而是另闢蹊徑採用Template 語法,讓編譯器在編譯階段就記錄了哪些數據需要更新。這讓Svelte 性能不僅勝過React,還勝過Angular 和Vue。

4、更優的Web Components 分發。Svelte 直接編譯成JS,生成瀏覽器能夠識別的Web Components 組件,這讓基於Svelte 開發的組件能夠用於其它框架,譬如React/Vue/Angular 等。

時光飛逝,Svelte 的發展速度可能也超乎我們的想像。被詬病不支持TypeScript 的前端框架沒有未來的Svelte 在2021 年也支持了TypeScript,UI 庫Svelte Material UI 也在逐步迭代中,開發者社區也加入了越來越多的小伙伴,豐富了Svelte 在單元測試、Web Components、SSR 等方面的實踐。

回顧2021 年,Svelte 最重要的莫過於下面兩件事:

1、2021 年11 月20 日舉辦了秋季峰會。峰會Rich Harris 給我們講述了Svelte 的歷史,並宣布他將入職Vercel,之後全職維護Svelte。峰會上也邀請到了社區眾多的開發者,分享Svelte 的一些實踐,讓我們看到Svelte 更多的可能性。

2、SvelteKit 正式發布beta 版。SvelteKit 是基於Svelte 開發的web 應用框架,類似於基於Vue.js 開發的Nuxt.js 框架。它繼承了服務端渲染SSR,路由,支持TypeScript,支持less/sass,支持Vite 打包等特性。既能高效開發,又高性能。儘管目前SvelteKit 目前還有些bug 仍需要解決,部分缺失的功能亟待完善。但仍不妨礙項目敢在生產環境去使用它。

靜待花開的攪局者

雖然我們看到Svelte 深受開發者的喜歡,但是到目前為止,仍然很難看到有大型應用在使用Svelte,其性能優勢、體積優勢等並沒有在大型應用中得到驗證。由於React/Vue/Angular 先入為主,尤其是在大公司,已經有非常完備成體系的配套方案,成熟的體系基本上很難去改動,後起之秀也很難有如React 等框架活躍的社區,Svelte 要走的路還是很長。但是我們觀察到,包括阿里、字節、騰訊等大公司也都在新業務中嘗試使用Svelte 開發,在中小型應用、h5 應用、Web Components 等方面確實有它的優勢所在,也值得嘗試。儘管Svelte 有很多優勢,但想以一己之力挑戰React/Vue/Angular 的江湖地位,目前來看還是需要靜待標杆大型應用,靜待各大大公司推出基於Svelte 開發的UI 庫,或許Svelte 大放異彩的時機就會到來。

4、桌面端- 前端開發的下一個戰場

持續擴大桌面應用領域影響

自2014 年Github 推出Electron 開源框架開始,前端跳出Web 客戶端局限,開發桌面應用的能力成為了可能,近年來,依托Electron、React Native、Flutter 等應用框架,前端跨端開發桌面應用的概念持續升溫。儘管這些方案和傳統的QT、Xaramrin 等技術棧相比,性能未必最優,但它意味著一些極具性價比的可選方案出現,大大降低了開發桌面應用的門檻。

2021 年,前端Electron、React Native Desktop 等應用框架的更新迭代都趨於穩定,雖然沒有了一些突破性的亮點功能出現,但各個框架都針對性能、應用場景等痛點問題在持續進行深入的優化,而近年概念火熱的Flutter 也將它的桌面版在21 年納入了Beta 階段,異軍突起的Tauri 以其優異的性能和包大小受到了關注,潛力不容小覷。總體而言,在桌面應用開發領域,前端技術的影響力在與日俱增,前端可以參與的內容比重也在不斷增加。

Electron

Electron 是GitHub 開發的一個開源框架。它通過使用Node.js(作為後端)和Chromium 的渲染引擎(作為前端)完成跨平台的桌面GUI 應用程序的開發。已有大量知名桌面應用採用Electron 進行開發,如slack、VSCode 等。Electron 的所需開發能力與前端開發能力技術棧有著較大的重合,因此對於前端開發同學來說,使用Electron 進行桌面開發的上手門檻較低,同時Electron 作為一個深耕迭代8 年的項目,應用生態鏈豐富,進一步減少了上手成本。

使用Electron 進行桌面應用開發,對於前端自身能力提升也有賦能,一方面擴展了技術廣度,可以將前端的業務能力範疇由單一的Web 端頁面擴展到PC 應用開發,一些目前Electron 暫時不支持的能力,還可通過C++ 編寫Node 組件來擴展支持;另一方面很多前端側的限制被打破,比如一些傳統的Web 安全限制,系統底層接口的調用,能夠做到開發能力賦能。

當然,Electron 也並不是全無缺陷的,一些常受詬病的缺點有:

  • 打包體積過大,由於捆綁了Chromium 內核等大量依賴,導致Electron 的打包體積普遍在100M+,這一點我們可以使用asar 壓縮、動態鏈接庫等方式進行優化。
  • 內存佔用高,同樣的由於捆綁了Chromium 內核,Electron 的內存佔用普遍也較高。
  • UI 層視覺渲染效率低,這一點也可以通過優化手段,如多進程處理任務、甚至利用視覺假象來提升用戶體驗。

雖然Electron 有著一些已知的問題,但完善的生態鏈、與前端技術的高度重合,目前仍然是快速開發桌面應用的推薦方案,對於性能問題我們也較容易通過一些常見的優化手段來進行解決,達到80 分的程度。2021 年,Electron 依然保持著8 週一個major 版本的穩定更新頻率,推出了V12 到V15 的多個大版本,更新的內容主要集中在API 的刪改、系統特性的適配、Chromium 內核等依賴的版本更新等細節方面。

React Native Desktop

React Native 是Facebook 技術團隊於2015 年4 月在早先的React 前端框架基礎上開源的一套移動跨平台開發框架。對於桌面應用的構建,目前RN 團隊暫時沒有推出官方的桌面端版本,主要依托社區項目進行持續發展的能力建設。在這之中,微軟開發的React Native For Windows + macOS 技術方案是經驗積累最多,也是開發迭代最為穩定的方案,自15 年底項目發布以來,已經經過了6 年的穩定迭代。2021 年RN 團隊推出了0.64-0.66 三個重要版本,而微軟在React Native For Windows 的迭代中,也時刻保證對RN 主版本的更新,同時也支持了大量Windows 相關的特性。如果你構建的桌面應用主要目標用戶在Windows 平台,那麼使用React Native For Windows 不失為一個好的選擇。

值得一提的是,2021 年RN 技術團隊除了在推出的重要版本中提供對新的Android 12 與iOS 15 系統的支持外,也著重提到了與微軟團隊在桌面應用構建技術上的共建,RN 團隊表示,將通過引入Facebook 的Messenger 團隊共建,來為桌面應用提供一些「獨有的」技術能力,以此提升React Native 桌面版的用戶體驗,對此,我們也將拭目以待。

Flutter Desktop

Flutter 是由谷歌推出的移動UI 混合開發框架,它實現了一整套自底而上的基礎庫,用戶可以在iOS 和Android 構建高質量的原生用戶界面。

目前Flutter 為了支持在桌面側的開發能力,採用的是把代碼轉成Web 的跨端渲染方案。但Flutter to Web 性能還存在著大量提升的空間,雖然這一年內業內有不少優化方案,但想要性能有明顯提升,多少都會通過魔改Flutter 源碼的方式來實現,這些優化手段在長期的Flutter 版本迭代過程中,會有較大的優化成本。即使這樣,優化過後的Flutter to Web 性能,和傳統的Web 項目相比,也略有不足。所以在不考慮兼容性的前提下,採用to Web 方案的開發盡量使用Canvaskit Render 模式,該模式是基於Skia 的WebAssembly 方案,會有更好的渲染性能,但加載性能方面還需持續優化。

可能是為了徹底解決桌面端的性能問題,2021 年中,Flutter Desktop 側推出了Windows Native 方案,但它目前僅支持64 位系統,這使得它無法支持Win7 等較低32 位系統的Windows 版本,會大大增加了開發者的兼容成本。不過2022 年2 月,Flutter Desktop 正式推出了穩定版,適配了許多常用插件以包含對Windows 的支持,包括camera,file_picker 和shared_preferences。更重要的是,社區已經添加了各種其他package 對Windows 的支持,涵蓋了從Windows 任務欄集成到串行端口訪問的全部內容。同時許多Microsoft 的團隊也積極配合,為正式版的發布做出了很大貢獻。2022 年,Flutter Desktop 值得嘗試一下。

Tauri

最近搭上Rust 的東風的Tauri 受到非常多的關注,對標Electron,主要有以下4 點優勢:

  • 包體積大小更小
  • 運行時內存佔用更小
  • 安全擺在第一位
  • 真正的開源

但是理性思考,對於前端開發來說,有三個致命的缺點:

  • Tauri 使用系統webview,會有兼容性問題,這也是Electron 重點解決的問題
  • 拋棄了nodejs,生態圈目前來說還是很難比得上Electron 的
  • 底層開發要用Rust,有一定的上手成本

當然Tauri 現在還不是非常成熟,但是隨著Rust 的生態起來,瀏覽器兼容性漸小之後,勝負猶未可知。

5、Rust – 是時候掌握一門新語言了

Rust 是JS 基礎設施的未來

隨著前端生態工具的逐漸完善,大家除了探索前端的新領域之外,同時還在思考如何提高工具的性能,眾所周知,JavaScript 的性能一直是被大家所詬病的點,但是前端的基礎設施卻是十分要求性能的,比如構建等,所以大家開始考慮是否能夠用別的語言來編寫前端工具,於是Rust 吸引了大家的眼球,Rust 語言自誕生以來,就以它的安全性、性能、現代化的語法吸引了大批的開發者,在過去六年的stackoverflow 最受喜愛的編程和語言中連續獲得榜首的位置,並且已經有眾多領域都出現了Rust 重寫的項目,Linux 項目也表示正在使用Rust 重寫一部分功能,可以說Rust 進入前端領域也是一種必然的趨勢。Lee Robinson 在2021 年寫的一篇文章《Rust Is The Future of JavaScript Infrastucture》(《Rust 是JS 基礎設施的未來》)列舉了眾多Rust 編寫的前端工具項目,並表示Rust 將會持續加大影響Javascript 的生態圈,這篇文章也是被眾多公眾號轉了個遍,引發大家的熱烈討論。

Rust 工具融入前端生態

在前端構建領域,2021 年出現了一個十分突出的項目—— swc,它是由Rust 編寫的構建工具,可以用來編譯、壓縮、打包,目前它已經被一些知名項目使用,比如Next.js、Parcel、Deno 等,Next.js 12 直接使用了swc 替代babel,並在他們的官網博客表示說使用了swc 之後,熱更新速度提升到了原來的三倍,構建速度提升到了5 倍,由此可見,Rust 性能的強大。

除了構建方面,在前端的其他領域也是有著Rust 的身影,比如Deno 的運行時引擎也是用的Rust 編寫的V8 引擎;前端的下一代工俱全家桶Rome 宣布使用Rust 重寫;Node.js 可以通過napi-rs 來調用Rust 模塊,實現高性能擴展;使用Rust 編寫的dprint 規范代碼器,要比Prettier 快30 倍;Rust 也可以編譯成WASM,並且出現了像yew、percy 這樣的WASM 前端框架。

可以預見的是,Rust 工具將會更加深度地融入前端生態,說不定會引發前端生態的又一次更新換代。

前端人是時候學習一門新語言

相信有不少人看到過這樣一個推特截圖,Redux 作者Dan Abramov 在某個提問“未來三年最值得學習的語言是什麼” 下回答了“Rust”,這或許是對前端人員的一個啟發,我們也是時候學習一門新語言來讓前端生態圈再次煥發活力了,可是不少人會被Rust 陡峭的學習路線給勸退,但其實Rust 在不少地方是跟前端開發有著相似的地方的,要想入門的話也並不是那麼陡峭。

圖片

比如,在工具鏈上,Rust 的rustup 就相當於nvm,可以切換運行工具cargo(Rust 版的npm)的版本,但它也比nvm 強大,在安裝rustup 的同時,還會安裝clippy(Rust 版的eslint)、rustfmt(Rust 版的prettier),用Rust 配套工具新建的項目就已經帶有代碼格式化、分析配套的工具。

再來看看cargo 與npm 的相似之處,兩個工具在很多命令上都有著相似的地方,並且npm 一些需要自己在項目配置的命令在cargo 這是不需要配置的,甚至cargo 是自帶了monorepo 的管理,可以直接配置多package 的項目,與其說cargo 跟npm 對應,倒不如說cargo 更像是npm 與yarn 的結合,這也是Rust 團隊借鑒參考現代化語言工具鏈的成果。

圖片

在語法上Rust 也是極具現代化語言的特點,借鑒了函數式編程、結構化語言的特點,並且在它們的基礎上也創造了許多更為先進的語法。在函數式編程的地方,也有著不少JavaScript 的身影,比如JS 的箭頭函數對應了Rust 的閉合函數;Rust 的數組同樣也有著map、reduce、filter 等方法;Rust 的函數也可以賦值給一個變量。

如果在以前說前端可以去學習的第二語言是C++,那麼現在或許就是Rust 了,它有著比C++ 更現代化的依賴管理、語法、工具鏈,讓你不至於在一開始就被勸退,還能讓你在前端領域更具競爭力。

6、低代碼將持續成為熱點話題

距我們在2020 技術趨勢中談及“低代碼” 又過去了一年,從2020 年19 億到2021 年28.5 億的市場規模,無疑表明該領域依舊火熱,依舊在快速發展中。如果說2020 年讓我們收穫了對低代碼領域持續升溫的預期,那麼2021 年則讓我們看到了更多關於低代碼領域未來發展的趨勢。

一方面,我們看到騰訊微搭、阿里宜搭等企業級低代碼平台在行業內開始發力,公司內也有無極等專注管理台搭建的平台逐步成熟。大量平台型產品仍在差異化高速發展,仍是主流的發展思路。在IMWeb 團隊內,從19 年開始的運營低碼平台Vision,到20 年的管理台低碼框架Hulk,我們一直在通過垂直類低碼平台加速業務研發。2021 年,我們進一步在服務端場景進行了嘗試,打磨出了專注接口搭建的HulkData 平台。

HulkData 通過Web 可視化組件搭建流水線,基於數據庫或已有API,配合少量代碼生成全新的API 接口。HulkData 借鑒BPMN 2.0 協議使用圖形來表達業務流程,支持多業務,多數據資源,低代碼、插件機制、流程編排、請求和響應參數修改。Serverless 日漸成熟,Serverless 的無運維特性對HulkData 而言是一個非常良好的契機,在HulkData 上創建的接口會以SCF 的方式部署到騰訊雲,不需要再關注服務器運維。使用HulkData 服務端接口編排可快速實現業務邏輯,敏捷接付業務應用,比傳統開發模式交付速度提升80%。目前內部三大業務接入使用共400+ 接口在正常運行。

另一方面,值得思考的是,在高速發展的差異化、場景化的平台產品之間,是否存在某些共性?畢竟不管針對什麼場景,從零建設一個低碼平台的成本絕不低,此類的資源浪費在大廠裡尤為突出。

20 年底IMWeb 團隊內啟動的Gems 低代碼引擎項目,其實就是對這個問題的探索。低代碼引擎的核心目標,是提供一套基礎標準、設施,幫助上層平台更有效地建設。而其思路的關鍵,在於引擎模型及能力的完備性、以及針對不同場景下的可擴展性。Gems 作為低代碼引擎,在21 年裡不斷完善自身的基礎能力與設計,提供了全面板插件化、核心編輯對象API 等能力。除了平穩支撐團隊內的運營與管理台低碼平台,也逐步邁出到團隊之外,幫助到公司內多個團隊在自身業務場景低碼平台的高效建設。有關Gems 的更多內容可以關注我們團隊在 QCon 的相關分享。

同時,我們也看到在今年底的GMTC 大會上,阿里已經對外宣傳了集團的低代碼引擎,從分享內容看已經支撐了60 多個低代碼平台的建設;而騰訊內部的低代碼Oteam 也在21 年開始組織起來,主要的目標也是底層核心的共建。從整個行業看,低代碼引擎已經開始嶄露頭角,且可預見到趨勢還將上升。只是這個細分賽道更多可能只是大廠參與,因為其需要大量的場景支撐驗證,而這是小廠或獨立開發者不具備的。

總觀下來,差異化的平台產品仍將是我們接觸低代碼領域的主要途徑;而低代碼引擎的出現,將為整個行業帶來更多的可能。

7、D2C 前端智能化未來可期

“前端智能化” 是近些年業界在前端+ AI 方向上的新的探索。何謂智能化?就是將智能化算法結合前端工程化實踐,讓機器進行輔助開發。

D2C:歷史與現狀

截止目前,前端智能化領域最大規模落地的產品形態就是各種Design to Code (下文簡稱D2C) 工具:輸入UI 設計稿,通過一系列算法,輸出可用的代碼。

2017 年一篇論文 pix2Code,提出了圖像生成代碼的想法。

2018 年,微軟開源了 Sketch2Code 項目,進一步驗證了該方向的可行性。

緊接著2019 年,阿里淘系上線 imgcook,並在接下來的幾年裡支撐了雙十一、618 等大量業務。這標誌著D2C 技術逐漸成熟,大規模業務落地勢在必行。

時間來到2021,國內外各大公司都在此領域展開了相應的探索和實踐:

騰訊IMWeb 團隊啟動了Project Auton,已經在內部上線試水,預計今年6 月對外提供服務;阿里的imgcook 依舊在持續進行快速迭代;字節內部基於低代碼平台,孵化出了“ALYX” 項目,也在內部展開了實踐;58 團隊開源了 Picasso ; 轉轉上線了” 神筆馬良” 平台…

另外,D2C 領域也湧現出一批創業公司。如國內的 CodeFun  、藍湖,國外的 Framer  、Anima 等。

值得一提的是CodeFun,在易用性、還原度方面有相對較好的表現,上線後獲得了不錯的口碑。

但在整個前端開源社區,目前D2C 領域還沒有一個足夠有影響力的開源項目。因此各家也基本都處於“閉門造車” 的狀態。

硬幣的兩面:缺陷、場景與機會

相對於早期基於純視覺算法的方案,目前大規模落地的D2C 產品基本都是以設計稿源文件(Sketch、Figma、XD 等) 作為原始輸入。

由於純視覺算法很難從二維圖像上提取UI 的層級等信息,而設計稿文件則可以通過解析內部DSL 獲取更詳細的結構化UI 描述,更方便進行後續的處理與代碼生成。

傳統的pro-code 開發模式下,通常都是“PRD + 設計稿” 作為輸入,產出業務代碼。但D2C 系統把設計稿作為唯一輸入,設計稿只是單純的UI 描述,導致很多信息無法從設計中推斷出。如動畫、交互、邏輯甚至是響應式等都無法單獨依靠D2C 實現。

由於這些缺陷,D2C 的場景大多也只是作為面向開發的輔助工具。距離真正的完全智能化(無需人工干預即可產出邏輯完備且生產環境可用的代碼)還為時尚早。

雖然存在上述諸多缺陷,但在UI 開發這一領域,D2C 大有可為。

D2C 的產物(組件/ 頁面代碼或描述UI 的DSL) 通常有如下幾種消費路徑:

  1. 產出代碼,作為基礎UI 組件,由開發者進行二次開發
  2. 產出代碼,作為基礎物料供給,結合low-code/no-code 平台進行二次編輯和編排
  3. 產出DSL,結合定制化的render 進行直接渲染

尤其是第二種消費路徑,借助近些年大熱的low-code 平台,對D2C 產出的UI 物料進行數據綁定、邏輯編排、樣式編輯、交互編排等人工干預和二次編輯,可以補全D2C 的能力短板,並且建立出一套快速、高效、可沉澱、可複用的代碼生產SOP。

另外, D2C 以其高效的供給效率,可以突破low-code/no-code 的物料生產瓶頸,為前端的研發範式從pro-code 走向low-code 的變革加上了助推劑。

借助D2C + low-code/no-code,再結合近年來大熱的SaaS、FaaS、BaaS 等技術產品形態,可預見地在不遠的未來,真的可以實現不需要工程師就可以零代碼快速上線一個數據、交互、邏輯完備的產品。這極大地降低了很多創新型業務的初期成本,甚至可能助推下一波互聯網創業浪潮,讓我們拭目以待。

不過目前為止,還沒有出現哪一個平台能把上述幾種產品形態(D2C + low-code/no-code + SaaS/FaaS/BaaS) 完美地整合起來形成閉環,同時保持優秀的用戶體驗。未來幾年,這個領域或許會催生出一些明星創業公司。

展望未來:深耕、整合、研發範式變革

展望2022 年,可以預見前端業界智能化及D2C 還將進行持續地發展,整體為如下兩大趨勢:

  1. 縱向上:持續深耕,優化流程、算法和體驗,讓“智能化” 真正的越來越“智能”
  2. 橫向上:建立標準和流程,打通整合上下游能力,串聯low-code、no-code、FaaS、BaaS、SaaS、設計體系、算法體系、研發體系、數據體係等… 真正形成工業化的快速生成體系,解放生產力。

從長遠來看,一旦上述體系建立起來,必將驅動業界開始下一次的研發模式變革。從目前的pro-code 為主的研發模式,變革為pro-code、low-code、no-code 三種模式相輔相成、互相供給和賦能的模式。同時由於標準化體系的建立,物料和產物都可以更容易實現通用和復用。這對於研發效能的提示無疑是巨大的!

這一些都充滿想像,即使智能化的路程中充滿質疑與險阻,但未來是值得期待的。新的一年還將繼續深耕和發展,2022 未來可期……

8、DevOps,研發效能仍是重點

研發效能是目前互聯網企業和傳統軟件企業都高度關注的領域,互聯網大廠希望通過“研發效能” 實現持續的研發能力提升以應對日趨複雜的產品開發;腰部廠商則希望通過“研發效能” 實現彎道超車,充分發揮後來者居上的優勢;更多中小企業看到國內互聯網大廠不約而同地在這個領域重點投入,紛紛也是摩拳擦掌準備在效能領域發力。

和敏捷的概念類似,到底什麼是研發效能很難精確定義。其實很多複雜概念也不是定義出來的,而是逐步演化出來的,是先有現象再找到合適的表述。其實,效率和效能也從來都不是軟件工程的專有名詞,縱觀人類發展史,就是生產力和生產效率不斷提升的發展篇章,到了數字化時代,軟件研發效能的重要性被凸顯了出來。如果要用一句話來總結研發效能的話,我們會用“更高效、更高質量、更可靠、可持續地交付更優的業務價值” 來總結。

圖片

我們能做的不是提升研發效能的絕對值,而是盡可能減緩研發效能惡化的程度,使其下降的不至於太快,努力保持現狀就是成功。

圖片

IMWeb 團隊在DevOps 方面,2021 年有較大的進展。一方面,我們與騰訊雲Coding 在開發、測試、部署、運維等多個領域進行了共建,團隊自研的效能平台Thanos 與Coding 團隊深度打造應用工作流方案,代理聯調平台TDE 與Coding 團隊打通測試環境Nohost 網關,接口聯調契約平台Tolstoy 與Coding 共建API 託管、Mock 和測試的能力。在研效大背景下,我們通過騰訊雲Coding 實現了效能平台的大統一,整體研發效能提升30% 以上。

9、微前端,不可輕視的一環

2016 年ThoughtWorks 提出了微前端思想:將龐大的項目拆分成各個小型靈活項目,這些小項目互不干擾,可以獨立開發、獨立運行以及獨立部署,由此拉開微前端帷幕。在2019 年阿里在single-spa 基礎上開發了qiankun 微前端框架後,微前端的熱度一直在增加。在微前端的發展過程中,開發者們也慢慢摸索出當下微前端的應用場景:

圖片

時間來到2021 年,微前端的框架已經非常多了,其中名聲比較響亮的有老牌的single-spa,Github Star 數最高的微前端框架qiankun,以及新興微前端框架京東的MicroApp。

圖片

single-spa 自2020 年發布了v5.0 後,在去年上半年主要工作還是圍繞v5.0 一些Bug 的修復,而在下半年7 月份發布了v6.0 的beta 版本。雖然v6.0 也有一些Breaking Changes,但是對於這些Changes,大多數用戶是不需要更新自己代碼的。其中比較重要的是在瀏覽器方面,v6.0 將是最後一個支持IE11 的版本,且在以後的版本v7.0 + 將不再支持IE11,single-spa 團隊將會把更多精力從瀏覽器兼容轉到維護整個single-spa 生態上。v6.0 還加入兩個新特性:

  • 支持異步取消頁面導航
  • 暴露patchHistoryApi,開發者可以使用single-spa 封裝後的pushState/replaceState/popstate/hashchange。

不僅老牌框架在發力,號稱“可能是你見過最完善的微前端解決方案” qiankun 也在不斷更新。qiankun 主要還是解決不同應用場景的一些問題,以及修復沙箱中一些JavaScript 的兼容問題,比如沙箱中的defineProperty 問題,以及沙箱性能問題等。雖然qiankun 在去年看起來沒太多更新,但是它也給出了令人激動的V3.0 RoadMap,裡面說到了非常多更新,主要更新有:獨立應用加載模塊以及獨立沙箱模塊。

不過,qiankun 依然沒有解決侵入性強的問題,並不能像類似iframe 一樣很方便地嵌入頁面。

下半年一個好消息是,京東也推出了自己微前端的解決方案MicroApp。它並沒有採用single-spa 和qiankun 的組件化思路,而是藉鑑了WebComponent 的思想,通過CustomElement 結合自定義的ShadowDom,將微前端封裝成一個類WebComponent 組件,從而實現微前端的組件化渲染。它有以下特性:

  • 類WebComponent + HTML Entry
  • 生命週期
  • 資源地址補全
  • JS 沙箱、樣式隔離、元素隔離
  • 數據通信
  • 預加載
  • 插件系統

MicroApp 在使用性和侵入性都做得非常完美,這個框架的發展和未來是非常值得期待的。

總的來說,微前端的基礎來自於 “所有大型系統都逃不過熵增定律”,它能解決的問題也是解構一些巨石應用,所以微前端更多時候是“悲觀主義工程師” 在工程上的妥協。