Coder Social home page Coder Social logo

genffy's Introduction

Hi there 👋

  • 💻 A web developer
  • 🏋️ Marathon & Trail runner 🏃, Swim 🏊
  • 🌱 I’m currently learning something about AI 🤖️

genffy's People

Contributors

genffy avatar

Stargazers

 avatar  avatar

Watchers

 avatar

genffy's Issues

关于git Submodules 使用的一些实践

背景

对于 git,大家再也熟悉不过了,几乎会天天跟它打交道,一般用的就是些很基础的功能。但是,最近接触到一个带有 submodules 的项目,感觉好神奇啊,刚开始完全懵逼,运行的时候发现依赖的文件夹下面是空的,一度怀疑这是不是个 bug,但是这明明是线上跑的好好的一个项目啊。然后就仔细对比了下工程目录,发现除了常见的 .gitignore 外还多了个 .gitmodules。打开看下是酱紫的:

➜  F2ECodeSnippet git:(master) ✗ cat .gitmodules
[submodule "git-submodules-action"]
    path = practice/git/submodules
    url = [email protected]:genffy/git-submodules-action.git

然后就好开心啊,去 google 了下。唔,似乎发现了个新天地。(原谅我这么的野生...

git submodules 的基本概念

Git 通过子模块处理这个问题(你想将两个项目单独处理但是又需要在其中一个中使用另外一个)。子模块允许你将一个 Git 仓库当作另外一个Git仓库的子目录。这允许你克隆另外一个仓库到你的项目中并且保持你的提交相对独立。 --Git-工具-子模块

看到这可能会有人要叫起来,这不就是包管理么,现在不都是通过npm(或者bower)来做,干嘛又搞这个玩意儿?个人的理解,这种场景大多出现在一个企业内部,公用模块一种管理机制,相对私有 npm 来说, gitsubmodule 这种方式或许或更加的灵活些,方便原 repo 和 submodule使用者同时进行修改和同步(相对提PR来说)。anyway,存在即合理。下面主要说下它的一些使用方法和一些需要注意的坑(文档&资料的搬运工)。

step by step

首先,看下它包含哪些命令 或者看这里

➜  F2ECodeSnippet git:(master) ✗ git submodule -h
usage: git submodule [--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
   or: git submodule [--quiet] status [--cached] [--recursive] [--] [<path>...]
   or: git submodule [--quiet] init [--] [<path>...]
   or: git submodule [--quiet] deinit [-f|--force] [--] <path>...
   or: git submodule [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--reference <repository>] [--recursive] [--] [<path>...]
   or: git submodule [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
   or: git submodule [--quiet] foreach [--recursive] <command>
   or: git submodule [--quiet] sync [--recursive] [--] [<path>...]

init & add

对于一个干净的项目来说,常规的操作是 init->add,等待 checkout 完成,项目里就有 .gitmodules 这个文件了,然后看下 .gitmodules.git/config.git/modules 对比下,具体的一些命令参数代表啥大家可以去看官方文档。

➜  Desktop mkdir -p git-submodules-action-new
➜  Desktop cd git-submodules-action-new
➜  git-submodules-action-new git init
Initialized empty Git repository in /Users/genffy/Desktop/git-submodules-action-new/.git/
➜  git-submodules-action-new git:(master) git submodule init
➜  git-submodules-action-new git:(master) git submodule add --name repoA [email protected]:genffy/repoA.git lib_modules/repoA
Cloning into 'lib_modules/repoA'...
remote: Counting objects: 17, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 17 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (17/17), done.
Resolving deltas: 100% (2/2), done.
Checking connectivity... done.
➜  git-submodules-action-new git:(master) ✗ la
total 8
drwxr-xr-x   5 genffy  staff   170B  7  6 00:43 .
drwxr-xr-x+ 22 genffy  staff   748B  7  6 00:41 ..
drwxr-xr-x  12 genffy  staff   408B  7  6 00:43 .git
-rw-r--r--   1 genffy  staff    89B  7  6 00:43 .gitmodules
drwxr-xr-x   3 genffy  staff   102B  7  6 00:43 lib_modules
➜  git-submodules-action-new git:(master) ✗ cat .gitmodules
[submodule "repoA"]
    path = lib_modules/repoA
    url = [email protected]:genffy/repoA.git
➜  git-submodules-action-new git:(master) ✗ cat .git/config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[submodule "repoA"]
    url = [email protected]:genffy/repoA.git
➜  git-submodules-action-new git:(master) ✗ ls .git/modules
repoA

初始化一个包含submodule的项目

然而,对于菜鸟的我来说几乎没有机会去初始化一个干净的项目的,更多的clone现有的代码然后更新啥的。其实 clone 一个包含submodule的项目并初始化,是件很简单的事情(鄙视下前面懵逼的自己) :

➜  Desktop git clone [email protected]:genffy/git-submodules-action.git && cd git-submodules-action && git submodule update --init
Cloning into 'git-submodules-action'...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 46 (delta 12), reused 0 (delta 0)
Receiving objects: 100% (46/46), 7.95 KiB | 0 bytes/s, done.
Resolving deltas: 100% (12/12), done.
Checking connectivity... done.
Submodule 'repoA' ([email protected]:genffy/repoA.git) registered for path 'lib_modules/repoA'
Cloning into 'lib_modules/repoA'...
remote: Counting objects: 17, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 17 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (17/17), done.
Resolving deltas: 100% (2/2), done.
Checking connectivity... done.
Submodule path 'lib_modules/repoA': checked out '9e468932f3529082b14d650969c429e89ed7fc36'

嗯,真的只有一句话。如果是有多个 submoule 需要用到 git foreach 这个方法;如果涉及到层级嵌套,可以加上 --recursive 这个参数。

嗯,以上差不多是些比较常规的用法了。

同步 & 更新

但是,项目总是要不断迭代更新的,对于的库共用模块则无法避免的要更新,有时候还需要使用者贡献代码或者 fix bug 之类的。下面就介绍下如何更新以及 submodule 同步的事情,其实也是比较简单的。

同步

假如在一个 git-submodules-action 下是这样的:

➜  git-submodules-action git:(master) cat .gitmodules
[submodule "repoA"]
    path = lib_modules/repoA
    url = [email protected]:genffy/repoA.git

所依赖的 repoA 是这样的:

➜  repoA git:(master) git remote -v
origin  [email protected]:genffy/repoA.git (fetch)
origin  [email protected]:genffy/repoA.git (push)
➜  repoA git:(master) git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

然后在 repoA 下修改点东西:

➜  repoA git:(master) vi base.css
➜  repoA git:(master) ✗ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   base.css

no changes added to commit (use "git add" and/or "git commit -a")
➜  repoA git:(master) ✗ git commit -am 'add class name'
[master c19e6fe] add class name
 1 file changed, 3 insertions(+)
➜  repoA git:(master) git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 344 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To [email protected]:genffy/repoA.git
   9e46893..c19e6fe  master -> master

然后在git-submodules-action下执行:

➜  git-submodules-action git:(master) git submodule update --remote
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From git.coding.net:genffy/repoA
   9e46893..c19e6fe  master     -> origin/master
Submodule path 'lib_modules/repoA': checked out 'c19e6fea3b148595a092979d8bd51ba98d8ebff4'

就能看到已经同步了,然后在这个 commit 提交,保证 submodule 的版本信息在主仓库中同步。这里其实有个坑的,详细参见 更新 submodule 的坑 的描述。唔同步原repoA的东西就没了。

更新

作为一个 team,时常为共用组件贡献代码也是件好玩的事。在 submodule 这中模式下,可以直接操作了。
还是上面两个 repo,这次直接在 git-submodules-action 更新。

➜  git-submodules-action git:(master) cd lib_modules/repoA
➜  repoA git:(a0e2b17) git branch -v
* (HEAD detached at a0e2b17) a0e2b17 fix confilct
  master                     a0e2b17 fix confilct
➜  repoA git:(a0e2b17) vi base.css
➜  repoA git:(a0e2b17) ✗ git status
HEAD detached at a0e2b17
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   base.css

no changes added to commit (use "git add" and/or "git commit -a")
➜  repoA git:(a0e2b17) ✗ git commit -a -m 'add green color '
[detached HEAD de05a18] add green color
 1 file changed, 3 insertions(+)
➜  repoA git:(de05a18) git push origin master
Everything up-to-date
➜  repoA git:(de05a18) git status
HEAD detached from a0e2b17
nothing to commit, working directory clean

然后在 repoA 中查看更新

➜  repoA git:(master) git branch -v
* master a0e2b17 fix confilct
➜  repoA git:(master) git fetch
➜  repoA git:(master)

啥?貌似并没有什么卵用对不对?嗯,这里就是一个比较大的坑了,详细参见 修改 submodule 的坑 的描述,当然这里也给出了解决方法,操作下

➜  repoA git:(de05a18) git status
HEAD detached from a0e2b17
nothing to commit, working directory clean
➜  repoA git:(de05a18) git checkout master
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  de05a18 add green color

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> de05a18

Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
➜  repoA git:(master) git cherry-pick de05a18
[master f004fa6] add green color
 Date: Wed Jul 6 01:38:34 2016 +0800
 1 file changed, 3 insertions(+)
➜  repoA git:(master) git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 343 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To [email protected]:genffy/repoA.git
   a0e2b17..f004fa6  master -> master

然后再到 repoA 下看下效果

➜  repoA git:(master) git fetch
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From git.coding.net:genffy/repoA
   a0e2b17..f004fa6  master     -> origin/master
➜  repoA git:(master) git pull
Updating a0e2b17..f004fa6
Fast-forward
 base.css | 3 +++
 1 file changed, 3 insertions(+)

嗯,这下同步和更行也就弄完了。

一个问题

其实,以上一路走下来其实还算是比较顺利的。真正困扰我的还有另外一个问题。比如我clone了别人的项目,执行了 rm -fr .git 的操作,然后 git init && git remote add origin <repo-url> 的操作,再执行上面的操作发现 submodule 无法自动更新,目前的解决方法是删掉 .gitmodules 重新开始😳
我想这应该是有更好的方法的吧?如过没有,那感觉又有的玩了,可以去看看 git 的代码了。

PS: 上面🌰的代码在 coding.net 上,分别是 repoA git-submodules-action 大家随便玩😊。

mac failed to install playwright-chromium

Why note this? PR's CI checked failed as i skipped install dependency and update pnpm-lock file, so i must to install it and update pnpm-lock file to pass CI.
PR's details: originjs/vite-plugin-federation#127

When install pnpm install playwright-chromium always pending like this:

node_modules/.pnpm/[email protected]/node_modules/playwright-chromium: Running install script...

The solution is try to manual install chromium and ffmpeg, the deitails: details:https://github.com/microsoft/playwright/blob/main/packages/playwright-chromium/install.js
The version's info and install details pls check this file: https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/utils/registry.ts

Manual Install

chromium

download it directly

ffmpeg

brew install ffmpeg

FYI: If you encounter such an error

tar: Error opening archive: Failed to open '/path/to/xxxx.tar.gz'
# tar --extract --no-same-owner --file /path/to/xxxx.tar.gz --directory /private/tmp/yyyyy

can try export HOMEBREW_BOTTLE_DOMAIN='' and rerun

Last

Rerun pnpm install playwright-chromium will be smoothly and worked.

Reference

为不同的 git repo 配置 ssh key 和 gitconfig

config ssh key and gitconfig for different git repo

对不同的邮箱生成不同的 ssh key

生成密钥对

# 设置公司的
ssh-keygen -t rsa -C "[email protected]" -f ~/.ssh/gitlab_rsa
# 设置默认的,一般都是给 gitlab 用的
ssh-keygen -t rsa -C "[email protected]"
# 查看生成的密钥对
ls -la ~/.ssh
# -rw-------    1 genffy  staff  2610 Feb 15 17:48 gitlab_rsa
# -rw-r--r--    1 genffy  staff   578 Feb 15 17:48 gitlab_rsa.pub
# -rw-------    1 genffy  staff  2602 Feb 15 17:51 id_rsa
# -rw-r--r--    1 genffy  staff   571 Feb 15 17:51 id_rsa.pub

创建配置文件

vim .ssh/config

填入以下内容

# gitlab.orgname.com
Host gitlab.orgname.com
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/gitlab_rsa
  User [email protected]

# github.com
#Host github.com
#  AddKeysToAgent yes
#  UseKeychain yes
#  IdentityFile ~/.ssh/github_rsa
#  User [email protected]

测试设置效果

ssh -T [email protected]
# Hi genffy! You've successfully authenticated, but GitHub does not provide shell access.
ssh -T [email protected]
# Welcome to GitLab, @zhengfei.li!

配置不同的 git 目录使用不同的密钥

复制默认的 .gitconfig

cp .gitconfig .gitconfig-gitlab
cp .gitconfig .gitconfig-id

编辑不同的配置文件的 user 信息

vim .gitconfig-gitlab
[user]
	name = zhengfei.li
	email = z[email protected]
	signingkey = ~/.ssh/gitlab_rsa.pub
[pull]
	rebase = false
[filter "lfs"]
	process = git-lfs filter-process
	required = true
	clean = git-lfs clean -- %f
	smudge = git-lfs smudge -- %f
[init]
	defaultBranch = main
[commit]
	gpgsign = true
[gpg]
	format = ssh
vim .gitconfig-id
[user]
	name = genffy
	email = g[email protected]
	signingkey = ~/.ssh/id_rsa.pub
[pull]
	rebase = false
[filter "lfs"]
	process = git-lfs filter-process
	required = true
	clean = git-lfs clean -- %f
	smudge = git-lfs smudge -- %f
[init]
	defaultBranch = main
[commit]
	gpgsign = true
[gpg]
	format = ssh

设置不同仓库目录使用不同 .gitconfig

vim .gitconfig
[includeIf "gitdir:~/workspace/"]
	path = .gitconfig-id
[includeIf "gitdir:~/Documents/workspace/"]
	path = .gitconfig-gitlab

最后可以在不同的目录下,修改下代码提交测试效果

前端er该知道的一些关于Nginx的事

“NGINX是一个免费的,开源的,高性能的HTTP服务器和反向代理,以及一个IMAP / POP3代理服务器。 NGINX以其高性能,稳定性,丰富的功能集,简单的配置和低资源消耗而闻名。

NGINX是为解决C10K问题而编写的少数服务器之一。 与传统的服务器不同,NGINX不依赖线程来处理请求。 相反,它使用更加可扩展的事件驱动(异步)架构。 这种架构使用小的,但更重要的是,在负载下的可预测的存储器量。 即使您不希望处理数千个并发请求,您仍然可以从NGINX的高性能和小内存占用中受益。 NGINX在所有方向上扩展:从最小的VPS一直到大集群的服务器。”

前言

据统计,就大家所知道web server中,Nginx的使用率占到了30%多,Nginx 的轻量、高效、高扩展性等特性越来越受到web开发者的青睐,不仅仅用作web服务器,向负载均衡、反向代理、分析统计、网络安全等方向都很多的实践和应用。

既然Nginx这么牛逼,但是跟我们前端开发来说又有什么关系呢?能给我们提供什么便利,以至于我们需要去了解它呢?

对于前端,大多数时候是不需要去了解关于web server相关的知识的,前端基本的开发都是静态的,最多只需要一个静态文件服务器即可,很多的 Node 小工具就提供了静态文件服务器的功能,比如 anywhere,http-server,webpack-dev-server,一个命令就能帮我们做好了。在这点上,Nginx能做的跟大伙儿差不多,除了能多配置点缓存、http头、端口映射之类的。

在前后端分离盛行的今天,有个痛点是很多前端er遇到的问题,那就是跨域,众所周知跨域的根源是源自浏览器的“同源策略”,以至于javascript在浏览器中无法加载其他域的对象或者数据。对于各种乱七八糟的跨域问题,解决方法很多,W3C还为此专门出了一个CORS(跨域资源共享)标准,这是一个比较完美的方案,在服务器端配置一个HTTP请求头Access-Control-Allow-Origin即可。但是在解决跨域的过程中,还有很多的痛点的,比如比较常见的Cookie问题。

对于以上说的两点,我们只需要Nginx就能帮我们轻松搞定,废话说了这么多,下面我们就简单实践下是如何做到的。

实验拓扑

domain name port desc
demo.com web 8082 主站
api.demo.com api 9000 api 服务器(web server)
static.demo.com static 8083 静态文件服务器(css,image,javascript)
stream.demo.com stream 8084 测试负载均衡

静态文件服务器

静态文件服务器,顾名思义其主要作用是提供静态资源的访问,直接返回访问 URL 请求的内容即可。很多包含有 HTTP 模块的编程语言都能搭建一个简单的静态文件服务器,比如:
PHP
利用其内建的 web服务器 ,很简单的就创建了一个8000端口的静态文件服务器,只可用于开发环境。

$ php -S localhost:8000

Node

// reference https://gist.github.com/ryanflorence/701407
var http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs")
    port = process.argv[2] || 8888;

http.createServer(function(request, response) {

  var uri = url.parse(request.url).pathname
    , filename = path.join(process.cwd(), uri);
  
  path.exists(filename, function(exists) {
    if(!exists) {
      response.writeHead(404, {"Content-Type": "text/plain"});
      response.write("404 Not Found\n");
      response.end();
      return;
    }

    if (fs.statSync(filename).isDirectory()) filename += '/index.html';

    fs.readFile(filename, "binary", function(err, file) {
      if(err) {        
        response.writeHead(500, {"Content-Type": "text/plain"});
        response.write(err + "\n");
        response.end();
        return;
      }

      response.writeHead(200);
      response.write(file, "binary");
      response.end();
    });
  });
}).listen(parseInt(port, 10));

console.log("Static file server running at\n  => http://localhost:" + port + "/\nCTRL + C to shutdown");

GO

// reference https://gist.github.com/paulmach/7271283
package main

import (
	"flag"
	"log"
	"net/http"
)
func main() {
	port := flag.String("p", "8100", "port to serve on")
	directory := flag.String("d", ".", "the directory of static file to host")
	flag.Parse()

	http.Handle("/", http.FileServer(http.Dir(*directory)))

	log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
	log.Fatal(http.ListenAndServe(":"+*port, nil))
}

就像上面所看到的,对于编程语言本身构建一个web服务器并不难,但是对于业务本身的帮助其实不是很大。最关键的是,对于静态文件件服务器来说,在生产环境中还会加上缓存,压缩,等一系列的特性,如此加上nginx的高性能,使用nginx来搭建静态文件服务器是不二之选,且看下nginx是怎么做的。

server {
    # 设置需要监听的端口
    listen 8083;
    # 配置静态文件根目录
    root /Users/dpDev/Documents/github/vue-starter/dist/static;
    # 开启文件浏览的功能,生产环境需要关闭
    autoindex on;
    # 设置图片的缓存策略
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
         expires off;
    }
    # 设置静态资源的缓存策略
    location ~ .*\.(js|css)?$
    {
         expires off;
    }
    # ...... 继续添加其他配置
}

效果如下:
静态文件浏览图
有没有很简单?

反向代理

在电脑网络中,反向代理是代理服务器的一种。它根据客户端的请求,从后端的服务器(如Web服务器)上获取资源,然后再将这些资源返回给客户端。与前向代理不同,前向代理作为一个媒介将互联网上获取的资源返回给相关联的客户端,而反向代理是在服务器端(如Web服务器)作为代理使用,而不是客户端。客户端通过前向代理可以访问很多不同的资源,而反向代理是很多客户端都通过它访问不同后端服务器上的资源,而不需要知道这些后端服务器的存在,而以为所有资源都来自于这个反向代理服务器。(维基百科:反向代理)

另外,维基百科上也说了反向代理主要的用途有:

  • 加密和SSL加速
  • 负载均衡
  • 缓存静态内容
  • 压缩
  • 减速上传
  • 安全
  • 外网发布

上面说的那些点,对于前端er来说属于比较高阶的内容了,看客们稍微了解下就好,对于前端er来说,主要是想利用反向代理来解决跨域的问题,下面看个例子:
业务场景:一个前端应用部署在domainA上,有一个数据请求是从domainB上获取
常规情况下会出现这样的问题:
出现跨域错误图
大家都知道,这就是典型的发生了跨域的问题。针对出现跨域的问题解决方案就不赘述了,这里简单说下通过一行简单的配置解决这问题。

server {
    listen 8082;
    index index.html;
    root /Users/dpDev/Documents/github/vue-starter/dist;
    # proxy
    # 当访问 http://demo.com/demo/ 时,会被代理到 http://api.demo.com/demo/ 
    # 就实现了一个简单的反向代理的功能
    location /demo/ {
       proxy_pass http://api.demo.com/demo/;
       proxy_set_header  X-Real-IP  $remote_addr;
    }
    access_log  /usr/local/etc/nginx/logs/demo.access.log;
}

重启下nginx,然后再看下结果,完美解决。
添加代理之后的请求图
除此之外,还能针对该代理设置其他的请求头信息。
Note:

  1. 如果有条件的,利用CORS规范在服务端设置Access-Control-Allow-Origin会更加方便些
  2. 在日常开发中,如有这种加载第三方数据的需求,最好沟通好,给该类请求加上一个prefix,比如http://domain/api/...这样方便做统一配置

负载均衡

对于互联网服务,负载平衡器通常是一个软体程序,这个程序侦听一个外部端口,互联网用户可以通过这个端口来访问服务,而作为负载平衡器的软体会将用户的请求转发给后台内网服务器,内网服务器将请求的响应返回给负载平衡器,负载平衡器再将响应发送到用户,这样就向互联网用户隐藏了内网结构,阻止了用户直接访问后台(内网)服务器,使得服务器更加安全,可以阻止对核心网络栈和运行在其它端口服务的攻击。(维基百科:负载均衡_(计算机))

在nginx中主要通过upstream这个模块来实现负载均衡的目的,upstream是Nginx的HTTP Upstream模块,这个模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。
通过nginx来配置负载均衡也很简单,直接看例子:

upstream mySvr {
  server 127.0.0.1:8082 weight=2;
  server 127.0.0.1:8000 weight=5;
}
server {
  listen 8084;
  server_name _;
  index index.html;
  location / {
    proxy_pass http://mySvr;
  }
}

然后我们请求http://stream.demo.com/看效果
负载均衡动图

调度算法

Nginx的负载均衡模块目前支持5种调度算法,下面进行分别介绍,其中后两项属于第三方调度算法。

  • 轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。
  • ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。
  • 基于权重。weight是设置权重,用于后端服务器性能不均的情况,访问比率约等于权重之比。
  • fair。这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。
  • url_hash。此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。

upstream 支持的状态参数

在HTTP Upstream模块中,可以通过server指令指定后端服务器的IP地址和端口,同时还可以设定每个后端服务器在负载均衡调度中的状态。常用的状态有:

  • down,表示当前的server暂时不参与负载均衡。
  • backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。
  • max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。
    NOTE,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup。

location规则

以上几个例子都用到了一个nginx中比较常见的location配置,下面简单说一下location配置后面url的规则:

location  = / {
  # 精确匹配 / ,主机名后面不能带任何字符串
  [ configuration A ]
}
location  / {
  # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
  # 但是正则和最长字符串会优先匹配
  [ configuration B ]
}
location /documents/ {
  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration C ]
}
location ~ /documents/Abc {
  # 匹配任何以 /documents/Abc 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration CC ]
}
location ^~ /images/ {
  # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
  [ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
  # 匹配所有以 gif,jpg或jpeg 结尾的请求
  # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
  [ configuration E ]
}
location /images/ {
  # 字符匹配到 /images/,继续往下,会发现 ^~ 存在
  [ configuration F ]
}
location /images/abc {
  # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
  # F与G的放置顺序是没有关系的
  [ configuration G ]
}
location ~ /images/abc/ {
  # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
    [ configuration H ]
}
  • 以 = 开头表示精确匹配
  • 如 A 中只匹配根目录结尾的请求,后面不能带任何字符串
  • ^~ 开头表示uri以某个常规字符串开头,不是正则匹配
  • ~ 开头表示区分大小写的正则匹配
  • ~* 开头表示不区分大小写的正则匹配
  • / 通用匹配, 如果没有其它匹配,任何请求都会匹配到

以上,大概介绍了下关于nginx的一些简单的用法,如有发现不妥,欢迎指正批评。

PS:对于前端er来说,最熟悉还是Node了,顺便推荐几款比较常用的Node的静态文件服务器

[vue3] vue-cli vs vite 两者配置对比

[email protected]

vite用的实在是太爽,但是由于不可抗力的因素(qiankun 亮点依赖 import-html-entry 不支持 type="module" 的问题,参见 issue #756#1024),被迫做了一次构建的改造,从 vite 换成了 @vue/cli,准确来说只是 build 的时候用了@vue/cli,开发环境可控,实在不想失去vite 那么流畅的开发体验。

Dotenv

两者默认加载的变量前缀不一样,viteVITE_vue-cliVUE_APP_,所以你的 .env 文件可能长这样

NODE_ENV=production
VITE_SYS_AUTH_CODE=99865f3f4f2a4f3ebe0b9f94528f72d7
VUE_APP_SYS_AUTH_CODE=99865f3f4f2a4f3ebe0b9f94528f72d7

获取ENV变量的方式也不一样,在 vite 里面是 import.meta.env,在 @vue/cli 里面是 process.env

update 11/09/2022

为了磨平开发环境下的差异性,可以稍微修改下 vite.config.ts ,让 env 的获取统一

import { defineConfig, loadEnv } from 'vite'
import type { UserConfigExport, ConfigEnv } from 'vite'

export default ({ mode }: ConfigEnv): UserConfigExport => {
  process.env = { ...process.env, ...loadEnv(mode, process.cwd(), 'VUE_APP_') }
  return defineConfig({
    define: {
      'process.env': JSON.stringify(process.env),
    },
  })
}

所以一个比较好的实践是,在平时开发的时,把这些配置都放到一个地方统一管理,切换也就是一个 if else 的事情

Entry File

vite 下默认是读 index.html 里面 <script type="module" src="/src/main.ts"></script> 标记,而 @vue/cli 里面是通过 vue-config.js 里面的 pages 处理

Pkg script

{
 "pro:vite": "node_modules/.bin/vite build",
 "pro:cli": "node_modules/.bin/vue-cli-service build"
}

devDependencies

在我的项目里,其实主要只增加了

"@babel/plugin-proposal-optional-chaining": "^7.12.17"
"@vue/cli-plugin-babel": "~4.5.0"
"@vue/cli-plugin-eslint": "~4.5.0"
"@vue/cli-plugin-typescript": "~4.5.0"
"@vue/cli-service": "~4.5.0"

以及对应的 CSS 文件处理 loader,这里要注意,如果用的是 less,对应的 loader 版本要注意看下,latest 版本是为 webpack5 准备的

"less": "^4.1.1",
"less-loader": "^7.3.0",

Config

通过将 devServer alias 等这些相同的配置抽取出来后,其实差异不大,但是开发模式下速度差几十个数量级

vue.config.js

/* eslint-disable @typescript-eslint/no-var-requires */
const { name } = require('./package.json')
const { baseUrl, devServer, alias } = require('./config')

module.exports = {
  publicPath: baseUrl,
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${name}`,
    },
    resolve: {
      alias,
    },
  },
  pages: {
    index: {
      entry: 'src/main.ts',
      template: 'index.html',
    },
  },
  devServer,
}

vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { baseUrl, devServer, alias } = require('./config')
export default defineConfig({
  plugins: [vue()],
  base: baseUrl,
  resolve: {
    alias,
  },
  server: devServer,
})

在 build 模式下,两者的速度差别其实不大。

EOF

Web Dev Streams

Q: 请列一个“介绍 web 开发中 stream 技术的使用”文章的提纲

I. 引言

介绍stream技术的背景和意义
II. 什么是stream技术

介绍stream技术的概念和定义
III. stream技术的应用场景

分析stream技术在web开发中的应用场景,如数据传输、大文件上传和下载等
IV. stream技术的优点

分析stream技术相较于传统web开发技术的优点,如降低内存消耗、提高性能等
V. stream技术的实现方式

介绍stream技术的实现方式,如Node.js中的stream模块
VI. stream技术的实际应用

分析stream技术在实际web开发中的应用案例,如实现文件压缩、实时音视频流等
VII. stream技术的未来

分析stream技术在未来web开发中的发展趋势和应用前景
VIII. 结论

总结stream技术在web开发中的作用和应用价值,强调它对web开发的重要性。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.