Skip to main content

9-22

1 刷新组件的常规写法

const [, refresh] = useState<number>(0)

refresh((i) => i + 1)

2 Error: network does not support ENS

可能原因:

  • 地址错误,注意地址中可能带有特殊字符,而在vscode中无法显示出来

3 测试入门

测什么?重点关注什么?

4 jest如何测试Promise

将promise返回,即可让jest等待promise结果

import { getLiquidityList } from './api'

describe('测试网络请求', () => {
it('测试能否调通Api', () => {
return getLiquidityList()
.then((res) => {
// console.log('[res]:', res)

expect(res.code).toBe(0)

expect(Object.keys(res.data).length).toBeGreaterThanOrEqual(0)
})
.catch((err) => {
console.log('[err]:', err)
})
})
})

[1] jest测试异步代码.https://jestjs.io/zh-Hans/docs/asynchronous

5 图片加载失败,备用方案

 const src: string | undefined = srcs.find((src) => !BAD_SRCS[src])

if (src) {
return (
<img
{...rest}
alt={alt}
src={src}
style={style}
//重点,出错后将当前url列入黑名单
onError={() => {
if (src) BAD_SRCS[src] = true
refresh((i) => i + 1)
}}
/>
)
}

6 如何用transform: scale()来模拟zoom?

zoom只会放大内部,而scale会将整个元素放大

const scaleRate = (1920-240) / (1440 - 240) = 1.15
// 放大比例
const Content = styled(Layoutd.Content)<{ screenWidth: number | undefined }>`
/* 将整个内容区放大1.15倍 */
transform: scale(${scaleRate});
transform-origin: 0 0;

/* 修正因放大而导致的宽度变大,思路:在放大前,先将当前内容宽度去除以比例,
放大后的值与当前值是一致的,也就是宽度不变,而其他值变大了
*/
width: ${({ screenWidth }) =>
screenWidth ? ((screenWidth - 240) / scaleRate - ((scrollbarWidth() ?? 2) - 2)).toFixed() + 'px' : '100%'};
/* 内容宽度 / 比例 - 导航条宽度 */
/* 2为导航条修正偏差值 */

/*
transform已知问题:如果分辨率过大(1805以上),
会导致右下角出现1-2px的白框
*/

/* zoom也可以解决此问题,但不兼容firefox */
/* zoom: 1.2; */
/*
* 已解决以下问题。2021-09-24 16:42:20
* 缩放1.2倍,由于失误将1920设计稿用1440的方式实现,
* 现需要放大1.2倍
*
* 已知问题:
* 火狐不支持zoom,但transform:scale()无法达到想要的效果,未找到合适的解决方案
*
* 带来后果:火狐浏览器用户看到的右边内容区会比Chrome浏览器看到的小1.2倍
* 其他用户不受影响
*/

/* 在H5端修改回来 */
@media (max-width: ${MEDIUM}) {
transform: none;
width: inherit;
}
`
// 获取导航条宽度
export function scrollbarWidth() {
const cWidth = document.body.clientWidth || document.documentElement.clientWidth //页面可视区域宽度
const iWidth = window.innerWidth //浏览器窗口大小
if (!iWidth || !cWidth) return undefined

console.log('[](iWidth - cWidth):', iWidth - cWidth, iWidth, cWidth)

return iWidth - cWidth
}

7 验证数字和小数点

export function validaInputValue(value: string | undefined) {
if (value) {
// 只要数字和小数点
if (!value.match(/^[\d\.]+$/g)) throw new Error('只要数字和小数点')

// 只要一个小数点
const hasOnlyOnePoint = value.match(/\./g)
if (hasOnlyOnePoint && hasOnlyOnePoint.length > 1) throw new Error('只要一个小数点')
}
}

9 web3-react连接流程

import React, { useState, useEffect } from 'react'
import { useWeb3React } from '@web3-react/core'
import styled from 'styled-components/macro'

import { network } from '../../connectors'
import { useEagerConnect, useInactiveListener } from '../../hooks/web3'
import { NetworkContextName } from '../../constants/misc'
import Loader from '../Loader'

const MessageWrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: 20rem;
`

const Message = styled.h2`
color: ${({ theme }) => theme.secondary1};
`

export default function Web3ReactManager({ children }: { children: JSX.Element }) {
const { active } = useWeb3React()
const { active: networkActive, error: networkError, activate: activateNetwork } = useWeb3React(NetworkContextName)

// try to eagerly connect to an injected provider, if it exists and has granted access already
const triedEager = useEagerConnect()

// after eagerly trying injected, if the network connect ever isn't active or in an error state, activate itd
useEffect(() => {
if (triedEager && !networkActive && !networkError && !active) {
activateNetwork(network)
}
}, [triedEager, networkActive, networkError, activateNetwork, active])

// when there's no account connected, react to logins (broadly speaking) on the injected provider, if it exists
useInactiveListener(!triedEager)

// handle delayed loader state
const [showLoader, setShowLoader] = useState(false)
useEffect(() => {
const timeout = setTimeout(() => {
setShowLoader(true)
}, 600)

return () => {
clearTimeout(timeout)
}
}, [])

// on page load, do nothing until we've tried to connect to the injected connector
if (!triedEager) {
return null
}

// if the account context isn't active, and there's an error on the network context, it's an irrecoverable error
if (!active && networkError) {
return (
<MessageWrapper>
<Message>
Oops! An unknown error occurred. Please refresh the page, or visit from another browser or device.
</Message>
</MessageWrapper>
)
}

// if neither context is active, spin
if (!active && !networkActive) {
return showLoader ? (
<MessageWrapper>
<Loader />
</MessageWrapper>
) : null
}

return children
}

上面是整个连接节点的代码,总共有以下几步:

第一步:尝试积极的连接(通过injected去连接)

例如:metamask注入的web3

第二步:尝试http连接(通过http去连接)

例如:https://arb1.arbitrum.io/rpc

第三步:在连接前的监听事件

通过下面两个事件实现:链改变、账户改变

ethereum.on('chainChanged', handleChainChanged)
ethereum.on('accountsChanged', handleAccountsChanged)

我们知道在有注入ethereum的时候,可以通过eth...去监听状态,那么通过http连接的呢?

问题1:web3和etherjs区别?

都是获取chain数据的js库,只不过各有特点,web3较早,维护人员稳定一些,使用者更多一些

问题2:连接节点和getLibrary有什么关系?

连接上了节点之后,就需要一个Provider提供服务(方法),例如:获取账户余额,获取区块信息等,其实library在etherjs中已经提供了,只不过可以将它进一步包装,例如:Web3Provider,JsonRpcProvider等,这样能够方便的调用其方法

10 v2ray可以调整模式

调整模式为指定IP地址才科学上网

image-20210926221057451

可以在 pac.js 中指定需要科学上网的IP地址(域名)

11 在react中判断是否为手机端的方法

import { isMobile } from 'react-device-detect'

https://www.npmjs.com/package/react-device-detect

12 前端连接钱包所需要的库

总的来说,需要两个库:etherjs或者web3jsweb3-react

etherjs提供底层的服务,而web3-react提供react方面的应用层服务(通过hooks访问数据,连接钱包等)

问题1:web3-react提供连接服务,那么原始通过web3去调用方法和连接合约是可以直接操作的,那么web3-react为什么要多做一次操作?

因为这样可以控制连接,例如:控制连接支持的网络

问题2:web3-react中如何连接合约呢?

通过实例化etherjs的Contract来连接合约,而实例化的时候可选是否传入签名

13 显示点点点-动画

export const Dots = styled.span`
&::after {
display: inline-block;
animation: ellipsis 1.25s infinite;
content: '.';
width: 1em;
text-align: left;
}
@keyframes ellipsis {
0% {
content: '.';
}
33% {
content: '..';
}
66% {
content: '...';
}
}
`

image-20210927150915618

14 react单元测试和组件测试

最近在看《持续交付2.0》这本书,里面讲到了测试用例集,书中说讲的基本都是C++、JAVA等项目的测试用例,基本都是同步的,但是我在思考,我们前端大量的异步代码如何进行测试?组件的生命周期、事件如何测试?

这两篇文章值得参考一下:

以上两篇文章并不适用于函数式组件,react16.8以上请使用官方推荐的 React Testing Library

https://github.com/testing-library/react-testing-library#suppressing-unnecessary-warnings-on-react-dom-168

问题1: React Testing Library与jest的区别?各自适用于什么情况呢?

目前,我认为 jest 是一个测试库,而 React Testing Library 是一个测试工具集,它提供各种工具去测试,React Testing Library是依赖于jest的

react组件测试

使用React Testing Library进行组件测试的 AAA模式 :编排(Arrange),执行(Act),断言(Assert)。

编排

在编排这一步,我们需要完成2项任务:

  • 渲染组件
  • 获取所需的DOM的不同元素。
function render(
ui: React.ReactElement,
options?: Omit<RenderOptions, 'queries'>
): RenderResult

上面是render函数的定义

const instance = render(<Counter />);
// OR
const { getByText, queryByText } = render(<Counter />);
// get* 查找text的元素,找不到报错
// query* 查找text的元素,找不到返回null

执行

触发相应的事件

fireEvent.click(incrementButton);
// OR
fireEvent.click(decrementButton);

断言

expect(counter.textContent).toEqual("1");
expect(counter.textContent).toEqual("0");

// 通过节点去查询元素
expect(instance.getByText('123')).toBeInTheDocument()

// 当然也可以通过屏幕去查询
expect(screen.getByText('123')).toBeInTheDocument()

[1] 使用 React Testing Library 和 Jest 完成单元测试.https://juejin.cn/post/6844904101730320397

示例-摘抄自 React Testing Library 文档

// Login/index.tsx
import * as React from 'react'

interface State {
resolved: boolean
loading: boolean
error: string | null
}

const initState : State = {
resolved: false,
loading: false,
error: null,
}
function Login() {
// 看不懂这个s,a的请看(state, action) => newState
const [state, setState] = React.useReducer((s: State, a: any) => ({...s, ...a}), initState)

function handleSubmit(event: any) {
event.preventDefault()
const {usernameInput, passwordInput} = event.target?.elements

setState({loading: true, resolved: false, error: null})

window
.fetch('/api/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username: usernameInput.value,
password: passwordInput.value,
}),
})
.then(r => r.json().then(data => (r.ok ? data : Promise.reject(data))))
.then(
user => {
setState({loading: false, resolved: true, error: null})
window.localStorage.setItem('token', user.token)
},
error => {
setState({loading: false, resolved: false, error: error.message})
},
)
}

return (
<div>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="usernameInput">Username</label>
<input id="usernameInput" />
</div>
<div>
<label htmlFor="passwordInput">Password</label>
<input id="passwordInput" type="password" />
</div>
<button type="submit">Submit{state.loading ? '...' : null}</button>
</form>
{state.error ? <div role="alert">{state.error}</div> : null}
{state.resolved ? (
<div role="alert">Congrats! You're signed in!</div>
) : null}
</div>
)
}

export default Login
// Login/index.test.tsx
import '@testing-library/jest-dom'
import * as React from 'react'
// import API mocking utilities from Mock Service Worker.
import {rest} from 'msw'
import {setupServer} from 'msw/node'
// import testing utilities
import {render, fireEvent, screen} from '@testing-library/react'
import Login from './index'

const fakeUserResponse = {token: 'fake_user_token'}
const server = setupServer(
rest.post('/api/login', (req, res, ctx) => {
return res(ctx.json(fakeUserResponse))
}),
)

beforeAll(() => server.listen())
afterEach(() => {
server.resetHandlers()
window.localStorage.removeItem('token')
})
afterAll(() => server.close())

test('allows the user to login successfully', async () => {
render(<Login />)

// fill out the form
fireEvent.change(screen.getByLabelText(/username/i), {
target: {value: 'chuck'},
})
fireEvent.change(screen.getByLabelText(/password/i), {
target: {value: 'norris'},
})

fireEvent.click(screen.getByText(/submit/i))

// just like a manual tester, we'll instruct our test to wait for the alert
// to show up before continuing with our assertions.
const alert = await screen.findByRole('alert')

// .toHaveTextContent() comes from jest-dom's assertions
// otherwise you could use expect(alert.textContent).toMatch(/congrats/i)
// but jest-dom will give you better error messages which is why it's recommended
expect(alert).toHaveTextContent(/congrats/i)
expect(window.localStorage.getItem('token')).toEqual(fakeUserResponse.token)
})

test('handles server exceptions', async () => {
// mock the server error response for this test suite only.
server.use(
rest.post('/api/login', (req, res, ctx) => {
return res(ctx.status(500), ctx.json({message: 'Internal server error'}))
}),
)

render(<Login />)

// fill out the form
fireEvent.change(screen.getByLabelText(/username/i), {
target: {value: 'chuck'},
})
fireEvent.change(screen.getByLabelText(/password/i), {
target: {value: 'norris'},
})

fireEvent.click(screen.getByText(/submit/i))

// wait for the error message
const alert = await screen.findByRole('alert')

expect(alert).toHaveTextContent(/internal server error/i)
expect(window.localStorage.getItem('token')).toBeNull()
})

msw库

在上一节组件测试中用到了msw,msw是一个用于mock数据的库,但它是真正开启了服务的,文档写的很好,还有互动

// src/mocks/server.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
// This configures a request mocking server with the given request handlers.
// 融合
export const server = setupServer(...handlers)
// src/mocks/handlers.js
import { rest } from 'msw'
export const handlers = [
rest.post('/login', (req, res, ctx) => {
// Persist user's authentication in the session
sessionStorage.setItem('is-authenticated', 'true')
return res(
// Respond with a 200 status code
ctx.status(200),
)
}),
rest.get('/user', (req, res, ctx) => {
// Check if the user is authenticated in this session
const isAuthenticated = sessionStorage.getItem('is-authenticated')
if (!isAuthenticated) {
// If not authenticated, respond with a 403 error
return res(
ctx.status(403),
ctx.json({
errorMessage: 'Not authorized',
}),
)
}
// If authenticated, return a mocked user details
return res(
ctx.status(200),
ctx.json({
username: 'admin',
}),
)
}),
]

上面两步已经将server配置好了接口,接下来在测试中使用server

// src/setupTests.js
import { server } from './mocks/server.js'
// Establish API mocking before all tests.
beforeAll(() => server.listen())

// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => server.resetHandlers())

// Clean up after the tests are finished.
afterAll(() => server.close())

15 mac上的状态栏网速

Stats软件.https://github.com/exelban/stats

image-20210928145012319

16 docker下载镜像太慢的解决方案

思路:利用阿里云的镜像加速服务-free

https://cr.console.aliyun.com

[1] docker下载镜像太慢的解决方案.https://blog.csdn.net/weixin_43569697/article/details/89279225

17 使用docker创建一个ubuntu20.04

❌ 意义不大,各种限制,特别是网络方面

转载:https://zhuanlan.zhihu.com/p/59548929

原文:https://blog.smslit.cn/2018/12/20/docker_ubuntu_learn/

大致步骤:拉取ubuntu镜像-> 启动镜像容器-> 安装需要的软件(vim、ssh服务端),并进行相关配置-> commit形成自己的镜像-> 启动自己的镜像容器-> 客户端通过ssh访问

如何创建快捷ssh?

为了更方便的连接,可以为容器创建 ssh 连接的主机短名,往 macOS 的 ~/.ssh/config 中添加以下内容:

Host learn
HostName localhost
User root
Port 26122

此时就可以通过命令 ssh learn 连接 ubuntu 容器 learn 了。

18 Github Actions

⚠️ GithubActions的自动化脚本基本上google一下都能找到相似的,修改修改就可以使用,不用专研过深

[1] GitHub Actions 入门教程.https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html

[2] Actions Market.https://github.com/marketplace?type=actions

19 ssh-scp带端口参数怎么办

#注意是大写P
scp -P 4588 [email protected]:/usr/local/sin.sh /home/administrator
#注意是小写p
ssh [email protected] -p 16112

20 自动化部署-连接远端服务器脚本

#!/bin/sh
eval $(ssh-agent -s)

#将ssh private key 放入当前服务器,这样才可以登录远端服务器
#注意加上""双引号
echo "$PRIVATE_KEY" > deploy.key

mkdir -p ~/.ssh
chmod 0600 deploy.key
ssh-add deploy.key

echo "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config

#复制一些东西
scp sh/deploy_dev_docker_pull.sh $HOST_NAME_15@$ADMIN_HOST_15:~/sh/
scp docker-compose-dev.yml $HOST_NAME_15@$ADMIN_HOST_15:~/sh/

#登录远端服务器并执行命令
ssh $HOST_NAME_15@$ADMIN_HOST_15 "cd sh && sh deploy_dev_docker_pull.sh"

⚠️ 注意:需在GithubActions的脚本中声明$PRIVATE_KEY、$HOST_NAME_15、$ADMIN_HOST_15等变量,例如:

#build_dev.yml
env:
DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }}
DOCKER_ACCESS_NAME: ${{ secrets.DOCKER_ACCESS_NAME }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
HOST_NAME_15: ${{ secrets.HOST_NAME_15 }}
ADMIN_HOST_15: ${{ secrets.ADMIN_HOST_15 }}

有几点需要说明:

ssh-add

ssh-add可以将private key添加到ssh-agent高速缓存区,这样就可以无需密码去连接服务器

注意文件权限为0600

1、把专用密钥添加到 ssh-agent 的高速缓存中:

ssh-add ~/.ssh/id_dsa

2、从ssh-agent中删除密钥:

ssh-add -d ~/.ssh/id_xxx.pub

3、查看ssh-agent中的密钥:

ssh-add -l

scp

scp可以将文件(目录-r)在两个服务器之间拷贝

scp -P 123 path target:path

例子:

scp -P 22 ./a.txt [email protected]:~/a.txt

21 Github Action 如果要设置多个触发方式

如果没有具体配置,则用多个数组:

on: [push, workflow_dispatch]

如果有一个配置,而另一个没有,则留空:

# 第一个留空就好,注意尾部冒号
on:
workflow_dispatch:
push:
branches:
- main

22 给服务器添加公匙-服务器免密登录

第一步:通过密码登录服务器

ssh 192.168.2.31 -l root

第二步:ssh-keygen

一路回车

ssh-keygen

第三步:登录远端服务器,并将用户公匙添加到authorized_keys

vim ~/.ssh/authorized_keys

[1] Linux 添加ssh公钥.https://blog.csdn.net/qq_24909089/article/details/81231373

问题1:WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

解决方案:删除~/.ssh/known_hosts,并重新尝试链接

rm ~/.ssh/known_hosts
ssh [email protected]
# 回车后输入yes

[1] 关于ssh登录出现异常警告:WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!.https://www.cnblogs.com/johnchain/archive/2013/04/08/3006631.html

问题2:如何生成私匙和公匙?

ssh-keygen -t rsa -C "您的邮箱地址"

一路回车

23 Github Action docker login报错-docker login can not perform an interactive login from a non TTY

命令如下:

docker login -u $DOCKER_ACCESS_KEY -p $DOCKER_ACCESS_TOKEN

报错,如果改成如下:则通过

docker login -u "$DOCKER_ACCESS_KEY" -p "$DOCKER_ACCESS_TOKEN"

24 docker push的时候-denied: requested access to the resource is denied

原因:极大可能是没有登录成功,尽管docker提示 Login success

在github action的yaml配置中,一定要检查环境变量是否生效

echo "检查是否有DOCKER_ACCESS_KEY环境变量"
echo "--------$DOCKER_ACCESS_KEY-------------/n"

=>输出***就表示可以访问
--------***-------------

在sh文件中是无法拿到github配置的环境变量,要访问只能通过yaml配置文件重新声明一下:

name: deploy dev to nginx
on:
workflow_dispatch:
push:
branches:
- main
env:
# 中转环境变量
DOCKER_ACCESS_KEY: ${{secrets.DOCKER_ACCESS_KEY}}
DOCKER_ACCESS_TOKEN: ${{secrets.DOCKER_ACCESS_TOKEN}}

这样就能够在sh文件中访问声明的环境变量

docker login --username "$DOCKER_ACCESS_KEY" -p "$DOCKER_ACCESS_TOKEN"

官网也有介绍,所以要多看看文档

Example using Bash

steps:
- shell: bash
env:
SUPER_SECRET: ${{ secrets.SuperSecret }}
run: |
example-command "$SUPER_SECRET"

https://docs.github.com/en/actions/security-guides/encrypted-secrets

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo \
"deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null


apt-get install docker-ce="5:20.10.8~3-0~ubuntu-focal" docker-ce-cli="5:20.10.8~3-0~ubuntu-focal" containerd.io

部署时,链接远端服务器需要配置deploy.key的注意

注意,private key一定要复制完全,头部、尾部都要复制进去,否则提示 format invalid

正确例子:

-----BEGIN OPENSSH PRIVATE KEY-----
b3Bl*********************kCZ0FXwcj
nxr5EMiLZX/qUAAAAPZ2lubGlua0AxNjMuY29tAQIDBA==
-----END OPENSSH PRIVATE KEY-----

25 docker中安装docker

总结

docker中安装docker有许多问题,不建议使用

docker in docker

目前只能通过 docker:dind 安装容器中的容器,其他如ubuntu-dind等都无法在容器中使用docker

docker run -d --name dind --privileged docker:dind # 启动容器
$ docker logs -f dind # 查看启动日志
$ docker exec -it dind sh # 进入容器

说明:docker:dind中安装的是 alpine linux ,包管理器为apk

[1] docker:latest 和 docker:dind 镜像区别.https://segmentfault.com/a/1190000025133926

Apk常用命令有

# 安装
add:命令从仓库中安装最新软件包,并自动安装必须的依赖包,也可以从第三方仓库添加软件包。add:安装PACKAGES并自动解决依赖关系。
apk add openssh openntp vim
apk add --no-cache mysql-client
apk add docker --update-cache --repository http://mirrors.ustc.edu.cn/alpine/v3.4/main/ --allow-untrusted

# 安装指定版本软件包
apk add asterisk=1.6.0.21-r0
apk add 'asterisk<1.6.1'
apk add 'asterisk>1.6.1

# 卸载
del:卸载并删除PACKAGES
apk del openssh openntp vim

# 升级
upgrade命令升级系统已安装的所以软件包(一般包括内核),当然也可指定仅升级部分软件包(通过-u或–upgrade选择指定)。
apk update #更新最新本地镜像源
apk upgrade #升级软件

# 搜索
search命令搜索可用软件包,-v参数输出描述内容,支出通配符,-d或–description参数指定通过软件包描述查询。
apk search #查找所以可用软件包

# 查看包信息
info命令用于显示软件包的信息。
apk info #列出所有已安装的软件包

实例:安装一个bash,并配置

配置国内源

sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories

安装

apk update
apk upgrade
apk add vim bash bash-doc bash-completion

vim ~/.bashrc
# 输入以下内容
alias update='apk update && apk upgrade'
export HISTTIMEFORMAT="%d/%m/%y %T "
export PS1='\u@\h:\W \$ '
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
source /etc/profile.d/bash_completion.sh

[1] 在 Alpine Linux 中安装 bash shell.https://www.oschina.net/translate/alpine-linux-install-bash-using-apk-command

[2] alpine linux更新国内源.https://blog.csdn.net/vah101/article/details/108602970

[3] alpine Linux-apk软件包管理器,就这么用.https://blog.csdn.net/hxpjava1/article/details/80221307

26 Docker删除所有容器

删除所有容器

docker rm `docker ps -a -q`
docker rm 'docker ps -a -q'

删除所有镜像

docker rmi `docker images -q`

27 Mac docker无法连接容器IP的问题

问题描述:能够通过 docker inspect查看容器的IP地址,但是无法ping通,所以无法访问里面的服务

解决方案:端口映射

docker run -d -p 7500-7550:7500-7550 --name dind8 --privileged docker:dind

注意:端口不要范围不要太宽,否则会导致失败

重新启动exit状态的容器

docker ps -a #查看所有容器,找到要重启的容器ID

docker start 容器ID

关闭容器

docker stop 容器ID或容器名
# OR
docker kill 容器ID或容器名

stop和kill的主要区别:stop给与一定的关闭时间交由容器自己保存状态,kill直接关闭容器

[1] Mac系统下docker容器无法使用--net host共享宿主机端口的解决方案.https://blog.csdn.net/qq_42937522/article/details/109052954

28 给alpine安装sshd

apk update && \
apk add --no-cache openssh tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
sed -i "s/#PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config && \
ssh-keygen -t dsa -P "" -f /etc/ssh/ssh_host_dsa_key && \
ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key && \
ssh-keygen -t ecdsa -P "" -f /etc/ssh/ssh_host_ecdsa_key && \
ssh-keygen -t ed25519 -P "" -f /etc/ssh/ssh_host_ed25519_key && \
echo "root:admin" | chpasswd

启动

/usr/sbin/sshd -D

修改ssh的端口

第一步:打开配置文件,修改为需要的端口

vim /etc/ssh/sshd_config

# 例如修改为7501端口
port 7501

第二步:重启sshd

/etc/init.d/sshd restart

[1] alpine安装sshd/ssh server(通过Dockerfile配置).https://www.cnblogs.com/sunsky303/p/11543747.html

[2] linux修改ssh端口.https://www.jianshu.com/p/7c4ffbc8927a

29 给Alpine linux设置环境变量

vim ~/.bashrc

# 设置环境变量
export DOCKER_ACCESS_KEY="demo"
export DOCKER_ACCESS_TOKEN="d9999994-40006b-41223a6-a102-5d88888888e0"

source ~/.bashrc

30 dcoker-compose基本用法

启动所有服务

docker-compose -f compose-file.yml up -d
# -d后台运行

关闭所有服务

docker-compose -f compose-file.yml stop
docker-compose -f compose-file.yml down
# down关闭所有服务并把容器也删除,而stop仅仅关闭所有服务

一般操作如下:

# 拉取镜像,重新启动服务
docker login -u "$DOCKER_ACCESS_KEY" -p "$DOCKER_ACCESS_TOKEN"

docker-compose -f compose/docker-compose-dev.yml down

docker rmi -f ginlink/sheep-web:dev

docker-compose -f compose/docker-compose-dev.yml up -d

[1] Get started with Docker Compose.https://docs.docker.com/compose/gettingstarted/

31 总结自动化部署的一系列操作

TODO

32 vite2+vue3最佳实践

[1] 2021必知必会的vite+vue3项目最佳实践.https://blog.csdn.net/l1063951462/article/details/114941408

(项目地址:https://github.com/57code/vite2-in-action)

33 mac如何切图-并上传到蓝湖

第一步:下载sketch

https://www.macwk.com/soft/sketch

第二步:按照蓝湖教程继续

https://sos.lanhuapp.com/lan-hu-xiang-xi-jiao-cheng.html#21-%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6

[1] mac免费软件下载.https://www.macwk.com/

34 mac抓包

[1] MAC系统利用charles抓取微信小程序和手机APP数据包(http和https数据包).https://www.jb51.net/article/147633.htm

[2] Charles 4.6.3b1 破解版 (http抓包神器) (官方版 + 激活码).https://www.macwk.com/soft/charles

抓http大题步骤:

第一步:设置charles的代理开启8888端口

第二步:让mac和手机处于统一网络

需要一个wifi

第三步:charles会弹出提示,开始记录

抓https的步骤:

TODO

35 nestjs(koa2)文档

nestjs的v8文档:https://github.com/nestcn/docs.nestjs.cn/blob/master/8/about.md

node相关学习文档:https://github.com/nestcn/docs.nestjs.cn

目的:用nestjs搭建一个文件上传的后台服务

nest + mysql + graph

一个示例:

nest mysql 实战.https://blog.csdn.net/u014196765/article/details/107184616/

项目地址:https://github.com/baiqingchun/nest

36 graphql

官网:https://graphql.cn/

视频学习:bilibili

38 如何从头搭建webpack项目

大致步骤:

yarn init=> 安装webpack以及cli=> 配置=> 性能优化

配置

  • 创建配置文件
  • 配置mode、入口、出口
  • 配置html插件(以模板引入),文档地址:https://github.com/jantimon/html-webpack-plugin
  • 配置开发环境serve、热更新
  • 配置ts支持(ts-loader)
  • 配置npm启动、打包脚本

[1] webpack5文档.https://webpack.docschina.org/guides/

39 mac安装mysql(包含客户端和服务器端)

brew install mysql

#进入数据库
mysql -u root -p #默认IP和端口
mysql -h 192.168.218.129 -u root -p -P 3306 #指定IP和端口

#如果要做服务端,则启动数据库
brew services start mysql

错误:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

描述:输入mysql -u root -p之后,出现以上错误

原因:mysql运行在docker之中,而以上命令是链接本机(127.0.0.1)的mysql

解决方案1:指定地址和端口

mysql -h 192.168.3.72 -u root -p -P 3307
#3307是启动容器暴露给主机的端口,为了与本机3306区分

注意不能只安装客户端mysql,服务端mysql也要安装 ,不安装服务端mysql也可以

解决方案2:通过容器ip直接链接(前提是可以ping通容器ip)

首先进入容器

docker exec -it 容器id bash

进入mysql数据库开启远程访问权限

mysql -uroot -p
use mysql;
update user set password_expired="Y" where user="root";
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';

cmd 远程连接

mysql -h 192.168.218.129 -u root -p -P 3306

[1] Mac终端安装mysql教程.https://blog.csdn.net/m0_46481239/article/details/105590054

[2] 本机连接虚拟机中docker启动的mysql数据库.https://www.cnblogs.com/zwq-/p/11221013.html

错误:npm的mysql包报错-ER_NOT_SUPPORTED_AUTH_MODE

解决方案:

mysql -u root -p
use mysql;
ALTER USER the_user IDENTIFIED WITH mysql_native_password BY 'the_password';

[1] ER_NOT_SUPPORTED_AUTH_MODE #2499.https://github.com/mysqljs/mysql/issues/2499

40 一个prettier的通用配置库

yarn add -D @fantasticit/code-lint

使用

// .prettierrc.js
const config = require('@fantasticit/code-lint/lib/config/prettier')();

module.exports = config

41 ts中的装饰器有什么用?

ts中的装饰器就是一个 函数,参数中包含修饰对象的所有信息,然后可以对这些信息进行加工。被修饰对象可以是类、属性、方法、参数,针对于不同对象传入的参数也不同。

注意:装饰器是 javascript 中的概念。

问题一:Reflect Metadata是什么?