0%

iterm2在最近一段时间一度变得非常卡,尤其是在一个tab下的多个窗口间互相切换操作时,卡顿时间在3-5秒钟,让我非常难受。

然后在刷微博时看到了Hyper,决定下载下来试试。Hyper打开试用10秒后,我觉得放弃iterm2,开始使用Hyper,Hyper在窗口切换和命令输入时让我感受到了久违的流畅感。

这里就简单介绍下Hyper。

Hyper

Hyper是基于Electron的一个Terminal。

Hyper官网可下载对应系统的安装包。安装完成后会自动继承ZSH的配置(包括插件和主题)。

Hyper的配置文件是一个叫.hyper.js的文件,可以配置一些基础信息。这些都可以直接在官网查看。

Hyper还支持自己的插件和主题。

由于我安装Hyper后自动继承了ZSH的配置,所以我基本上可以无缝切换使用,这里只介绍一个Hyper插件,它支持系统全局唤起Hyper的快捷键。

hyperterm-summon

hyperterm-summon支持你通过系统全局快捷键唤起Hyper窗口。

安装:

打开Hyper配置文件,添加hyperterm-summonplugins数组中完成安装。

配置:

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
config: {
summon: {
hideDock: false, // 默认false,设为true会影藏dock的Hyper图标
hideOnBlur: false, // 默认false,设为true会在窗口失去焦点时影藏Hyper
hotkey: 'command + I'
}
},
plugins: [
'hyperterm-summon'
]
}

在当下搭建前端工程时一定避不开babel,对于babel最常用的两个库@babel/polyfill@babel/plugin-transform-runtime,需要搞清楚他们的作用和区别。

@babel/polyfill

@babel/polyfill主要提供需要修改内置api(实例方法)才能达成的功能,譬如:扩展Object.prototype,给上面加上assign方法,就属于修改内置API的范畴。

Babel 7.4.0后,这个包被弃用并被两个子包替代:core-js/stable(提供polyfill)和regenerator-runtime/runtime(提供generatorasync方法,可以用runtime实现)。这里就要说到babel 7后的另一个库:@babel/preset-env

@babel/preset-env

@babel/preset-env根据指定的执行环境提供配置polyfill。之前的stage-X库都已废弃。

@babel/preset-env主要是依赖browserslist来设置target进而判断运行环境,然后根据useBuiltIns的配置来决定如何引入polyfill。

useBuiltIns属性主要有三个值:"usage" | "entry" | false,默认是false。这里建议安装core-js替代@babel/polyfill

1
2
3
4
5
npm install core-js@3 --save

# or

npm install core-js@2 --save

useBuiltIns: false

不自动引入polyfills,也不会转换import "core-js"import "@babel/polyfill"引用为单独的polyfill。

useBuiltIns: 'entry'

处理在项目入口的引入,注意你的整个应用(bundle)只能使用一次import "core-jsimport "regenerator-runtime/runtime"。如果多次引入会报错。推荐创建一个只包含import声明的单入口文件。

in

1
import "core-js";

out(基于不同的环境)

1
2
import "core-js/modules/es.string.pad-start";
import "core-js/modules/es.string.pad-end";

in

1
2
import "core-js/es/array";
import "core-js/proposals/math-extensions";

out(基于不同的环境)

1
2
3
4
5
6
7
8
9
import "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopables.flat-map";
import "core-js/modules/esnext.math.clamp";
import "core-js/modules/esnext.math.deg-per-rad";
import "core-js/modules/esnext.math.degrees";
import "core-js/modules/esnext.math.fscale";
import "core-js/modules/esnext.math.rad-per-deg";
import "core-js/modules/esnext.math.radians";
import "core-js/modules/esnext.math.scale";

useBuiltIns: 'usage'

在文件需要的位置单独按需引入,可以保证在每个bundler中只引入一份。

in

a.js

1
var a = new Promise();

b.js

1
var b = new Map();

out(如果环境不支持上述语法)

1
2
import "core-js/modules/es.promise";
var a = new Promise();
1
2
import "core-js/modules/es.map";
var b = new Map();

out(如果环境支持上述语法)

1
var a = new Promise();
1
var b = new Map();

tips

理论上useBuiltIns: 'entry'这种由入口文件一股脑把所有pollfill全部引入的方式是不推荐的,而useBuiltIns: 'usage'这种按需引入应该是最优的处理方式,但是要注意一点就是useBuiltIns: 'usage'不会处理第三方依赖包的引入模块,所以如果第三方依赖包使用了高级语法而未处理兼容性的话,可能会出bug。

corejs

22{ version: 2 | 3, proposals: boolean },默认是2

这个配置项只有当useBuiltIns: usageuseBuiltIns: entry时才有效,指定@babel/preset-env引入的core-js版本。

当使用useBuiltIns: entry时,你可以直接引入指定的polyfill比如import "core-js/proposals/string-replace-all"

当使用useBuiltIns: usage时,有两种选择:

1、将shippedProposals设置为’true`

2、使用corejs: { version: 3, proposals: true }

@babel/plugin-transform-runtime

@babel/plugin-transform-runtime主要提供全局内置对象比如PromiseSetMap,并将全局内置对象抽取成单独的模块,通过模块导入的方式引入,避免了对全局作用域的修改(污染)。

有人会奇怪babel里为什么会有@babel/plugin-transform-runtime@babel/runtime?刚开始是只有@babel/runtime插件,但是@babel/runtime有个问题,在代码中直接引入helper函数,意味着不能共享,造成最终打包出来的文件里有很多重复的helper代码。所以,Babel又开发了@babel/plugin-transform-runtime,这个模块会将我们的代码重写,如将Promise重写成_Promise(举例),然后引入_Promise helper函数。这样就避免了重复打包代码和手动引入模块的痛苦。

总结

当前babel版本最优的使用方式应该是@babel/preset-env搭配@babel/plugin-transform-runtime,能够很好的处理高级语法的兼容性问题。

coding时遇到一个场景需要后端接口返回正则表达式,且正则表达式是以字符串的形式放到一个JSON数据中去的。我们在联调过程中就会发现前端通过JSON.parse转义后的对象,正则表达式里的反斜杠“\”会有丢失。

chrome控制台测试结果如图:

demo1

我们可以看到,JSON.parse在处理反斜杠的字符串时,会丢失反斜杠或直接报错。报错信息:

1
2
3
VM3086:1 Uncaught SyntaxError: Unexpected token a in JSON at position 7
at JSON.parse (<anonymous>)
at <anonymous>:1:6

在不了解原因的情况下,我又试了直接输出字符串会出现什么效果,如图:

demo2

可以看到javascript字符串在遇到反斜杠时不会报错,但是也会丢失部分反斜杠

所以可以先从反斜杠下手查找对应文档,我们都知道反斜杠“\”是转义字符。那么反斜杠到底可以转义哪些字符呢?这里是MDN的列表:

转义符

那么不在这个列表的字符跟在反斜杠后会发生什么呢?demo2的结果告诉我们JavaScript在字符串里会直接忽略这个反斜杠并返回。

那么为什么到JSON.parse会直接报错了呢?

这个问题的关键点就是JSON.parse方法内的值其实首先是一个字符串,那么JavaScript就会先对这个字符串进行处理,所以真正传给JSON.parse方法的值应该如图:

demo2

JSON.parse是在遇到反斜杠后的字符不在支持的转义列表后才报的错。这里可以看出JSON.parse和JavaScript字符串在处理转义符时是有差异的,JavaScript字符串是忽略,JSON.parse报错。

问题描述

上传接口上传9.3M的TXT文件报:HTTP Status Code: 413 Request Entity Too Large

此问题通过搜索很快能定位到需要设置NGINX的client_max_body_size,查看当前NGINX发现已经配置client_max_body_size为16M,没有解决问题。

进一步测试,发现上传8.1M的文件没有问题,但是上传9.2M出现413问题。

解决方案

猜测client_max_body_size需要调整为上传文件大小的两倍,调整client_max_body_size到30M,上传9.2M文件成功

根本原因分析

进一步测试,发现上传9.3M的TXT文件,接口Request的Content-Length字节为19526438,相当于18.6M。这个大小已经超过最初NGINX设置的client_max_body_size大小16M,所以最初上传9.3M失败。而之前测试的8.1M的TXT文件它的Content-Length为16109146,不到16M,所以上传成功。

为什么原始文件上传后,它的Request的Content-Length会变成原始文件大小的两倍呢?

查询文档发现,TXT文件的编码不同,会导致在上传时的Content-Length大小不同。这个上传接口的Content-Type为multipart/form-data,会将上传文件转换成二进制编码进行上传。而一般TXT文件的编码方式都是Unicode。Unicode转换成二进制导致最终的Content-Length变大。

注:以下命令如不特殊说明,都是在Mac环境下操作,其他系统的命令可能有所不同。

ping

ping是最常用的命令,用来测试数据包能否透过IP协议到达特定主机。ping的运作原理是向目标主机传出一个ICMP echo@要求数据包,并等待接收echo回应数据包。程序会按时间和成功响应的次数估算丢失数据包率(丢包率)和数据包往返时间。

1
2
3
4
5
ping arayzou.com  // 不间断的每秒执行
ping 8.8.8.8 // 可以直接ping IP
ping -c 10 arayzou.com // 指定执行次数
ping -i 0.4 arayzou.com // 指定间隔时间,单位秒
ping --help // 帮助

ssh

一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。常用来远程登录系统。

1
2
3
ssh user@hostname
ssh root@8.8.8.8
ssh-keygen -t dsa // 构建ssh密匙对

traceroute / tracert / tracert

用于显示数据包在网络上经过的路由器的IP地址

Mac下的traceroute;windows下的tracert;Linux下的tracert

1
traceroute arayzou.com

ipconfig / ifconfig

用来获取网络接口配置信息并对此进行修改。windows下的ipconfig对应Linux/Mac下的ifconfig。

修改配置信息的功能大致列举如下:

  • 开启/关闭指定的网络设备
  • 配置网卡的IPv4/IPv6地址
  • 设置网卡传输队列的长度
  • 设置网卡的子网掩码
  • 设置网卡的最大传输单元
1
ifconfig  // 获取本机网络接口配置信息

nslookup

用于查询域名DNS的记录。经常用来检查域名解析是否正常,在网络故障的时候用来诊断网络问题。

1
2
3
nslookup domain [dns-server]
nslookup arayzou.com // 不指定dns-server用系统默认DNS服务器
nslookup -qt=type domain [dns-server] //指定参数,查询其他记录

Non-authoritative answer(未授权的回答):指DNS缓存,

dig

解析域名DNS除了nslookup,dig命令也可以用来解析域名,dig可以得到更多的域名信息。

1
2
dig arayzou.com
dig -t MX arayzou.com // 查询MX记录类型

whois

顾名思义,用于查找并显示用户/域名信息

1
whois arayzou.com

netstat

netstat命令用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。

1
netstat -a  // 列出所有连线

telnet

用来探查远端的某个端口是否可访问。
用来做远程登录。

1
telnet 8.8.8.8 8080

nmap

用于检测目标主机的端口、服务类型、版本信息扫描,需要安装。

1
nmap 8.8.8.8

logo

WebRTC简介

2010年5月,Google 花费6820万美元收购拥有编解码、回声消除等技术的 GIPS 公司。之后谷歌开源了 GIPS 的技术,与相关机构 IETF 和 W3C 制定行业标准,组成了现有的 WebRTC 项目。

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。

WebRTC包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。

p2p对等式网络(peer-to-peer, 简称P2P),又称点对点技术,是无中心服务器、依靠用户群(peers)交换信息的互联网体系,它的作用在于,减低以往网路传输中的节点,以降低资料遗失的风险。

WebRTC支持情况

bs

主流浏览器和设备目前基本都支持了,iOS在去年更新的11也支持了webRTC,接下来我们来了解下WebRTC主要做了哪些事情

3 main tsks

  • 获取到设备的影像(audio)和声音(video)的串流
  • 建立连接,传送影像和声音
  • 传送任意数据
Read more »

Nginx简介

Nginx(发音同engine x)是一个网页服务器,它能反向代理HTTP, HTTPS, SMTP, POP3, IMAP的协议链接,以及一个负载均衡器和一个HTTP缓存。

Nginx 是由俄罗斯人 Igor Sysoev 为俄罗斯访问量第二的大型的门户网站及搜索引擎Rambler.ru站点开发的。在Nginx逐渐受到广泛使用后, Igor Sysoev于2011年成立以Nginx为主的网页服务器软件设置、方案解决公司“Nginx, Inc.”;并担任该公司的CTO。

Nginx当前使用路情况:

Nginx与Apache对比:

Apache 在处理流量爆发的时候(比如爬虫或者是 Digg 效应) 很容易过载,这样的情况下采用 Nginx 最为合适。Nginx作为前端服务器很有优势。

Nginx特点

  • 核心特点:它能在支持高并发请求的同时保持高效的服务
  • 高扩展性(模块扩展)
  • 高可靠性
  • 低内存消耗
  • 单机支持5万以上的并发连接
  • 热部署

反向代理

Nginx主要的一个功能就是反向代理,那为什么叫反向代理?那什么是正向代理?

正向代理是一个位于客户端和原始服务器之间的服务器, 从而为客户端从原始服务器中取得所需要的数据。客户端向代理服务器发送一个请求,并且写明了地址。之后代理向原始服务器转交并且将获得的内容返回给客户端。

对于客户端来说,反向代理就好像原始服务器。并且客户端不需要进行任何设置。客户端向reverse proxy中的name-space发送请求,接着反向代理判断请求走向何处,并将请求转交给客户端。

Nginx能做什么?

  • nginx搭建静态资源服务器
  • 反向代理分发多端口后端服务,配合pm2
  • nginx在前端中的应用
    • 反向代理解决跨域问题
    • nginx根据UA跳转PC和M站
    • Nginx获取cookie做分流
    • 资源合并
    • gzip压缩
    • 图片处理(压缩)
    • SourceMap配合调试
Read more »

这是个小众场景,因为现在webpack大多是和react配合使用,react并不需要在html中添加过多内容,所以可能关注不是很多,我之前研究webpack,希望可以配合jQuery做基础的前端技术栈的打包,所以希望可以热更新HTML。

首先我们需要理解的是webpack所有文件皆是JS模块,我们在entry里定义了某些入口文件,通过webpack处理这些入口文件内部的依赖,最后打包到output里的目录中去。按照这个思路,我们可以把html文件也当成一个js模块,在js入口文件中引入,这样webpack的HRM就可以监听到这个html模块了,自然就可以做到热更新!

通过这个思路,我们需要一个转义html文件的插件:raw-loader

首先我们安装raw-loader

1
npm install --save-dev raw-loader

webpack配置如下:

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
// webpack.config.dev.js
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
devtool: 'cheap-eval-source-map',
entry: [
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
module: {
loaders: [{
test: /\.css$/,
loaders: ['style', 'css']
}, {
test: /\.html$/,
loader: "raw-loader" // loaders: ['raw-loader'] is also perfectly acceptable.
}]
},
devServer: {
contentBase: './dist',
hot: true
}
}

这样我们在入口文件引入html文件:

1
2
// index.js
require('./index.html')

现在就可以做到热更新了,但是我们还需要区分一下本地和生产环境,不然生产环境会把html打包进去。配置如下:

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
// webpack.config.prod.js
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
devtool: 'source-map',
entry: ['./src/index'],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false,
},
}),
new webpack.optimize.OccurenceOrderPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
],
module: {
loaders: [{
test: /\.css$/,
loaders: ['style', 'css']
}]
}
}
1
2
3
4
//index.js
if (process.env.NODE_ENV !== 'production') {
require('./index.html')
}
Read more »

饭要一口一口吃,路要一步一步走,webpack不能再稀里糊涂的拷来拷去了,先来了解一下常用的Plugins和Loaders

Loaders简介

用途

loader是webpack中一个重要的概念,它是指用来将一段代码转换成另一段代码的webpack插件。为什么需要将一段代码转换成另一段代码呢?这是因为webpack实际上只能处理JS文件,如果需要使用一些非JS文件(比如Coffee Script),就需要将它转换成JS再require进来。当然,这个代码转换的过程能做的远不止是Coffee->JS这么简单,比如编译Less/SASS/CoffeeScript,比如在页面中插入一段HTML,比如修改替换文本文件等等。

串联

loader是可以串联使用的,也就是说,一个文件可以先经过A-loader再经过B-loader最后再经过C-loader处理。而在经过所有的loader处理之前,webpack会先取到文件内容交给第一个loader。

1
require('style!css!./style.css');

常用Loaders清单

官方list-of-loaders

Read more »

nginx+https+http2搭建(一),第二部分会简单介绍一下http1.1,https和http2,最后再介绍nginx+https+http2的搭建过程。

HTTP现状

目前主流的http版本是http1.1版,它是在1999年发布的,距今已经有超过十五年的时间。

首先http的安全性问题:

  • 通信使用明文(不加密),内容可能会被窃听
  • 不验证通信方的身份,因此有可能遭遇伪装
  • 无法证明报文的完整性,所以有可能已遭篡改
    这里最经典的例子就是恶心的运营商劫持,针对这个就要说到下面的https解决方案

http1.1出生的那个年代,网站的规模还很小,但是现如今的网站已经不是web页面了,而是web应用,SPA,动辄几兆的请求,上百个连接,几十个域名和同域几十个连接,大部分的时间都消耗在网络上,http1.1的瓶颈就显现出来了:

  • 因为HTTP实际上对每个TCP连接,只允许一个优先的请求。
  • 请求只能从客户端开始。客户端不可以接收除响应以外的指令
  • 请求/响应首部未经压缩就发送,首部信息越多延迟越大。
  • 发送冗长的首部,每次互相发送相同的首部造成的浪费较多
  • 可任意选择数据压缩格式,非强制压缩发送
    为此我们做了很多克服延迟的方法,雪碧图,内联样式,域共享等等。。而这里的大部分问题,在http2协议中都得到解决!

HTTPS简介

HTTPS = HTTP + 加密 + 认证 + 完整性保护,它并非是应用层的一种新协议,而是身披SSL外壳的HTTP。

SSL(Secure Socket Layer)是独立于HTTP的协议,不光是HTTP,SMTP和Telnet等协议也可配合SSL协议使用。可以说SSL是当今世界上应用最为广泛的网络安全协议。

HTTPS安全可靠,但是使用SSL时,处理速度会变慢,这里主要体现在通信慢和加密处理慢。

HTTP/2简介

HTTP/2于2015年5月作为互联网标准正式发布。它基于Google制定的SPDY协议,由IETF HTTPbis小组制定维护。并且Google表示将放弃SPDY转而全力支持HTTP/2。

HTTP/2 协议由以下两个 RFC 组成:RFC 7540和RFC 7541。它与HTTP/1.x的主要区别:

  • 基于二进制而不是文本的
  • 完全多路复用,代替原来的排序和阻塞机制
  • 在一条连接中并行处理多个请求
  • 压缩头部减少开销
  • 允许服务器主动推送响应到客户端的缓存中

HTTP/2兼容性:caniuse

ssl证书安装

我这里用的是letsencrypt各大知名网络厂商联合发布的免费 SSL 证书,签发比较麻烦,签一次有效期三个月,可以继续续签。安装地址Certbot
这里没有什么难度,按照教程安装即可。

安装:

1
sudo apt-get install letsencrypt

生成证书:

1
letsencrypt certonly --standalone -d demosite.com

生成后会告诉你证书所在路径,这个要记好,下面的nginx配置时要用到。

nginx+https+http2配置

默认的https的端口是443,而我们的网站默认端口是80,这里的nginx我们需要做一个转发,之前提到的demosite.conf可以改成这样

1
2
3
4
5
6
7
8
9
10
11
12
13
server
{
listen 443 ssl http2;
server_name file.demosite.com;

ssl_certificate /etc/letsencrypt/live/file.demosite.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/file.demosite.com/privkey.pem;

location / {
root /home/demosite;
}
access_log logs/static_file_access.log;
}

listen的端口改为443,后面加ssl表示用https,加http2表示使用http2协议,现在的nginx最新版已经默认支持http2模块,不需要特别安装。

然后我们新建一个配置文件vi demosite_80.conf,代码如下:

1
2
3
4
5
server {
listen 80;
server_name file.demosite.com;
return 301 https://file.demosite.com$request_uri;
}

这个配置文件就是做一个80端口的转发,然后重启nginx就可以看到绿色的小锁了。

如果地址是https但是没有绿色的小锁,可能的原因是你的站点有引用不是https协议的资源,这里就需要你一一排查了。

参考:
https://imququ.com/post/http2-resource.html
HTTP/2 常见问题集锦