0%

如果现在要开发一个 React 项目,那最快的方式应该就是直接使用 Facebook 官方开源的脚手架 creat-react-app,简称:CRA。但是,随着项目的业务场景复杂度提升,难免会需要在开发环境里做一些配置上的调整。这个时候就只能把脚手架进行 eject 后,亲自上阵修改 Webpack 的配置了,即便是这样 CRA 对于 Webpack 的配置灵活度也是相对的不太高。如果这个时候对 Webpack 不够熟练的话,就会有种心有余而力不足的感觉。

想当初我为了要给公司的前端项目搭建开发环境时,也是被 Webpack 折腾的死去活来,配置 Webpack 的时候总是记不住配置里的那些字段,而且配置时还要牵扯到一系列的工具,像 ES6 编译器 Babel、CSS 预处理器 less/sass、CSS 后处理器 postcss,还有各种 webapck 的 loader 和 plugin。所以,在刚开始的一段时间里都还是直接 CRA 了事。不过在经过一段时间的毒打后,在后续的项目里逐渐的把 CRA 替换为自行搭建的开发环境。现在让我从零开始一个前端项目的话,我更多的会选择自己去搭建开发环境,其次才会去选择官方的 CLI。

而这篇文章最主要目的是想让大家(特别是新手)能够从零开始,一步一步搭建出一个完整的开发环境。然后在搭建的过程中,一点一点的了解每一步中所配置项的作用及其原理,每一个插件的作用及其影响并对比同功能插件的差别。只要跟着步骤来走,就一定能实现所说的同样功能。

先附上项目地址:webpack-typescript-react-practice2

阅读全文 »

接着上一文,在更优雅的 JavaScript 1中,我们聊到了基础的 JavaScript 编写的建议。包括如何可靠的声明变量、常量、函数、以及利用合适的函数构建合适的逻辑,现在我们思考改善代码的第一步,如何命名?

在我们开始阅读代码之前,编码风格与命名方式会比代码的抽象方式、设计技巧更令我们印象深刻。很多时候也会为项目的整体风格定下基调。如果你阅读过一些算法工程师写的代码,常常会看到单字母变量反复的声明不知所以的赋值与拷贝累赘的条件判断等等。我们虽不能说这样有问题,因为他们的代码大多的确是可以正常的运作,甚至在运行的时间或空间效率上有一些优势。但这在工程,特别是大型工程中是不值得称道的,根据经验我们可以把这类代码归类为“屎山”,充其量是“堆”了一摊高性能的“屎山”。

而我们现在做的则是脱离“编程只不过是工具”的阶段,脱离“屎山男孩”,让机器面有喜色、富有人性,使阅读者在某个瞬间也能切实的感受到创作者的思维跳动与审美哲学。

阅读全文 »

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

貌似,现在大家写代码都只是在追求其极致性能、精巧体积、华丽技巧,而忽视了最重要的”code for humans“。

我们知道在日常项目开发时,代码被人阅读的难度是远高于执行引擎的。所以要写出好的代码就需要尝试脱离自己的视角,以第三人的眼光重新审视、理解其上下文的含义。 这样创作出的代码结构、组合、技巧才会予人阅读的幸福感。我们致力于书写优秀的代码就意味着,代码不仅仅是一个工具,更是将其视作为用来传达精神、思想、理念的一座桥梁。这是一种对于书写者智慧的锤炼与分享。

阅读全文 »

平时在项目开发的过程中,因为 JavaScript 模块化的历史遗留问题,难免会存在在 CommonJS 的模块里头 import ES6 的模块,或者在 CommonJS 的模块里头 require ES6 的模块的情况发生。为了能够搞清楚他们之间的转换小秘密,所以就专门记录一下,方便日后回顾,顺便上来水一文。

因为这两种模块在网络上存在着各式各样的叫法,所以在文章开始前,为了能够和大家达成一致的共识。在后面我将会用 CJS 代指 CommonJS Module,用 ESM 代指 ES Modules。

ESM 转 CJS

1. ESM export 转 CJS exports

举个栗子:

1
2
3
4
// a.js
export var foo = "bar";
export function func() {}
export default 1;

a.js 中的 ESM 在经过 babel 转为 CJS 后,代码变为:

注:在 ESM 被转为 CJS 时,转译器会在其导出的对象中定义一个值为 true 的私有的变量 __esModule

1
2
3
4
5
6
7
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

exports.func = func;
var foo = (exports.foo = "bar");
function func() {}
exports.default = 1;

其实也就等价于:

1
2
3
4
5
6
"use strict";
exports.__esModule = true; // 该属性实际上会通过Object.defineProperty API设置为不可枚举

exports.foo = "bar";
exports.func = function () {};
exports.default = 1;
阅读全文 »

缓存在开发人员的眼里并不陌生,它对于程序的性能和效率的提升起到了至关重要的作用。甚至是在 CPU 与内存这种硬件与硬件间的交互,也存在着多级别的缓存用以提升交互间的性能。同样的,在前端要进行性能的优化,减少客户端与服务端的资源请求,提升客户端页面的加载速度,自然也就摆脱不了缓存这个“魔咒”。而前端文件缓存实质上也就是 HTTP 缓存,而 HTTP 缓存经过 HTTP 版本的迭代升级,也存在着几种不同的缓存设置方式。

阅读全文 »

毋庸置疑,目前互联网世界里 HTTP 协议(Hypertext Transfer Protocol)已经是大家日常网上冲浪时最常用的应用层协议。但是,由于 HTTP 其本身主要就是用于传输超文本的网络协议,并不会保证所传输的数据是否安全可靠。所以,在使用 HTTP 协议进行密码数据传输时,就类似于在通往数据接收方的路上,走着一个衣服上写着密码内容的人。

SSL发展史

由于使用 HTTP 协议就如同让数据在大街上裸奔的原因,所以网景(Netscape)在 1995 年设计了 HTTPS 协议,使用了安全套接字层(Secure Sockets Layer:SSL)保证数据传输的安全可靠。随着传输层安全协议协议(Transport Layer Security)的发展,我们目前已经用 TLS 替代了废弃的 SSL 协议,而一般现在所说的 SSL 都是代指 TLS。

所以,可以说 HTTPS 是对 HTTP 协议的一种扩展,由于其基于了传输层的安全协议,我们得以可以使用它在互联网上安全地上网冲浪,传输私密数据等等。然而 HTTPS 从第一次发出建立连接请求到连接成功建立发送数据,这中间需要七次握手存在 4.5 倍的往返延迟(Round-Trip Time:RTT),比 HTTP 要多出几倍。所以,今天在这里就粗解一下其中的过程及其原因。

  1. TCP 协议,通信双方三次握手建立 TCP 连接
  2. TLS 协议,通信双方四次握手建立 TLS 连接
  3. HTTP 协议,客户端向服务端发送请求,服务端反馈响应

我们可以从上面就可以看出,多出的往返延迟应该是在 TLS 协议的握手阶段产生出来的。而我们下面所做的分析都是建立在特定版本的协议实现以及常见场景上。因为,随着网络技术的发展,网络协议的迭代升级,一些新版本的协议已经通过新的机制优化掉多余通信往返,在后面我们会略带一提。

阅读全文 »

流量控制

1. 什么是流量控制

在 TCP 传输中,如果数据发送方的发送速度过快,那么就会造成数据接收方来不及接收所有发送出的数据。那么在这样的状况下,就会有分组丢失的情况发生。控制数据发送方的发送速度,使得数据接收方来得及接收,这就是流量控制。

2. 流量控制的目的

流量控制的其根本目的就是防止 TCP 传输中的分组丢失,它是构成 TCP 可靠性传输的其中一个方面。

3. 如何实现流量控制

TCP 传输的流量控制由滑动窗口协议连续 ARQ 协议)实现的,滑动窗口协议既能保证分组无差错、有序接收,也实现了流量控制的功能。主要的方式就是接收方在返回的 ACK 中会包含自己的接收窗口大小,并利用该接收窗口大小来实现控制发送方的数据发送。

阅读全文 »

TCP/IP 作为目前互联网举足轻重的网络通信协议,不是没有它的道理。TCP/IP 提供供了点对点的链接机制,以让源主机中的源进程发出的数据能够送达目标主机的目标进程里去,这其中的资料封装、寻址、传输、路由、接收都会以标准化的操作完成,并且它们还能保证数据在传输过程中有序不重不漏

但是你不知道的是,当应用层协议使用传输层的 TCP 协议进行数据传输时,传输层 TCP 协议可能会将应用层所发送的消息分成多个数据段,我们一般称呼它叫:TCP 分段。而在其下层的网络层 IP 协议也有可能会对传输层 TCP 协议的数据段分成多个数据包,我们一般称呼它叫:IP 分片。但是由于 TCP 协议会自行先分段,所以正常情况下都轮不到 IP 协议进行分片。那为什么它们要拆分我们的数据呢?又为什么 TCP 协议自行分段后,就没 IP 协议什么事了呢?我们带着这些疑问继续探索。

阅读全文 »

其实 TCP 粘包这个问题,在 TCP 的设计角度上看,其问题本质就是一个伪命题。但是为什么会有那么多的开发者提出这样的问题?我们从 TCP 设计的特性可以不难看出,TCP 本就是面向连接基于字节流可靠的传输层通信协议,所以在 TCP 的这个层面来说并不存在包的这个概念,也就没有粘包这么一说了。那按照这么说,粘包问题还能凭空出现的?

在开始之前,我们先达成共识:

  1. 协议层中传输数据的基本单位统称为:Data Unit(数据单元)
  2. 网络层 IP 协议传输的数据单元称为:Packet(包)
  3. 传输层 TCP 协议传输的数据单元称为:Segment(段)
  4. 传输层 UDP 协议传输的数据单元称为:Datagram(报)
  5. 应用层传输的数据单元称为:Message(消息)
阅读全文 »