Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
shfshanyue committed Apr 7, 2022
1 parent 954088b commit 54aa477
Show file tree
Hide file tree
Showing 10 changed files with 565 additions and 36 deletions.
8 changes: 8 additions & 0 deletions douyin/http-cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@ max-age 可设置强缓存时间周期,在该周期内,将直接从客户端
它每次发送请求时,需要进行缓存新鲜度校验,如果资源过旧,将直接从响应中获取,否则从客户端缓存中进行获取。

新鲜度校验,通过请求头 If-None-Match 与响应头 ETag 进行对比,或者请求头 If-Modified-Since 与响应头 Last-Modifed 进行对比。

一般来说,我们对经构建工具打包后,带有 hash 的资源进行一年的强缓存。

而对不带 hash 的资源进行协商缓存控制,注意协商缓存需配置 Cache-Control 为 max-age=0,或者 no-cache。

否则一个没有设置 Cache-Control 的静态资源,将会根据 Date 与 Last-Modified,计算出强缓存时间。

我们可以通过谷歌浏览器中开发者工具中的网络面板,查看其 Javascript、CSS 等资源的响应头,来确认是否配置了正确的缓存策略。
20 changes: 20 additions & 0 deletions douyin/minify.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ function f(a,b){return a+b}console.log(f(3,4))
console.log(7)
```

terser 是 js 中专业的代码压缩工具,在 webpack 中可使用 `terser-webpack-plugin` 进行代码压缩。

我们可以在 Terser REPL 中在线尝试压缩代码。

哦对,在测试环境中用以调试随便打的 console.log,出现在生产环境中是不不太好。

很多同学也将去除生产环境中的 console.log 写在简历上。

这仅仅需要对 terser 添加一个配置项 drop_console 即可完成。

## 纯文字

大家好,我是山月。
Expand All @@ -58,3 +68,13 @@ console.log(7)
我们开启代码压缩的神奇魔法,在编译期对代码进行预计算。

经优化,代码最终仅有 14 个字节。

terser 是 js 中专业的代码压缩工具,在 webpack 中可使用 terser-webpack-plugin 进行代码压缩。

我们可以在 Terser REPL 中在线尝试压缩代码。

哦对,在测试环境中用以调试随便打的 console.log,出现在生产环境中是不不太好。

很多同学也将去除生产环境中的 console.log 写在简历上。

这仅仅需要对 terser 添加一个配置项 drop_console 即可完成。
4 changes: 4 additions & 0 deletions frontend-engineering/deploy/ci-env.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ $ CI=true npm run test
$ CI=true npm run build
```

::: v-pre

## 写段 CI 验证下 CI 中的环境变量

![](https://cdn.jsdelivr.net/gh/shfshanyue/assets/2022-01-11/clipboard-9125.9b3a8e.webp)
Expand Down Expand Up @@ -158,3 +160,5 @@ jobs:
## 小结

关于 CI 中的环境变量介绍就到此了,下篇文章将介绍功能分支的 Preview。

:::
128 changes: 95 additions & 33 deletions frontend-engineering/deploy/simple-intro.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# 关于前端部署的简单理解
# 手写最简静态资源服务器

在所有人入门编程及学习更多编程语言时,敲下的第一行代码是: 输出 `hello, world`

初学如何部署前端,如同学习编程一样,第一步先根据最简单页面进行部署。
``` js
console.log('hello, world')
```

初学部署前端,如同学习编程一样,第一步先根据最简单页面进行部署。

比如本系列专栏,先部署一个最简单 HTML 如下所示,只有几行代码,我称它为**hello 版前端应用**
比如本系列专栏,先部署一个最简单 HTML 如下所示,只有几行代码,无任何 CSS/Javascript 代码,我称它为**hello 版前端应用**

``` html
<!DOCTYPE html>
Expand All @@ -21,11 +25,20 @@

> PS: 本文以 [simple-deploy](https://github.com/shfshanyue/simple-deploy) 仓库作为实践
我们将带着两个疑问,一步一步了解前端部署:

1. 如何手写一个简单的静态资源服务器用以部署前端
1. 为何需要 nginx、docker 等工具辅助前端部署

## HTTP 报文

部署可看做对 HTTP 资源的服务,或者说,是对 HTTP 请求报文的响应。我们写一段服务器代码用以返回 HTML,便完成了对前端的部署。
HTTP 是在互联网中进行数据交互的协议,你可从互联网中拿到文档、图片、音频及视频各种资源。

而最简部署可看做,你向服务器发送一个获取 HTML 资源的请求,而服务端将响应一段 HTML 资源。我们在请求资源的过程中将发送一段请求报文(Request Message),而服务端返回的 HTML 资源为响应报文(Response Message)。

以下是对*hello版前端应用*的一段简单的 HTTP 请求及响应报文。
我们写一段服务器代码,在 HTTP 响应报文中设置响应体为 HTML,便完成了对前端的部署。

以下是对**hello版前端应用**的真实的 HTTP 请求及响应报文。

> 通过 `curl -vvv localhost:3000` 可获得报文信息。
Expand Down Expand Up @@ -54,13 +67,34 @@ Keep-Alive: timeout=5
</html>
```

以下是对**hello版前端应用**的 HTTP 请求及响应报文的图文表示

![](https://cdn.jsdelivr.net/gh/shfshanyue/assets/2022-02-24/simple-deploy.67a117.webp)

## 一段简单的服务器部署代码
好,那接下来我们写一段服务器代码,用以响应 HTML。

## 手写简单静态资源服务器: 响应字符串

作为前端,以我们最为熟悉的 Node 为例,写一段最简单的前端部署服务。该服务监听本地的 3000 端口,并在响应体返回我们的**hello 版前端应用**

为求简单,我们直接将**hello 版前端应用**以字符串的形式进行响应。

作为前端,以我们最为熟悉的 Node 为例,写一段最简单的前端部署服务
Node 中写服务端最重要的内置模块(`builtinModule`)为 [node:http](https://nodejs.org/api/http.html),通过 `node:` 前缀,可指明其为内置模块,被称作 `Protocol Import`。从而避免了 node 内置模块与第三方模块的命名冲突

该服务监听本地的 3000 端口,并返回我们的*hello 版前端应用*
``` js
const http = require('node:http')
```

通过 `http.createServer` 可对外提供 HTTP 服务,而 `res.end()` 可设置 HTTP 报文的响应体。以下是一段 hello 版本的 nodejs 服务。

``` js
const server = http.createServer((req, res) => res.end('hello, world'))
server.listen(3000, () => {
console.log('Listening 3000')
})
```

我们将**hello 版前端应用**以字符串的方式在代码中进行维护,并通过 `res.end()` 设置其为响应报文的响应体。最终代码如下。

> PS: 该段服务器 nodejs 代码位于 [simple-deploy/server.js](https://github.com/shfshanyue/simple-deploy/blob/master/server.js)
Expand All @@ -84,19 +118,36 @@ server.listen(3000, () => {
})
```

启动服务,并在浏览器端打开 `localhost:3000`,可看见 `hello, shanyue`
通过 `node server.js` 启动服务,成功运行。

``` bash
$ node server.js
Listening 3000
```

启动服务后,在浏览器端打开 `localhost:3000`,可查看到响应头及响应体 `hello, shanyue`

![](https://cdn.jsdelivr.net/gh/shfshanyue/assets/2021-12-31/clipboard-3621.529aef.webp)

**恭喜你,部署成功!**

但是前端静态资源总是以文件的形式出现,我们对代码进一步优化
但是前端静态资源总是以文件的形式出现,我们需对代码进一步优化

## 一段稍微复杂的服务器代码: 文件系统
## 手写简单静态资源服务器: 响应文件

当然,部署前端作为**纯静态资源**,需要我们使用文件系统(file system)去读取资源并将数据返回。

在代码中,html 以前以字符串形式进行维护,现在将其置于文件系统中的 `index.html` 中,并通过 nodejs 中文件系统读取文件的相关 API `fs.readFileSync('./index.html')` 进行获取文件内容,代码如下。

``` js
// fs 为内置模块,
const fs = require('node:fs')

当然,部署前端作为**纯静态资源**,需要我们使用文件系统(fs)去读取资源并将数据返回。
// 通过 fs.readFileSync 可读取文件内容
const html = fs.readFileSync('./index.html')
```

在代码中,html 以前是个字符串,现在通过 nodejs 文件系统读取文件的相关 API `fs.readFileSync('./index.html')` 进行获取,代码如下
我们将**hello 版前端应用**以文件系统的方式进行维护,并通过 `res.end()` 设置其为响应报文的响应体。最终代码如下

> PS: 该段服务器 nodejs 代码位于 [simple-deploy/server-fs.js](https://github.com/shfshanyue/simple-deploy/blob/master/server-fs.js)
Expand All @@ -113,9 +164,16 @@ server.listen(3000, () => {
})
```

当然,对于前端这类纯静态资源,**自己写代码无论从开发效率还是性能而言都是极差的**
接下来启动代码,成功运行。

``` bash
$ node server-fs.js
Listening 3000
```

当然,对于前端这类纯静态资源,**自己写代码无论从开发效率还是性能而言都是极差的**,这也是我们为何要求助于专业工具 nginx 之类进行静态资源服务的原因所在。

比如将文件系统修改为 `ReadStream` 的形式将会提升该静态服务器的性能,代码如下。
比如将文件系统修改为 `ReadStream` 的形式进行响应将会提升该静态服务器的性能,代码如下。

```js
const server = http.createServer((req, res) => {
Expand All @@ -130,58 +188,62 @@ const server = http.createServer((req, res) => {
$ npx serve .
```

create-react-app 构建成功后,它会提示使用 `serve` 进行部署。
`serve``next.js` 的母公司 `vercel` 开发的一款静态资源服务器。作为前端久负盛名的静态服务器,广泛应用在现代前端开发中,如在 `create-react-app` 构建成功后,它会提示使用 `serve` 进行部署。本地环境而言,还是 [serve](https://github.com/vercel/serve) 要方便很多啊

![Creact React APP 构建后,提示使用 serve 进行部署](https://cdn.jsdelivr.net/gh/shfshanyue/assets/2021-12-31/clipboard-3980.619061.webp)

**然而,Javascript 的性能毕竟有限,使用 `nginx` 作为静态资源服务器拥有更高的性能。**

但是对于本地环境而言,还是 [serve](https://github.com/vercel/serve) 要方便很多啊。

## 部署的简单理解

那什么是部署呢,为什么说你刚才部署成功?
通过以上两个最简服务的成功运行,可以使我们更加深入的了解前端部署。我们再回头看,什么是部署呢,为什么说你刚才部署成功?

假设此时你有一台拥有公共 IP 地址的服务器,在这台服务器使用 `nodejs` 运行刚才的代码,则外网的人可通过 `IP:3000` 访问该页面。那这可理解为部署,使得所有人都可以访问。

假设此时你有一台拥有公共 IP 地址的服务器,在这台服务器使用 `nodejs` 运行刚才的代码,则外网的人可通过 `IP:3000` 访问该页面
假设你将该服务器作为你的工作环境,通过 `npm start` 运行代码并通过,所有人都可访问他,即可视为部署成功。看来你离所有人都可访问的部署只差一台拥有公共 IP 的服务器

那这可理解为部署,使得所有人都可以访问
实际上,有极少数小微企业在生产环境中就是直接 ssh 进生产环境服务器,并通过 `npm start` 部署成功后,通过 IP 与端口号的方式进行访问。当然通过 IP 地址访问的项目一般也非公开项目,如果公开使用域名的话,则用 nginx 配置域名加一层反向代理

假设你将该服务器作为你的工作环境,通过 `npm run start` 运行代码并通过,所有人都可访问他,部署成功。看来你离所有人都可访问的部署只差一台拥有公共 IP 的服务器。
**不管怎么说,你现在已经可以通过裸机(宿主机)部署一个简单的前端应用了。**

不管怎么说,你现在已经可以通过裸机(宿主机)部署一个简单的前端应用了。
## 关于部署的更多疑问解答

## 一些疑问
我们现在已经可以在本地跑起服务了,但是在生产环境部署为什么还需要 nginx,甚至 docker 呢?

*问: 那既然通过 `npm start` 可以启动服务并暴露端口对外提供五福,那为什么还需要 nginx 呢?*
接下来,我回应一些关于前端部署的更多疑问。

**你需要管理诸多服务(比如A网站、B网站),通过 nginx 进行路由转发至不同的服务,这也就是反向代理**,另外 nginx 还可以提供 TLS、HTTP2 等功能。
*一问: 那既然通过 `npm start` 可以启动服务并暴露端口对外提供服务,那为什么还需要 nginx 呢?*

**你需要管理诸多服务(比如A网站、B网站),通过 nginx 进行路由转发至不同的服务,这也就是反向代理**,另外 TLS、GZIP、HTTP2 等诸多功能,也需要使用 nginx 进行配置。

当然,如果你不介意别人通过端口号去访问你的应用,不用 nginx 等反向代理器也是可以的。

![反向代理](https://cdn.jsdelivr.net/gh/shfshanyue/assets/2022-02-24/Nginx.632fa5.webp)

*: 我确实不介意别人通过 IP:Port 的方式来访问我的应用,那在服务器可以 npm run dev 部署吗?*
*二问: 我确实不介意别人通过 IP:Port 的方式来访问我的应用,那在服务器可以 npm run dev 部署吗?*

可以,但是非常不推荐。`npm run dev` 往往需要监听文件变更并重启服务,此处需要消耗较大的内存及CPU等性能。
**可以,但是非常不推荐**`npm run dev` 往往需要监听文件变更并重启服务,此处需要消耗较大的内存及CPU等性能。

针对 Typescript 写的后端服务器,不推荐在服务器中直接使用 `ts-node` 而需要事先编译的理由同样如此。

当然,如果你也不介意性能问题也是可以的。

*: 那为什么需要 Docker 部署?*
*三问: 那为什么需要 Docker 部署?*

用以隔离环境。

假设你有三个后端服务,分别用 Java、Go、Node 编写,你需要在服务器分别安装三者的环境,非常麻烦
假设你有三个后端服务,分别用 Java、Go、Node 编写,你需要在服务器分别安装三者的环境,才能运行所有语言编写的代码,这对于开发者而言非常麻烦

假设你有三个 Node 服务,分别用 node10、node12、node14 编写,你需要在服务器分别安装三个版本 nodejs,非常麻烦
假设你有三个 Node 服务,分别用 node10、node12、node14 编写,你需要在服务器分别安装三个版本 nodejs 才能运行各个版本 nodejs 编写的代码,对于开发者而言也非常麻烦

而有了 Docker,就没有这种问题。
而有了 Docker,就没有这种问题,它可单独提供某种语言的运行环境,并同时与宿主机隔离起来

对于前端而言,此时你可以通过由自己在项目中单独维护 `nginx.conf` 进行一些 nginx 的配置,大大提升前端的自由性和灵活度,而无需通过运维或者后端来进行。

## 小结

本篇文章介绍了了一些对于前端部署的简单介绍,并使用 nodejs 写了两段代码用以提供静态服务,来加深理解。
本篇文章介绍了了一些对于前端部署的简单介绍,并使用 nodejs 写了两段代码用以提供静态服务,加深对前端部署的理解。虽然我们可自写代码对前端静态资源进行部署,但从功能性与性能而讲,都是远不如专业工具的。

在本文章,将应用在本地或者宿主机进行成功运行,但是现代流行的前端部署方案,都是使用 docker 对前端进行部署。

而在下篇文章中,我们将介绍如何使用 Docker 将仅有十几行代码的 **hello 版前端应用** 跑起来。
23 changes: 23 additions & 0 deletions post/10000.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
哔哩哔哩粉丝突破一万,前端面试重启!

大家好,我是山月。

就在今天愚人节的凌晨零点零三分,我的哔哩哔哩粉丝数达到了一万。从截图可以看出,十二月底打破千粉大关,三个月增长了九千粉丝。

![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9c17b5054a9d4287aaa8c8f2a1975d10~tplv-k3u1fbpfcp-watermark.image?)

接下来,准备了一些一分钟即可讲完的前端小知识,将被我放在合集《前端一分钟》。

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/015e1bc474d044c393c320c0a224b10f~tplv-k3u1fbpfcp-watermark.image?)

我在三月份上半月的朋友圈宣布暂时停止模拟面试一段落。但是,由于得到了珠峰架构的独家赞助,模拟面试得以继续。关于珠峰架构的这个 logo,将会在我模拟面试时挂在直播间右下角。

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/48cb3b182a884a17b455af769ee55645~tplv-k3u1fbpfcp-watermark.image?)

我的模拟面试一个月将会进行十次,感兴趣的同学可以添加我的微信 `shanyue-bot` 来报名了,如果报名超过十个,将会做进一步筛选。

如果不会写简历,可以在我的公众号后来回复简历二字,获取我简单做的简历内容模板。

哦对,我昨天刚在院里种了两排蜀葵,希望能发芽。

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0ab5bdbfdb12497384309e431ad0396b~tplv-k3u1fbpfcp-watermark.image?)
Loading

0 comments on commit 54aa477

Please sign in to comment.