尝试用 WSL2 + Ubuntu 开发

目的

用 WSL2 模拟 Linux 开发环境,然后用 Linux 开发项目,熟悉各种 Linux 系统和命令,为以后成为大神埋下习惯的种子

前言

可不看

笔者是 Window 用户,去年真正学 Linux,以前也用过虚拟机开发,也有过各种尝试,但因为各种原因,还是回归 Window 开发

去年看到方应杭的直播开发,了解到 docker + VS code 的开发模式,而后就写了 手把手提高开发体验:dev-container,配置好后我没有继续研究,没有马上把环境切换成,直到最近,换电脑,才想着就用 Linux 开发吧

正文

什么是 WSL

Window 中的 Linux 系统,Window 提供的内置虚拟机

所以我们可以在 Window 中安装 Ubuntu、Centos 等 Linux 系统

但他的缺点是文件系统和 Window 不一致,但可以共享

说白了,如果你在 Linux 中操作 Window 中的文件,会卡顿。反之亦然

WSL、docker、Window 的虚拟机(Hyper-v)的关系相当于,Window 用 Hyper-v 实现了虚拟机,也就是 WSL,window 中的 docker 也是基于此技术来实现容器化的

省流版

修改默认安装目录到 D 盘

更换阿里云软件源

更新软件

安装 oh my zsh

配置 ssh

node 环境

ruby 环境

修改默认安装目录到 D 盘

wsl --help # 查看文档
wsl --list # 查看启动的 wsl 数量
wsl --list --verbose # 列出已安装的 Linux 发行版
wsl --set-default-version <Version> # 设置默认 WSL 版本
wsl --set-default <Distribution Name> # 设置默认 Linux 发行版
wsl --shutdown # 关闭 wsl
wsl --export <Distribution Name> <FileName> # 导出
wsl --unregister Unbuntu-18.04 # 注销当前分发版
wsl --import <Distribution Name> <InstallLocation> <FileName> # 导入
ubuntu1804 config --default-user johan # 设置默认登陆用户

同理,可以把 docker 也放到 D 盘中

更多命令可以前往官网查看

更换阿里云软件源

1.备份

sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

2.修改

sudo vim /etc/apt/sources.list

将 source.list 文件内容替换成下面的

deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse

更新软件

sudo apt update && sudo apt upgrade -y

安装 oh my zsh

安装 zsh

sudo apt install zsh -y

安装 ohmyzsh

sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

安装 ohmyzsh 插件,按照自己的喜好

可以看看 antfu 的配置

git clone https://github.com/denysdovhan/spaceship-prompt.git "$ZSH_CUSTOM/themes/spaceship-prompt" --depth=1
ln -s "$ZSH_CUSTOM/themes/spaceship-prompt/spaceship.zsh-theme" "$ZSH_CUSTOM/themes/spaceship.zsh-theme"

进入 .zshrc 文件,并修改成ZSH_THEME="spaceship",并让配置立马生效 source ~/.zshrc

将 ohmyzsh 设置为默认编辑器

chsh -s $(which zsh)

配置 ssh

生成 github 公钥

ssh-keygen -t rsa -C "t511069160@qq.com" -f "~/.ssh/id_rsa_github"

生成 gitlab 公钥

ssh-keygen -t rsa -C "XX" -f "~/.ssh/id_rsa_gitlab"

配置 config 文件

Host github
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_github

Host 10.110.119.233
HostName 10.110.119.233
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_gitlab

测试是否配置成功

ssh -T git@github.com
ssh -T git@10.110.119.233

node 环境

使用 nvm 来控制 node 版本,因为有些老项目还在用 14 版本的

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash

如果说安装失败或者安装很慢,就在 /etc/hosts 中将 raw.githubusercontent.com 域名映射下,具体方法可看GitHub520

将配置写进 .nvm 中

export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

再让配置立即生效source ~/.zshrc

nvm --version # 0.39.3
nvm install 16.19.1 # 下载 16.19.1 版本的 node
nvm list # 查看 node 列表
nvm use 16.19.1 # 使用 16.19.1 版本的 node

nvm下载

ruby 环境

使用 rvm 来管理 ruby,安装文档参考官网

安装 GPG keys

gpg2 --keyserver keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB

报错:

没有gnupg2库

先下载 gnupg2

apt install grupg2 -y

grupg2 安装好了,就重新 GPG keys。再安装 rvm

curl -sSL https://get.rvm.io | bash -s stable

安装结果

安装好后,我们需要修改 ruby 安装源,来提高安装速度

 echo "ruby_url=https://cache.ruby-china.com/pub/ruby" > /usr/local/rvm/user/db

看截图中的绿色字,RVM 安装的路径

使 rvm 命令生效

source /usr/local/rvm/scripts/rvm

此时,rvm -v 就能看到 rvm 1.29.12(latest)...

安装 ruby

rvm install ruby-3.1.3
rvm list known:#查看
rvm list:#查看
rvm use 3.1.3 --default #使用 3.13 为默认版本的
ruby -v # ruby 3.1.3p185

安装 rails

gem install rails --verbose # --verbose 可以查看进度
rails -v # 7.0.4

遇到的问题(一)

之前用 curl -sSL https://get.rvm.io | bash -s stable 安装完后,使用gem install railscommand not found ubuntu,解决不了,后来尝试了各种方法安装,例如下载源码,例如用sudo apt-get install ruby-full,后来都不是很好使

可怪自己 linux 基础太差,英语又不好,下载完 rvm 后,它已经提示了,让我切换用户并重新登录

安装完rvm后的提示

而我第二次安装的契机是不死心,还是想用 rvm 安装,然后就想到先卸载,再重新安装

发现了 apt-get purge rvmapt-get remove rvm 等命令,第二次安装我用了 sudo 命令,安装地址改成了 /usr/shar/rvm

删除 rvm

sudo apt-get purge rvm

重新安装

curl -sSL https://get.rvm.io | sudo bash -s stable

第一步,将正在用的用户添加到 rvm 组中

sudo usermod -a -G rvm johan

第二步,注销-再次登录

我的办法比较土,先切换到 root,再切回来

su root
su johan

第三步,运行生效命令

source /etc/profile.d/rvm.sh

这样就安装成了

遇到的问题(二)

因为在 WSL 中开发,但是有时候要用手机来查看样式问题,所以需要在手机端访问,但是 WSL 启动的服务,手机端访问不了。笔者对网络方面的知识不了解,也不想了解。按照从局域网访问 WSL2 这篇文章的操作来做

先开启对应端口防火墙,再将 WSL 上的 ip 、端口映射到本地

后续

做事情都要有所目的,当初写 手把手提高开发体验:dev-container 时,想着把环境配置成一致,方便项目部署。但发现所占内存太大,笔记本(12G)带不动。现如今新电脑(32G)虽然可以用此方法来开发,但笔者的目的变了,笔者现如今想学的是 Linux 、bash,使用 WSL 能随时随地接触它,熟悉它,习惯它

开发还是用 WSL ,但是写东西,例如写博客之类的还是会依赖于 Windows,所以真不如别人说的还不如买一台 mac 呢

参考资料

芝麻开门,显示全文!

安装 docker 后无法启动

前言

好久没写文章了,一部分是忙了,另一部分是过年懒了,还有一部分是在学习 ruby,想搞个前端七天学 ruby 系列文章,敬请期待

正文

最近在部署 ruby 项目中,遇到了 docker 19 版本无法在两个容器中互联的问题,后升级 docker 至最新版本(23)解决,但升级完后之后,无法启动

可惜的很,没截图

当使用 docker --version 或者 docker ps 时,说没有启动

Failed to start Docker Application Container Engine.

通过systemctl status docker 启动 docker,报错

failed to start daemon: Error initializing network controller: Error creating default "bridge" network

没启动 bridge 网络

firewall-cmd --permanent --zone=docker --change-interface=docker0
# 防火墙加入 docker0
firewall-cmd --reload
# 重启防火墙

这样 docker 就正常运行了

参考资料

芝麻开门,显示全文!

前端路由hash、history的实现

前言

这个坑,已经埋在笔者的待办事项里很久,就好比一滴酱油滴在白色的桌子上,现在有时间了,很想把它“擦掉”

正文

前端路由实现有两种,一是 hash,另一种是 histroy。

hash 原本是为了定位,笔者印象中最开始是 PC 端商城的楼层,点击跳转到某一模块

history 是 HTML5 新出的 API,它属于 bom。通过 history 对象可以操作浏览器的会话历史以及向前向后跳转

笔者是 React 开发者,Vue 好久没用了,所以以下内容是以 React 的角度描写

前端开发——React 全家桶——路由采用第三方库 react-router 和—— react-router 的底层是 history

我们在写 react 的路由写法时,通常为两种,hash 和 history ,使用它的本质是 history 库

笔者在这里写个简单的

hash 模式

它的本质是通过监听hash变化事件来修改路由内容

<body>
  <a href="#/home">Home</a>
  <a href="#/user">User</a>
  <a href="#/about">About</a>
  <div id="view"></div>
</body>
<script>
  function onHashChange() {
    const view = document.getElementById("view");
    switch (location.hash) {
      case "#/home":
        view.innerHTML = "Home";
        break;
      case "#/user":
        view.innerHTML = "User";
        break;
      case "#/about":
        view.innerHTML = "About";
        break;
      default:
        view.innerHTML = "Home";
        break;
    }
  }
  window.addEventListener("hashchange", onHashChange);
</script>

hash模式

history 模式

看了 hash 模式,我们会觉得很简单,无非是监听 hash 的变化,现在我们再看 history 模式

<body>
  <a href="/home">Home</a>
  <a href="/user">User</a>
  <a href="/about">About</a>
  <div id="view"></div>
</body>
<script>
  const elements = document.querySelectorAll("a[href]");
  elements.forEach((el) =>
    el.addEventListener("click", (e) => {
      e.preventDefault();
      const test = el.getAttribute("href");
      history.pushState(null, null, el.getAttribute("href"));
      onPopState();
    })
  );

  function onPopState() {
    const view = document.getElementById("view");
    switch (location.pathname) {
      case "/home":
        view.innerHTML = "Home";
        break;
      case "/user":
        view.innerHTML = "User";
        break;
      case "/about":
        view.innerHTML = "About";
        break;
      default:
        view.innerHTML = "Home";
        break;
    }
  }
  window.addEventListener("popstate", onPopState);
</script>

无非是把 hashchange 改成了 popstate,当 history 对象变化时,会出发 onPopState 事件,而我们的 history 模式不想 hash 模式那样,点击hash 对象时(#xx)会自动监听,所以我们遍历监听路由点,点击时实现和 hash 一样的模式,即点击时往历史中添加一条记录

线上demo:

芝麻开门,显示全文!

手把手提高开发体验:dev-container

之前看过方应杭的一期工作流视频,讲他是如何配置开发环境的。讲真,这期视频给我一丝震撼,原来不用虚拟机也能在 linux 上开发,但是它的配置过于复杂,我想配置一套自己的一套开发环境

视频中的 remote-container 已经更名为 dev-container,而 0.245.2 以上版本的 dev-container 有问题,会报”An error occured setting up the container - Remote Docker”,在 Issues 中有人给出了方法是降级到 0.245.2

当降级到 0.245.2,就可以愉快的使用 dev-container 了

现在我们已经成功了 dev-container 插件

现在我们要做的是,通过 dockerfile 生成一个 linux 容器,并在这个容器中开发

小试牛刀

FROM centos:8

RUN uname -a

RUN cat /etc/os-release

我们基于 centos:8 来构建一个镜像,其中,打印系统名和查看系统

基于centos的镜像

点击添加终端,就进入容器中了,这个容器就是我们基于 vscode 的 dev-container 插件

vscode中的linux

如果只是个裸机,是万万不行的,我们需要安装一些开发环境和应用,提高我们的开发效率

更新所有包

在更新包之前,我们要先修改 centos 的镜像源

RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*

修改成国内的镜像,再更新包

RUN yum update -y

下载 vim

先下载 vim

RUN yum install vim -y

如何配置,怎么配置 vim,介于还处于新手阶段,就常规操作即可,不用配置什么

下载 oh-my-zsh

如果冒冒失用它官网的下载链接,会报错

RUN sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
# curl: (7) Failed to connect to raw.githubusercontent.com port 443: Connection refused

意思是说 Github 的 raw.githubusercontent.com 域名解析污染,访问不了

解决方法有不少,如通过修改 hosts 解决此问题,先在 ipaddress查询 raw.githubusercontent.com 的真实 IP,在修改 hosts

vim /etc/hosts

添加199.232.68.133 raw.githubusercontent.com

hosts文件

重新下载 zsh

sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

zsh安装成功

这方法只能在 linux 中使用,如果你要用 dockerfile 中修改 /etc/hosts,就行不通,因为 /etc/hosts 文件是只读的,笔者在这里花了不少时间想解决,但还是没找到解决方法

还有一种方法是修改下载源,换成国内地址

sh -c "$(curl -fsSL https://gitee.com/mirrors/oh-my-zsh/raw/master/tools/install.sh)"

并将默认命令行修改成 on-my-zsh

RUN chsh -s /bin/zsh

但这个方法需要两个前提,一是需要下载 git

RUN yum install git -y

二是因为 centos 8 系统中并未带 chsh 命令工具,会提示 chsh: command not found,原因是系统没有自带的 util-linux-user 工具包导致,所以在执行 chsh 命令前,先安装它

RUN yum install util-linux-user -y

如此,我们就配置好了一个基于 centos 的有 vim、on-my-zsh 的 linux 环境

完整的 dockerfile 如下所示:

FROM centos:8

RUN uname -a

RUN cat /etc/os-release

# 修改镜像源
RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*

# 更新系统
RUN yum update -y

# vim
RUN yum install vim -y

# chsh
RUN yum install util-linux-user -y

# git
RUN yum install git -y

# oh-my-zsh
RUN yum install zsh -y
RUN sh -c "$(curl -fsSL https://gitee.com/mirrors/oh-my-zsh/raw/master/tools/install.sh)"

RUN chsh -s /bin/zsh

光有这些不够,还要下载前端环境、如 node 、pnpm,还有后端环境,笔者最近也对 ruby 很感兴趣,也会在这里安装 ruby 环境

前端环境

我们采用 nvm 来控制 node 版本

安装 nvm 的方式有很多种,像方应杭是下载源码,再拷贝到容器中,如果没有网络限制,也可以用 curl 下载等等,我采用的是 git install

ENV NVM_DIR /root/.nvm
RUN git clone https://github.com/nvm-sh/nvm.git /root/.nvm/
# RUN git checkout v0.39.3
RUN sh ${NVM_DIR}/nvm.sh &&\
	echo '' >> /root/.zshrc &&\
	echo 'export NVM_DIR="$HOME/.nvm"' >> /root/.zshrc &&\
	echo '[ -s "${NVM_DIR}/nvm.sh" ] && { source "${NVM_DIR}/nvm.sh" }' >> /root/.zshrc &&\
	echo '[ -s "${NVM_DIR}/bash_completion" ] && { source "${NVM_DIR}/bash_completion" } ' >> /root/.zshrc

再通过 nvm 下载最新版本的 node

RUN nvm install stable

但是这样会报错,说 nvm: command not found,为什么这样,不求甚解,去找另一种解决方法

笔者选择先安装个默认版本的 node 和 npm,按照这里的包管理安装

RUN dnf module install nodejs:16

默认dnf module install nodejs 会安装 v10 版本,太低了,最高 16,选新不选久

再下载 pnpm ,将其设为包管理器

RUN curl -fsSL https://get.pnpm.io/install.sh | sh -

如此一来,前端的开发环境以及 node 环境就在这个 dockerfile 中了

ruby 环境

我找的教程是这个,日本人做的,内容很齐全,按照步骤,能运行好环境

RUN dnf module install ruby:3.0 -y
RUN gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/
RUN curl https://dl.yarnpkg.com/rpm/yarn.repo > /etc/yum.repos.d/yarn.repo
RUN dnf -y install ruby-devel rpm-build make gcc gcc-c++ gcc-gdb-plugin libxml2 libxml2-devel mariadb-devel zlib-devel libxslt-devel
RUN gem install nokogiri -- --use-system-libraries
RUN gem install rails --version="~>7.0"

如此一来,我们的开发环境就初步弄好了,我将它发布到 dockerhub 上,如果有需要,可以以此改造

总结

这篇文章花了我不少时间,主要很多 linux 知识点为涉猎过,之前也没在虚拟机上配置 linux 的经验。不过还好,算完成了,如此一来,开发时就可以用 vscode + linux 开发应用了,剩下的就是熟悉它

参考资料

芝麻开门,显示全文!

从面试题到插件机制的小思考

起初是因为一道面试题,这个面试题是去年遇到的,即如下代码:

class Operator {...}
var op = new Operator(1)

op.add(3).minus(2).multi(2).division(1)

写出 Operator 中的代码,当初不会写,因为完全没遇到过笔试写这类题目。当然,这也暴露了我基础薄弱的问题

现在,可以一解,其实很简单,add、minus、multi、division 都是 Operator 的方法,调用后能返回是因为返回了 this,this 指向调用者,所以还是指向实例(即 op)

class Operator {
  constructor(initial) {
    this.num = initial;
  }

  add(num) {
    this.num = this.num + num;
    return this;
  }

  minus(num) {
    this.num = this.num - num;
    return this;
  }

  multi(num) {
    this.num = this.num * num;
    return this;
  }

  division(num) {
    this.num = this.num / num;
    return this;
  }
}

var op = new Operator(1);
op.add(3).minus(2).multi(2).division(1);

注意,一定要 return,你调用一个方法,不 return,就不会有结果。一般你调用方法总是要有返回值吧

再次提醒,能链式调用的关键在于调用方法后返回 this,this 指向调用者即实例

而此类又能衍生思考一个问题,库的「插件」机制

无论是 Chrome 中的插件,还是 PhotoShop 中的插件,还是 Webpack(前端打包库) 中的插件,还是 jQuery、Axios、BetterScroll 等库的插件,在写应用程序时,为了扩展性,我们都会使用“插件思维”,把核心的功能实现出来,再通过插件机制来扩展自身

多说无益,如果使用插件机制来实现此功能,该如何改造呢?

class Operator {
  plugins = [];
  constructor(initial) {
    this.num = initial;
  }

  use(plugin) {
    this.plugins.push(plugin);
    this[plugin.name] = plugin.exec.bind(this);
  }

  // 这里加一个方法,调用显示结果
  result() {
    return this.num;
  }
}

const AddPlugin = {
  name: "add",
  exec: function (num) {
    this.num = this.num + num;
    return this;
  },
};

const minusPlugin = {
  name: "minus",
  exec: function (num) {
    this.num = this.num - num;
    return this;
  },
};

const op = new Operator(5);
op.use(AddPlugin);
op.use(minusPlugin);
op.add(5).minus(2).result(); // 8

我们打印 op 能看到方法 add、minus 都作用到实例上了

实例op

当然,这只是冰山一角,如果说到如何写库,按照现代 JavaScript 库的写法要考虑的东西还有很多,等笔者对其研究有所收获后,会写一篇

芝麻开门,显示全文!

记录服务器内存爆炸

最近在准备全栈项目,本想拿以前的项目练练手,一测试,发现有bug。遂修改代码,推到远程仓库,登录服务器,拉代码时,报错,说error: unable to create temporary file: No space left on device,意思是说「无法创建临时文件:设备上没有剩余空间」

纳尼~~

我的小服务器上都没挂什么服务啊,为什么会没内存了

不管怎么样,先查一下

有人也遇到这样的问题:解决Linux出现“cannot create temp file for here-document: No space left on device”的问题

解决方案:

1、df -h 查看硬盘空间

2、top 查看cpu及内存

3、du -h –max-depth=1 /var/log/* 查看/var/log路径下文件的大小

4、du -sh /* 查看哪个目录最大

5、cat /dev/null > /var/log/mongodb/mongod.log 清空mongodb日志文件

使用 df -h 查看硬盘的空间,发现全被/dev/vda1 占据了

查看硬盘空间

而后面又有个 overlay,也是 40G,不明白没关系,继续往后步骤找

第二、三步没啥用,主要是第四步。现在根目录下输入du -sh * ,发现 var 目录占了36个G,不得了

查看根目录下的各文件所占内存

进入 var 目录查询du -sh *,发现 lib 目录占了 35G

var目录下的各文件所占内存

继续进入 lib 目录,查询du -sh *,发现 docker 目录占了 35G。明白了,问题出在 docker 容器上,也许是镜像,也许是容器,所占的内存太大了

那就把没用的镜像和容器删除吧

删到后面发现是启动的 check 酱容器占满了内存,删除了这个容器后,内存就恢复了

删除内存吸盘后的内存

check 酱或许是写入了什么错误日志之类的,导致占满了内存。想想,也就不用

为此,也不去纠结,再说了,这个服务个人感觉并不是很好用,老是报错

学到的东西

主要是 linux 的操作

例如:

  • df -h:查看硬盘空间
  • du -sh *: 查看哪个目录最大

芝麻开门,显示全文!

Docker 内部DNS解析失败

最近在玩 Easy 的开源应用:check 酱,按照它的教程,我启动了云端检测,但出问题了

监听报错

提问 Easy

提问 Easy

笔者比较菜,不知道他说的 「DNS 解析有问题」 指的是什么?

我当时的理解是 DNS 不是和域名有关吗,我外网能访问啊

后来他重要的话说三次之后,我思考了下,想着是我容器内部的 DNS 解析失败,一查,果然是这样

docker容器中ping不通

在容器中,能 ping 的通 ip,但是不能 ping 域名

找了一圈,有让我重启 docker 服务的,有说让我修改/etc/docker/daemon.json 添加 dns 解析的,还有一些指导,但都无济于事

到最后想到用英文解决,一搜”Docker containers can’t resolve DNS on centos“

答案就有了——Containers cannot resolve DNS in CentOS

原来是防火墙做了拦截,只要把 docker 添加为防火墙的信任接口中就能解决

firewall-cmd --permanent --zone=trusted --add-interface=docker0 # 添加 docker 至信任接口
firewall-cmd --reload # 重载

ping通了

如此就解决了,果然,还是要靠英文啊

Check 酱能做什么

check 酱是一个通用网页内容监控工具,可以监测网页内容变化,并发送异动到微信

如果在云端架上服务,那么只要检测数据,满足条件后的就会通知到我的微信

我会拿它干什么呢?

我觉得最好的用处就是检测加密货币的数据,当满足某个价格,某个指标后,提醒自己

减少看盘,回归生活才是正道

check 酱的 B 站教程合集:https://www.bilibili.com/video/BV1JY4y1P71b

付费课程:https://next.ftqq.com/31

芝麻开门,显示全文!

网页长按保存及识别二维码

网易哒哒的 H5 一向是业界精品,其中不少 H5 会成为爆款,能在朋友圈广泛流传的那种。同时,他们还写了一本很水的书——制造爆款:H5营销策划一本通,草草介绍了下各式各样的H5,但相关的技术文章却都没这么介绍,笔者一直想仿做类似的H5,找来找去,也只找到两篇网易同厂的技术类文章:

就此,笔者做个简易H5,介绍一下个人认为H5中比较重要的功能点——长按保存图片及识别二维码

此项目主要用到三个库

前期准备

设计稿:魔改公司H5中的其中一页

字体:寻找开源字体,这款不错——LXGW WenKai / 霞鹜文楷

此外,就是布局,笔者在移动端法门:自适应方案和高清方案 中阐述过一个观点:

不同的布局方式作用不同,像新闻类的H5,采用 px 为单位,是为了让大手机看到更多的信息;像应用型的H5,采用 rem/vw 为单位,力求在各种手机上能保持一致UI

像营销页面,是希望在各种手机上保持UI一致,理论上采用 rem/vw 是没问题的,但是 ggvswild 在高质量前端快照方案:来自页面的「自拍」 中曾说:

为了给到html2canvas明确的整数计算值,避免因小数舍入而导致的拉伸模糊,建议将布局中使用中使用%vwvhrem等单位的元素样式,统一改为使用px

而笔者在实际项目开发时,采用 rem 为单位并没有发现拉伸模糊问题。除此之外,笔者又寻找了几个网易的 H5

个人总结:在布局上它们都使用绝对定位布局,在长度单位上各有特色,所以做 H5 布局是无所谓用那种方式,只要在截图页不让元素拉伸即可,也就是说如果拉伸模糊了,可查一下此元素的单位是否是小数,至于其他页的布局,习惯用那个就用那个

实战开始

字体的运用

字体「 霞鹜文楷」大约4.4M,太大了,用 fontmin 提取用到的字体,这里我直接使用 Fontmin 的客户端,无它,命令行执行出错,营销页只用到了9个汉字,裁剪后从4.4M减少到 44kb

二维码功能的实现

很简单,看文档就能学会

var qrcode = document.getElementById("qrcode");
new QRCode(qrcode, {
  width: 200,
  height: 200,
  colorDark: "#000000",
  colorLight: "#ffffff",
  correctLevel: QRCode.CorrectLevel.L,
}).makeCode(window.location.href);

快照实现

将 html2canvas 和 canvas2image 结合,将 HTML 转成 base64 图片,而这一功能可以做成一个库:

var convertToImage = (function () {
  function createBaseCanvas(scale, width, height) {
    const canvas = document.createElement("canvas");

    canvas.width = width * scale;
    canvas.height = height * scale;

    const context = canvas.getContext("2d");

    // 关闭抗锯齿
    context.mozImageSmoothingEnabled = false;
    context.webkitImageSmoothingEnabled = false;
    context.msImageSmoothingEnabled = false;
    context.imageSmoothingEnabled = false;

    context.scale(scale, scale);

    return canvas;
  }

  function convertToImage(container, options = {}) {
    const scale = window.devicePixelRatio;

    const width = container.offsetWidth;
    const height = container.offsetHeight;

    const canvas = createBaseCanvas(scale, width, height);

    const ops = {
      useCORS: true, // 如果截图的内容里有图片,解决文件跨域问题
      allowTaint: false, // 是否允许跨源图像污染画布
      ...options,
    };

    return html2canvas(container, ops).then((canvas) => {
      const imageEl = Canvas2Image.convertToPNG(
        canvas,
        canvas.width,
        canvas.height
      );
      return imageEl;
    });
  }
  return convertToImage;
})();

使用:

convertToImage(document.querySelector("#capture")).then((imageEl) => {
  document.getElementsByClassName("save")[0].appendChild(imageEl);
});

canvas2image 的坑点

  1. 最新版本(1.4.1)已支持缩放,已解决图片不清晰的问题
    • 图片不清晰以前是个大问题,不少博文都有对其说明,目前的版本没看到模糊
  2. 文档上写支持 background-image:linear-gradient(),但是如果是渐变至透明是不行的

渐变背景色

而我希望呈现这样的样式:

背景图

背景渐变方案:

background-image: linear-gradient(90deg, $white, transparent);

改成背景图:

background: url("../bg.png") no-repeat;
background-size: 100% 100%;
  1. 文字会出现位移,这个问题至今一直存在,作者也没有修复

以上就是所遇到的问题,像跨域之类的问题,随着时间的推移,文档上都有说明,已经不是什么问题

线上预览地址:这里

2023.3.14 更新

文字会出现位移小爝 给出了方案html2canvas 文字向下偏移兼容方法,主要改动源码中的两点:

// var baseline = img.offsetTop - span.offsetTop +2;
var baseline = parseInt(getComputedStyle(span, null).lineHeight, 10) - 5;
_this.ctx.textBaseline = "alphabetic";

主要是修正字体的基准位移。给我开了一个思路,找不到解决方案就直接去找源码debugger

参考资料

芝麻开门,显示全文!

工作中使用 Git 解决问题的场景

简单来说,就这七点:

  • 使用 git rebase 让提交记录更加清晰可读

  • 使用 git reflog + git reset 跳到任意 commit

  • 使用 git cherry-pick 获取指定的 commit

  • 使用 git commit —amend 更改提交内容

  • 使用 git revert 回滚某次的提交

  • 使用 git stash 来暂存文件

  • 配置 git alias 提升工作效率

使用 git rebase 让提交记录更加清晰可读

rebase 基本用法

rebase 翻译为变基,它的作用和 merge 相似,用于把一个分支的修改合并到当前分支

如下图所示,经过 rebase 后提交历史的变化情况

rebase

不明白单分支的好处,可以在看看知乎的这个问题:Git commits 历史是如何做到如此清爽的?

Vue 的作者尤雨溪就是说:多用 rebase

具体用法:

  • 基于 master 分支创建 feature 分支
  • 在 feature 分支上开发功能点
  • master 上也提交了 commit
  • 在 feature 分支上执行 git rebase master,意为以 master 分支最后的提交作为基点,逐个应用 feature 的每个更改

git rebase VS git merge

合并分支有两种,即 rebase 、merge

merge 翻译为合并,即 git merge branchname,即合并分支代码,这种方法会保存每次 commit 的,当你使用 gitk 查看时就发现好几条颜色的线

另一种是 rebase,即去除一系列的提交记录,“复制”它们,然后在另一个地方逐个放下去

所以 rebase 的优势就明了了,它能创造更清晰的提交记录

但 merge 会保留你所有的 commit 的历史时间,当开发人员一多,历史记录就会变得混乱

rebase 的交互模式

在开发中,通常会在一个分支上产生很多无效的提交,这种情况下使用 rebase 的交互模式可以把多次 commit 压缩成一次提交,得到一个干净的提交历史

# 先看提交
git log
# f9f6f3b commit 3
# 2feb45f commit 2
# 07a3cb6 commit 1
# 我们要修改 2 的话,rebase 到它的下一个 commit,这里是 1
git rebase 07a3cb6 -i
# 然后在打开的对话框里面修改,之后还要一个 rebase continue
git rebase -i <base-commit>
# 或者是 git rebase -i HEAD~2 对最近的两次 commit 进行合并

也有人称之为后悔药功能,即你无论写什么 commit,最后都可以修改,无论提交什么,都可以合并,DIY 性强

使用 git reflog + git reset 跳到任意 commit

换个说法叫时光机,即通过查找所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作),通过 reset HEAD 跳到指定 commit

git reflog
#afa2f45 HEAD@{10}: checkout: moving from 今天 to 明天
#4abcda5 HEAD@{11}: commit: 打通1800处仙窍
#de42069 HEAD@{12}: commit: 真言轮经大成
git reset HEAD@{10}
# 或者 git reset --hard afa2f45

如此一来,就回到了 afa2f45 commit 处,熟悉「时间法则」、「时光机」的人都知道,这是回到过去

使用 git cherry-pick 获取指定的 commit

意为“挑拣”提交,和 merge 合并一个分支的所有提交不同,它会获取某个分支的单个提交,并作为一个新的提交接入到当前分支上

这个需要故事背景才容易理解

张三在分支上开发功能,每个功能点提交一次 commit,共六个提交六个功能点(分别是 feature1~feature6),再回到第一个提交点,即他使用 git reset --hard feature1 跳转第一个 commit,在此基础上开发一个新功能,即 feature7,那么如果把 feature7 合并到 feature6 上怎么做?

git reflog
# git reflog 查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作)
# 找到 feature7 的 commit 4c97ff3
# 回到 feature6 的 commit cd52afc
git reset --hard cd52afc
# 使用 cherry-pick 拿到 feature7 的代码
git cherry-pick 4c97ff3

具体可看小蝌蚪的这篇 小蝌蚪传记:git 时光穿梭机—女神的侧颜 来体会一二

简单来说,你的每一次 commit,就是一次记录,可以合并到任意地方。所以开发功能点或者修复 bug 之类,尽量做到一个功能点一个 commit,方便出错时挑拣代码

使用 git commit —amend 更改提交内容

amend 的意思是修正

# 继续改动你的文件
git add .
git commit --amend --no-edit
# 你这次的改动会被添加进最近一次的 commit 中

合并到上次的 commit 中

git commit --amend:弹出让你修改内容

git commit --amend --no-edit:保持上一次的 commit 内容

PS:假如你的代码已经 push 了的话,要慎用,因为会修改提交历史。

使用 git revert 回滚某次的提交

上文提到一个回滚操作:git reset --hard xxx,能回到某次的 commit,除此之外,还有一种则是能撤销某次 commit

# 先找到你想撤销的那个 commit hash值
git log
git revert <commit-id>

这种做法会新建一条 commit 信息,来撤回之前的修改。

而 git reset 会直接提交记录退回到指定的 commit 上。

所以就个人开发或个人 feature 分支而言,可以使用 git reset 来回滚代码,但在多人协作的集成分支上,git revert 更适合。这样,提交的历史记录不会被抹去,可以安全地进行撤回

使用 git stash 来暂存文件

顾名思义,就是把本地的改动暂存起来

先了解下 git 的四大工作区域

四大工作区域

Git工作区

  • Workspace(工作区):本地电脑所见的文件和目录

  • Index/Stage(暂存区):一般存放在 .git 目录下,当你 git add 改动文件,改动的文件就放入在「暂存区」

  • Respository(本地仓库):当你 git clone 地址,就将远程仓库克隆到本地仓库。它是存在本地的版本库,其中 HEAD 指向最新放入仓库的版本。当你执行 git commit,文件改动就到本地仓库

  • Remote(远程仓库):类似 Github、Gitlab、码云等放在代码托管平台

常见的场景是你还在开发一个功能点的时候,突然有个线上 bug 需要你紧急修复,这次你可以 git commit 提交到本地仓库,后续通过 git commit --amend 继续在原 commit 上修改内容。但这里还有一种方法,即将代码存在暂存区,等 bug 修复完后,再从暂存区取出

基本命令如下:

git stash # 将本地的改动暂存
git stash save "message" # 执行存储时,添加备注
git stash pop # 应用最近一次暂存,并删除暂存记录
git stash apply #恢复最近的存储,但不会把存储从存储列表中删除,某人使用第一个存储,即 stash@{0},如果要使用其他,git stash apply stash@{$num}
git stash list # 查看 stash 了哪些存储
git stash clear #删除所有缓存的 stash
git ls-files --stage #查看 index 暂存区

配置 git alias 提升工作效率

主要是为了简化命令,它的基本用法是 git config --global alias.<简化的字符> 原始命令

如下面的例子:

git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.br branch

当然,另一种方法是在 .gitconfig 文件中设置

[alias]
st = status -sb
co = checkout
br = branch
mg = merge
ci = commit
ds = diff --staged
dt = difftool
mt = mergetool
last = log -1 HEAD
latest = for-each-ref --sort=-committerdate --format=\"%(committername)@%(refname:short) [%(committerdate:short)] %(contents)\"
ls = log --pretty=format:\"%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green)[%cn]\" --decorate --date=short
hist = log --pretty=format:\"%C(yellow)%h %C(red)%d %C(reset)%s %C(green)[%an] %C(blue)%ad\" --topo-order --graph --date=short
type = cat-file -t
dump = cat-file -p
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

参考政采云的配置

除此之外

还有一些不常见却好用的命令

  • gitk:打开 git 的图形化工具
  • gitjk:撤消您刚刚在 git 中所做的操作
  • git help -g:展示帮助信息
  • cat .git/HEAD:查看分支文件
  • git fetch --all && git reset --hard origin/master:回到远程仓库的状态
    • 抛弃本地所有的修改,回到远程仓库的状态
  • git push -f origin master:强行获取远程最新代码
  • git reset --merge:merge 代码后想测回到原来版本

参考资料

芝麻开门,显示全文!

加密货币预测记录

虽然有在公众号「随朱波流」写有关理财的文章,但介于这篇文章很可能会被禁掉,所以在个人博客上做备份

最近LUNA暴跌,从200美元到归零,大概花了3天时间,一个市值高达400亿美元的币种,一个曾今进入前五,最近一年来稳坐前十的币种,就这样崩盘了,伴随而来的是加密货币的崩盘,总市值跌没了5000千万美元(一个礼拜时间)

具体事情自招财大牛猫描述的很到位:惊天动地

有一个韩国团队做的项目叫**UST,这是一个算法稳定币,1:1挂钩美元。**怎么挂钩呢,它采用预言机,通过燃烧另一个叫做LUNA的虚拟币来铸造。

比如LUNA现在价格5美元,那么要铸造1美元的UST,就要燃烧0.2个LUNA。如果LUNA涨到10美元,那就燃烧0.1个。

在这个机制下,如果想买UST的人越多,就会燃烧越多的LUNA,从而推高LUNA的价格,这个大家都能理解吧。LUNA过去一年涨了几十倍。

那怎么刺激大家来买UST呢?韩国团队搞了一个存款项目,只要你存UST进来,**每年固定给你19.8%的利息。**这个收益非常高,因此一经推出就遭到哄抢,UST的锁仓资金一路飙升,最高峰超过了300亿美元。

看到这里你一定会感到疑问,这19.8%的利息是从哪来的,谁给出?确实,由于贷款的利息不够高(12%左右),贷款资金也远远跟不上存款增长的速度,整个项目每天都净亏损几百万。去年底的时候资金池就告急了,韩国团队临时追加了4.5亿进去续命,于是才又拖了半年。

他们之所以花这个钱,是希望趁着快速扩张的阶段,尽可能的给这个UST创造更多线下应用的场景。比如韩国以及东南亚的一些自动售货机都有支持UST支付的网点,只要需求上去了,盘子就能稳住。

但无论怎么样19.8%的利息都很难维持,终于到了今年5月初,韩国团队宣布把利息下调到18%,之后每个月动态调整。他们也不敢一口气把利息降的太多,因为一旦降太多,别人不存UST了,选择出售或者兑换等值的LUNA退出,那汹涌的抛盘有可能引发负面螺旋,直接崩盘。

利息下调后的刚开始几天没啥事,但最近美联储加息,整个加密货币都跌的惨惨的,**终于在前天晚上突然有大资金集中抛售UST,把与美元的钩子打脱掉了。**恐慌逐渐发酵,韩国团队立刻调集资金护盘,想要保住挂钩。

但雪崩效应逐渐被激发,想逃命的人越来越多,抛盘一波比一波猛,韩国团队库存的20多亿资金很快就打光了,然后就是UST的汇率开始一泻千里。

截止最新情况,**UST=0.4美元,脱钩60%,LUNA更惨,2天时间从80元跌到2元。**因为这个盘子的规模很大,UST+LUNA有接近400亿美元的市值,国外很多人和机构都进行了投资,所以这次爆炸可以说是震惊了整个币圈和金融圈。

我这两天看戏看的惊心动魄,有很多韩文的帖子,我用软件翻译,大意都是我不想活了,我这辈子的积蓄都完蛋了,我的杠杆爆仓了之类的。

财富它不会凭空增长,也不会无故消失,它只是不停的在流动。

以及后续文章保大弃小

UST和美元的汇率最低到过0.2,之后触底反弹,一度涨到0.8,之后回落目前在0.6附近。韩国团队围绕UST苦心建设了一整套公链生态,自然不愿意轻易放弃,**他们想出来的办法就是超发LUNA,用这部分LUNA去兑换和烧毁市场上过剩的UST,以挽回汇率。**但LUNA就被砸的很难看,已经从80跌到2毛钱了。

其实就是保一个,弃一个。但这也是没办法的事,因为UST不恢复挂钩LUNA也是必死无疑,等到UST勾回去了,没准LUNA到时候也有机会捞上来。

以及最后的结局——湮灭

UST最新汇率是0.07,已经脱钩美元高达93%,为了拯救UST而疯狂增发的LUNA更惨,跌的只剩1分钱。目前看起来是大的没保住,小的也完蛋,死亡螺旋正在毁灭这两个一周前市值还有400亿美金的项目。

不跌还好,一跌我就来劲了,这几天没怎么写技术文章,一是因为这段时间业务多了,二是加密市场跌出了翔,我,想抄底了。

于是乎,这几天研究了一轮,再次做一下笔记更新

有人刻舟求剑的画了这样的图

加密货币未来预测

来源自推特,出自谁未知

周末看了ahr999的微博合集,很多人估计对他的囤币指标有所了解,看完之后,加深了一点我对“比特币四年一个周期”的认可度,我扒拉下最近几次加密货币的高点和低点,也来刻舟求剑预测下

历年高点时机历年低点时机时间跨度跌幅
2013年11月:¥80002015年1月:¥90014个月88.75%
2017年12月:$200002018年11月:$320011个月84%
2021年11月:$68900?

而更之前的是从32美元跌到2美元,时间不详,来源ahr999

按照时间跨度来看,下一次的低点节点在2022年的10月——2023年1月;而低点价位在7750——11024;低点的时机和跌幅应该有一定的关系。我个人觉得本轮跌幅不会像以往那么多,就像这次BTC没有如愿涨到10万美元一样

此外,我还有一个指标,就是ahr999指标,虽然他现在微博被封,但在github上能找到此前微博的记录,我看完了2020年到2021年的微博,他说的有一点我很赞同——“我们第一个周期能够囤的币,大概会等于我们这辈子能囤的币”

所以这次熊市我会看两个指标,一个是ahr999,如果跌倒0.45以下,我会进场。另一个是跌破80%,也就是13780点,我大概会在一个星期内打完所有的可投资加密货币的钱

而我会买什么币

2022年5月份的想法是

  • BTC
  • ETH
  • ADA
  • XHR

为什么要买这些币,怎么个买入策略?等有空再写吧

我希望低点时机出现在2023年的1月份,因为这个时候会发年终奖,正好可以入场

附加阅读

芝麻开门,显示全文!