23030816
-
需求:备份一个 repo 到另一个 github 账号的 repo,首先需要同步所有分支,然后更改 remote url,最后推送所有分支到新仓库。
- How do I fetch all Git branches?
- How do I change the URI (URL) for a remote Git repository?
- Set up git to pull and push all branches
git branch -r | grep -v '\->' | sed "s,\x1B\[[0-9;]*[a-zA-Z],,g" | while read remote; do git branch --track "${remote#origin/}" "$remote"; done git fetch --all git pull --all # change the URLs git remote set-url origin new.git.url/here # push tags and branches. git push --all origin
20230812
-
Web 调试
-
让你的飞书更好用:破解飞书的复制限制
-
Deploying IPFS on Linux with Docker Containers
-
Install IPFS Kubo inside Docker | IPFS Docs:主要看这个部署单个节点
docker logs -f ipfs_host docker exec ipfs_host ipfs <args...>
20230811
- ga-tracker:适用于UniApp和微信小程序的谷歌统计 (Google Analytics) SDK,只支持 Universal Analytics,即形式如 UA-XXXXXXXX-1 的 ID。(2023 年 7 月 1 日起就用不了了,最后我直接将 script 代码放到 index.html head 中去了,不知道起不起作用)
- Google Analytics分析终极入门指南
20230809
- List of applications - ArchWiki:Arch Wiki 万岁,可以很方便地去找 Linux 下的各种工具及其 wiki。
- NCurses Disk Usage
- PHP 设置 UTC 0 时区时间:默认就是 UTC 0 时区时间;或者指定 timezone 为
UTC
;再或者设置为格林威治当地时间Etc/Greenwich
,其值与 UTC 0 时区时间相同。-
Setting timezone to UTC (0) in PHP:
echo date('Y-m-d H:i:s T', time()) . "<br>\n"; date_default_timezone_set('UTC'); echo date('Y-m-d H:i:s T', time()) . "<br>\n";
-
Is there a difference between the UTC and Etc/UTC time zones?: That is, they’re long and short names for the same timezone
- iOS 终于支持了 PWA,一起来认识一下这个强化版「小程序」 | 科普 - 少数派
- 如何用 Xcode 安装 Github 中的未上架 iOS App - 少数派
- 写给5年前端妹子的三万字脚手架教程 - 掘金
- macOS 平台最好的 PDF 阅读器是什么? - 知乎:对于绝大部分人来说 Preview.app 是最佳的选择。系统自带、速度极快、兼容性尚可、有基本的编辑功能、支持批注。只有极少数需要填表、数字签名、高级编辑的情况下才会需要 Acrobat。
20230808
- Java8 是没有 Mac M1 版本的,但是 Java11 有,虽然 On Java8 用的是 Java8,但是还是只能安装 Java11 了,Java11 是继 Java8 使用率最高的 LTS。
- How to pronounce “Gradle”?:
/'ɡreɪdl̩/
- Gradle从0入门到实战系列
- 环境变量除了 PATH 外(即原本有的),不能放在 .zprofile 中,通过 env 即可查看添加的环境变量没有生效,而应该在 .zshrc 中进行 export。
- How to prevent Homebrew from installing a certain formula dependency?:
brew install --ignore-dependencies formula
20230807
- JSON fromatter:可以将 json file 键去重
- How to find out the virtualization type of an linux VPS?:
hostnamectl status
20230805
-
Deploying Redis on Linux with Docker Containers
-
Deploying RabbitMQ on Linux with Docker Containers
-
-
husky:
yarn add -D husky
-
# Install commitlint cli and conventional config yarn add -D @commitlint/{config-conventional,cli}; # Configure commitlint to use conventional config echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js; # add hook npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'
-
-
hook was ignored because it’s not set as executable: I think it’s probably a problem that wasn’t created taking into account the file permissions of Linux at the time of init on Windows.
chmod ug+x .husky/*
-
-
Docker privileged オプションについて:允许容器中运行一些特权命令,比如调用宿主机的所有设备。
-
Defining an array as an environment variable in node.js:通用的是 split(),还有一种是 JSON.parse()
FESTIVALS = "bonnaroo, lollapalooza, coachella" var festivals = process.env.FESTIVALS.split(", "); ANY_LIST = ["A", "B", "C"] const LIST = JSON.parse(process.env.ANY_LIST);
-
vscode markdown 中 ```shell语法基本上没颜色 怎样添加?:grep rm find 等这些并不是 shell 里的关键字,而是需要特定环境变量,所以没高亮,而比如 if then cd 等这些会高亮的。
-
no matching manifest for linux/arm64/v8 in the manifest list entries:这个原因是M1的CPU是linux/arm64/v8,但是想要使用的image不支持这个;指定模拟
platform: linux/amd64
就可以正常运行了。 -
COPY with docker but with exclusion: Create file .dockerignore in your docker build context directory。.dockerignore 文件从入门到实践
-
问题:我有一个 Nest.js 项目,它需要的基础服务有 MySQL、Redis 和 RabbitMQ,然后我将它们放到一个 docker-compose.yml 文件中进行部署,遇到的问题是 nest.js 服务无法连接数据库,但是进入容器后是可以直接用 container_name 和容器 ip 地址连接上数据库的。
-
这里 Prisma doesn’t resolve the names of docker containers from within other containers in OSX Docker 有一个讨论,反正我尝试了依旧没用,所以决定单独部署 api,不再浪费时间了。
-
env_file:可以将 enviroment 部分都放到文件中去,docker-compose.yaml 也支持
project-${VAR}
使用环境变量。 -
Access mysql remote database from command line:
apk add mysql-client mysql -u {username} -p'{password}' \ -h {remote server ip or name} -P {port} \ -D {DB name}
-
Build a real-time chat application with Nestjs and PostgreSQL
-
20230804
-
需求:评论要显示刚刚、几分钟前、几个小时前、几天前、几个月前等等状态。考虑使用现成库,但是要注意将时间转换为相同时区再计算。
-
现状:Response Header 返回的是没有时区差的标准 UTC 时间
Fri, 04 Aug 2023 07:10:11 GMT
,Response Body 返回的内容的时间是服务器所在日本本地时间2023-08-04 15:08:28
,dayjs() 返回的是客户端(中国)本地时间Fri Aug 04 2023 15:19:17 GMT+0800 (China Standard Time)
。 -
相关文章
- Day.js | 更优雅的处理JavaScript中的日期
- Day.js:Moment.js 的 2kB 轻量化方案
- RelativeTime:相对时间
- 国际化 (i18n)
- 时区
- ISO格式的UTC时间与本地时间的互相转化
- 聊一聊 GMT、UTC 以及 ISO8601
- 时区名称:List of tz database time zones 或 タイムゾーン一覧
-
解决方案:将 Body 返回的日本时间解析成当时的 UTC 时间;获取当前 UTC 时间;两者计算相对时间;然后加入国际化。
import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' import timezone from 'dayjs/plugin/timezone' import relativeTime from 'dayjs/plugin/relativeTime' import 'dayjs/locale/zh-cn' dayjs.extend(utc) dayjs.extend(timezone) dayjs.extend(relativeTime) const commentCreateTimeUTC = dayjs.tz('2023-08-04 17:18:28', 'Asia/Tokyo') const nowTimeUTC = dayjs.utc() console.log('relative time: ', nowTimeUTC.locale('zh-cn').to(commentCreateTimeUTC))
-
-
我觉得写代码有两种状态,一种状态是使用非常合适的非常好用的库,可以非常简单方便的实现各种需求,几行代码就可以达到非常不错的效果;另一种状态,就是不存在这样合适的库,这种情况,要么是使用不那么合适的库,结果你需要各种 Hack,代码写的很乱,几百行都不够,要么就是自己去实现一个合适的好用的库,当然这个不仅花费时间更长,对开发者的要求更高。我们都认同,合适的工具能够达到事半功倍的效果,在编程的世界里,就是找到那些合适的编程语言、框架、库来实现自己的需求,找不到就去实现;这就是编程的乐趣,你既可以成为工具的受益者,也可称为工具的创造者。(PS:使用 dayjs 有感)
20230803
-
类似 ts-ignore 忽略某行的类型检测,可以用
eslint-disable-next-line
忽略某行的 ESLint 规则,参考 Disabling Rules -
UI Bakery RegEx Library,正则表达式规则集,常用的根本不需要自己写
-
classnames 方法,用于将多种类型变量合并成 css class 的值(string)。
-
Deploying MySQL on Linux with Docker Containers
- mysql - Official Image | Docker Hub:例子过于简单
- Mysql 的 Docker 部署文档:之后 docker 命令的例子
- docker-compose でMySQL環境簡単構築:单个 MySQL 服务
- How to create Master-Slave MySQL 8 with docker-compose.yml/MySQL 主从复制原理及配置: MySQL服务的主从架构
- A step by step how to start docker-compose container at boot:Container 使用
restart: always
后会跟随 Docker daemon 一起启动。
-
ProgrammersLevelUp:用20年时间跟着皓叔刷“程序员练级攻略”。
- READ: 《入门篇》和《专业基础篇》中的那些书和文章,你肯定是得认真精读的,这是基础。
- WRITE: 你需要完成一个能用的项目,对于选择什么样的项目,这里,我也有几个建议。第一,从自己的痛点出发,写一个能解决自己问题的东西。第二,临摹别人的作品,复刻一个其它的成功产品。有人说,学好一门语言或是一个开源软件最好的方式,就是用想学 / 喜欢的编程语言翻译下这个开源软件,比如,你用 Go 语言翻译一下某个 Java 的组件。第三,深度参与一些你喜欢的开源项目。第四,在工作中找到风险可控的项目和需求。
20230802
-
自动国际化/多语言/i18n
- 前端自动国际化解决方案:通过
\p{Han}
这个正则,就可以写一个脚本,将原本中文翻译成英文并替换为$t('English')
或t('English')
,同时所有中文提取到一个文件中用于接下来的翻译。- How to match chinese characters with grep?:
cat /tmp/test | grep -P '[\p{Han}]'
,参见 Unicode Scripts。 - JS 中的 Unicode:修饰符 “u” 和类 \p{…}/Javascript unicode string, chinese character but no punctuation:
/\p{Script=Han}/u.test(char))
- How to match chinese characters with grep?:
- i18n-ally:vue-i18n 官方推荐的插件,配置好了后就大大减轻了工作了,虽然还是需要调整。
-
Doesn’t work with Vue and vuex-i18n:我安装好后发现只识别 vi.json 文件,之后通过查看 output 中 i18n-ally 的 log 发现其他语言文件语法错误,最后一个键值对带了逗号,导致 i18n-ally 报错。
-
配置
sourceLanguage="locale"
即提取的键值存到对应的 locale.json 文件中;displayLanguage="locale"
即能够将 $t(‘key’) 中的 key 映射为 locale.json 中 key 对应的 value,从而实现预览。 -
现代 Vue 工程之「国际化 i18n 开发」 - JOYK Joy of Geek, Geek News, Link all geek
-
Nuxt3 下配置如下
{ "i18n-ally.localesPaths": "./lang", "i18n-ally.keystyle": "nested", "i18n-ally.sourceLanguage": "zh-CN", "i18n-ally.displayLanguage": "zh-CN", "i18n-ally.sortKeys": true, "i18n-ally.keepFulfilled": false, "i18n-ally.pathMatcher": "{locale}.{ext}", "i18n-ally.enabledParsers": [ "json", "json5" ], "i18n-ally.translate.engines": [ "google", "google-cn", "deepl", ], "i18n-ally.translate.deepl.useFreeApiEntry": true, }
-
- 前端自动国际化解决方案:通过
-
多语言切换,域名会变成服务器的私有 IP 10.2.0.10,再刷新后又正常了,在本地测试没有问题,但是实际上线后就有这个问题。
- 之前为了获取语言切换后后台返回的多语言数据,使用了 window.location.reload(),现在考虑不用,而是在语言切换的时候重新请求相关的接口;但是之前请求用的是 cookie,会比语言切换慢一步,比如从中文=>日文=>繁体,那么选择日文展示的是之前选择的中文,选择繁体展示的是之前选择的日文,因此考虑用 pinia store 这个状态管理来存 locale,这样就可以获取最新的值;但是第一次使用时会检测浏览器默认语言,store 就没办法知道了检测的值了,只能考虑同时用 store 和 cookie,store 默认值为空,这样第一次用 cookie 的值。关于重新请求接口,Nuxt3 有一个 refreshNuxtData API,重新请求当前页面请求的 API,其他的则需要手动重新请求。
- 上面修改多语言行为后,发现没有解决跳向私有 IP 的问题,问题重新描述为——
npx nuxi generate
生成静态文件,通过 Nginx 部署到服务器,访问的时候如果 reload 页面,会跳到服务器局域网 IP。-
具体描述:直接 https://testweb.iruca.ai/create 会跳到 http://10.2.0.10/create; 但 https://testweb.iruca.ai/abcd 正确显示 404,因为正确 404 了,我猜测应该是前端的问题,但是前端实在找不到问题在哪里。之后我又尝试了 https://testweb.iruca.ai/create/(多了个斜杠),发现可以访问了,因此猜测是 nginx 配置问题。之前一访问就直接跳转了,其实可以用
curl -i https://testweb.iruca.ai/create
可以查看跳转前的内容,显示为 301 Moved Permanently(最好用这个来测,由于浏览器有缓存,更改 nginx 后并不能马上在浏览器上看到结果,还以为修改的无效呢!)。配置 Nginx 将 try_files 行中的$uri/
替换成了$uri/index.html
,问题就被解决了。 -
Nginx二级子路径请求,如何去掉尾部多余的"/“以及避免301重定向请求:导致 301 是 Nginx 默认行为——当访问URI时,如果访问资源为一个目录,并且URI没有以正斜杠(/)结尾,Nginx 服务就会返回一个301跳转,目标地址就是加一个正斜杠。
-
搞懂前端技術名詞 SSR與SPA:这次部署的就是 SPA 应用,特点是生成的 index.html 文件的主要内容是挂载点
<div id="__nuxt"></div>
,部署的特点是始终返回这个 index.html,nuxt 生成的静态文件中,pages下的页面都单独一个目录,目录中都是内容完全一样的 index.html。 -
Prepare NuxtJS for static deployment • Today I Learned:Nuxt SPA 部署的 Nginx 配置可以参考这个。
location /. { # Remove trailing slash and redirect it rewrite ^(.+)/+$ $1 permanent; # Redirect index.html rewrite ^(.+)/index.html$ $1 permanent; # Serve folder path via index.html try_files $uri $uri/index.html =404; # Serve a custom static error page error_page 404 /404.html; }
-
-
Nginx
- Nginx 极简教程
- 连前端都看得懂的《Nginx 入门指南》:代理其实就是一个中介,A和B本来可以直连,中间插入一个C,C就是中介。刚开始的时候,代理多数是帮助内网client访问外网server用的(比如HTTP代理),从内到外 . 后来出现了反向代理,“反向"这个词在这儿的意思其实是指方向相反,即代理将来自外网client的请求forward到内网server,从外到内。
- 增加nginx虚拟主机配置文件(conf.d):
域名.conf
只是一个用于区分的名字而已。 - nginx配置url重写
- Nginx 的正确发音是?:恩静克思
[ˈendʒɪnks]
- Nginx的server_name和location配置
20230731
- 维基百科有一个 Simple English 的版本,用最常用的单词解释各种事情。
- coinphd 的 admin 项目的路由,不是那种固定的路由,不像 nuxt 或 uniapp 那样,在 pages 目路下的路径就是路由路径,uniapp 还需要修改 manifest.json,而 nuxt 则是完全不需要了。admin 项目是根据调用 api 返回的路由数组,在全局前置守卫中动态地添加对应的路由。总的来说,路由方便程度 nuxt(web) > uniapp(mobie) > vite(admin),路由安全程度及自由程度 vite(admin) > uniapp(mobie) > nuxt(web)。
- 不论是前端、后端还是运维,掌握程序运行流程是开发的前提,一个是你要知道如何看现有的代码,一个是你要知道到哪里去改代码。就前端来说,运行流程就是路由,你在浏览器上输入网址,网址对应具体的页面,而该页面就是执行特定的代码文件所产生的,而你的任务就是根据网址找到对应的执行文件;像 Nuxt、Next 这种,网址的路径对应 pages 下的路径,就比较简单直接;像 uniapp、antd 这种,网址与执行文件由路由配置来进行映射,这种关键就是找到路由配置文件。就后端来说,与前端基本上一致,像 Nest 这种,路由就自动对应着 routes 目录下 controller 文件;像 PHP 这种,默认路由就是在 controller 目录下的路径,但是也可以通过配置文件来进行配置。就运维来说,执行文件变成了运行的 docker,你的任务,就是根据特定的域名,找到对应的docker容器,将来自互联网的请求交予它处理。掌握了路由后,你就可以在路由的某个阶段,或者某个路由中添加东西了,进行开发了。万事开头难,掌握了第一步后,接下来的就简单了。你看图灵机,程序的本质,就是按照顺序执行一个又一个的任务的,面向过程、面向对象、函数式等编程方法,还有各种框架,各种工具辅助等等,本质还是按照顺序执行一个又一个的任务,而要去理解,也就是自己去按照顺序执行一个又一个的任务。
- 项目中前端如何实现无感刷新 token!:评论很有意思。
- 第一种,accessToken + refreshToken:accessToken的特点是使用频繁但有效期短。使用频繁是因为它会在每个请求中传输,所以它更容易泄露。refreshToken的特点是有效期长,但使用频率很低。它长期存在本地,不会随着每个请求传输,所以不容易泄露,但又能延长真正的过期时间。所以两个token的搭配,既保证了用户可以长时间不退出,又尽量降低了token泄漏的风险。
- 第二种,单token后端动态延长有效期:当用户一直在操作页面调用接口且当前token没过期时,后端统一在拦截器中自动续时确保token永远不会过期,这样就可以避免突然让用户去登录。当用户长时间未操作页面token失效时,拦截器返回401跳转登录。也起到使用token鉴权的目的。
20230729
- 2023 年香港手机卡完全攻略:hahasim
- 程序员劳动法赔偿 101
- WARP:旨在确保您的数据在传输过程中得到保护,不是用来让你访问受地理限制的内容的。
- aircrack-ng 破解 WIFI 密码: https://github.com/conwnet/wpa-dictionary
- Stable Diffusion 新手入门手册:像素图片模型 Pixel art style
- xLog
- Coursera(
/kɔːrsˈɛrə/
) - 如何用3个月零基础入门「机器学习」?
- 网易公开课vs网易云课堂:网易公开课能学到幸福是什么、公正的意义等等具有普世价值的形而上层面的内容,而云课堂则更加入世,直接教你谋生的技能。两者的部分免费课程有重叠,但是凡事免费内容,都可以在BiliBili 找到的。
20230726
- 如果发现 vscode 报错 Cannot find module,但是 tsconfig.json 确实配置好了的,可以考虑重启 vscode,这样就行了。
- 聊聊 EventStream 服务器端推送
- JS 中的 Reflect 和 Proxy
- CSS gap属性进化史
- String.prototype.split() 是支持正则表达式的。
- Microsoft Learn:Microsoft 的教程!
- Blockchain
20230725
- PHP 部署问题
- file_put_contents (/chat/server/runtime/cache/…): Failed to open stream: No such file or directory
- file_put_contents:没有文件就创建前提是——你资源路径得存在,并且有权限
- 在docker-compose.yaml中,
./server
目录是 mount 到容器的chat/server/
,因此实际是问题是./server/runtime/
不存在或者没有权限,解决办法就是创建或者加权限 - 还是没有仔细的看报错,而是去试各种方法期望能幸运地解决问题,对 PHP 有一种新人的恐惧,停留在不知道、不了解的心理状态,失去了对 PHP 的深入学习的动力。
- SQLSTATE php_network_getaddresses: getaddrinfo failed: Temporary failure in name resolution:原因是没有添加 .env 文件,也就没有提供 mysql host。
- Turning expose_php OFF in php.ini:the
X-Powered-By
header. - 关键文件:server 即为 thinkphp 项目根目录,被直接 mount 到 docker 中
- /server/.env 环境变量
- /server/runtime 应用的运行时目录,是一个存储程序运行时生成的临时文件的地方。通常,它包含了缓存文件、日志文件、临时文件等,这些文件不是程序的核心部分,但是却非常重要。在程序运行过程中,这些文件可以被动态生成和更新,以满足程序的运行需求。当程序关闭后,这些文件通常会被删除,因此它们不会对系统造成永久性的影响。
- /server/public/uploads 上传或者生成的图片等资源
- /server/public/debug.txt
file_put_contents('debug.txt', 'info')
输出位置
- file_put_contents (/chat/server/runtime/cache/…): Failed to open stream: No such file or directory
- Nested CSS was detected, but CSS nesting has not been configured correctly:uniapp 项目,给
<style>
添加上lang="scss"
属性就行了——<style lang="scss">
- 谈谈像素以及微信小程序的 rpx
- TypeScript 中的代码清道夫:非空断言操作符:ts变量函数后面的感叹号有什么用处?
20230722
-
OAuth2
-
理解OAuth 2.0:在前后端分离的项目中,客户端是前后端的整体,具体某个步骤由前端执行还是后端执行,在不同的实现之中并不相同。
- 流程如下:
- 用户访问客户端,后者将前者导向认证服务器。(client_id)
- 用户选择是否给予客户端授权。
- 假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI”(redirection URI),同时附上一个授权码。
- 客户端收到授权码,附上早先的"重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。(client_secret)
- 认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
- 实现方式:要理清,就需要抓住关键的输入参数,分别是 client_id、client_secret、redirect_uri,这些参数由前端给还是后端给,就导致实现的不同。
- 前后端交互 OAuth 认证:参见前后端分离基于Oauth2的SSO单点登录怎样做?图示。这种方式,前端用 client_id 去获取授权码 code,redirect_uri指向前端,然后前端将 code 传给后端,后端用 client_secret 去获取 access_token,最后生成 token 给前端。
- 后端 OAuth2 认证:例如 passport-google-oauth20。在这种方式中,前端只需要添加一个指向后端链接,剩下的所有操作都由后端完成;redirect_uri 指向后端,后端通过 client_id 和 client_secret 去获取授权码 code 与 access_token,最后生成 token 给前端。
- 流程如下:
-
How to send JWT to front end server after successful login for storage on localStorage?:在后端 OAuth2 认证认证方式中,所有操作都在后端执行,后面就有一个向前端发送 token 的问题。可以参考文章 NODE AUTHENTICATION WITH GOOGLE OAUTH: PART 2 (JWTS)
- redirect 到前端,token 放在 url 中,如果 CDN 缓存了 token,会导致安全问题。
- redirect 到前端,url 中放一个一次性的 code,前端再去 code 请求 token。
- 同域直接种植 Cookie,然后 redirect 到前端。
- window.open & window.postMessage 方式:前后端分离下的第三方登陆处理(最优)
-
Why does JavaScript “window.postMessage” create duplicate messages?
const receiveMessage = (event)=> { window.removeEventListener('message', receiveMessage, false); console.log(event.data) // do something else } window.addEventListener('message', receiveMessage, false);
-
Specifying multiple targetOrigin uris in postMessage:postMessage 不支持多个域名,只能重复发送了
targetWindow.postMessage(message, "https://domain1.com"); targetWindow.postMessage(message, "https://domain2.com");
-
Open a URL in a new tab (and not a new window):
window.open(url, '_blank').focus();
-
-
移花接木:针对OAuth2的CSRF攻击:加入了 state 后,攻击者需要被攻击者的 cookie,攻击者的 Authorization Code,随机的 state 才能攻击进入被攻击者的第三方账户。
-
-
CORS
- Cors跨域(一):深入理解跨域请求概念及其根因
- Cors跨域(二):实现跨域Cookie共享的三要素:服务器要向不同域名的网站种植 Cookie,要求服务器 Access-Control-Allow-Credentials为true、客户端请求withCredentials为true。
- Cors跨域(三):Access-Control-Allow-Origin多域名?
- Cors跨域(四):解决方案对决JSONP vs CORS
-
PHP使用OAuth2实现Google登录:从前端获取授权码
20230721
- setTimeout 与 setInterval —— 实现优雅轮询:使用 setTimeout 做轮询比 setInterval 更好。
- 5000 多字,让你一文掌握 TS 枚举:可以直接打印 enum 看看数据结构是怎么样的;要遍历 ts enum,要么用字符串枚举,要么通过
isNaN(Number(item))
过滤掉数字枚举数字;但是不推荐使用在运行时代码逻辑里,因为 enum 用于类型定义,只不过由于TS设计的特殊性它混入了运行时。 - socket 到底是个啥
20230720
- Safari Reader 打印 PDF。
- 腾讯云开发者社区的文章很适合打印的。
- 对于 51CTO,主要是行号导致的问题,通过代码删除:
document.querySelectorAll('.pre-numbering').forEach(item => item.parentElement.removeChild(item))
- 微前端究竟是什么?微前端核心技术揭秘!
20230719
-
PromptArt 图片提示词优化
-
Mac-AI-fy 智能化操作
-
Can HTTrack download a subdirectory?:
httrack www.example.com/subdirectory/ -D -O "C:\Users\subdirectory"
-D makes it so the process “can only go down into subdirs”。注意 subdirectory 要带反斜杠,即 subdirectory/
-
grep -P no longer works on MacOS.:
brew install grep
20230718
-
Mobile (uniapp)写的多语言选择没有显示出来(why?),在本地测试是有的啊!草!经过查找发现是 GitHub PAT 过期了,报错
Support for password authentication was removed on August 13, 2021.
。 -
博客:Eric Fu
-
0xaaiapiphp
-
Error: php@7.4 has been disabled because it is a versioned formula!: 原因是php7.4已经不在维护,可通过第三方源安装(注意,下面都是用 docker 进行开发,其实是不需要安装 php 的)
brew tap shivammathur/php brew install shivammathur/php/php@7.4
-
OrbStack:替代 Docker Desktop。项目整体用 docker 来开发测试,后面也直接通过此方式来部署。项目是直接将源文件 mount 到容器中,所以更改之后能够立马测试。若说 redis 与 mysql 可以远程,但是 php-fpm 与 nginx 则是必须的,所以直接本地开发还是比较麻烦的。通过看 docker-compose.yml 来了解项目是怎样运行的,核心是 nginx 的配置,root 指向 ThinkPHP 的入口文件;php-fpm 用的likeshop/php:8.0.22-fpm镜像,这个镜像在 Google 中搜不出来,需要到 Docker Hub 中先搜索 likeshop 仓库,然后进入 likeshop/php 镜像页面中选择 tag。
-
Clash 启用自定义DNS后,系统本地的hosts文件解析被绕过了:Change default system ignore list
-
Mysql docker container keeps restarting: 是因为下面这一句,docker 容器将 lib 目录挂在在了系统目录上,我以为是我需要配置的,因此是直接复制过来的,但实际是容器本身的内容给挂载出来。我的系统是 arm,服务器是 amd4,因此不断重启。
./config/mysql/mysql5.7.29/lib:/var/lib/mysql
-
DBeaver Restore a database from a SQL export:
- Right-click the database and click Tools > Execute script.
- dbeaver: native client is not specified for connection: “Local Client …” => “Browse …” => mysqldump executable
- Mac OS X 快速访问根目录的4种方法:使用快捷键 Command + Shift + G 快速激活“前往文件夹”功能
- Install only mysqldump on macOS:
brew install mysql-client
- Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’: Changing host from localhost to 127.0.0.1 helped.
- ‘Access denied; you need (at least one of) the PROCESS privilege(s) for this operation’ when trying to dump tablespaces:
--no-tablespaces
-
-
Javascript中对象如何检查key(键)是否存在:in操作符、hasOwnProperty方法。
-
Omniinfer: Fast and cheap AI image generation API.
-
PhpStorm:
- Single Click To Open File:project 的设置图标
- Enable Preview Tab
- Always Select Opened File
- Presss Ctrl+R or select Edit | Find | Replace from the main menu to open the Replace in File window.
- 升级 macos 13 后 intellij 系列编辑器闪屏?:在 Help | Edit Custom VM Options 添加配置项目
-Dsun.java2d.metal=false
- How to use directly function key (F1 - F9) instead of pressing fn + function key in IDE in OSX?: Preferences > Keyboard > Shortcuts > Function Keys,之后用
fn
+function key
方式来调亮度与声音等。 - IntelliJ - Upper|Lower: ⌘ + Shift + U
- 全局查找文件:Shift + Shift
- 全局查找文件内容:Command + Shift + F
- IDEA 如何快速跳到下一行:Command + Shift + Enter
- Single Click To Open File:project 的设置图标
20230717
- Paypal怎么用?Paypal使用教程详解
- 一起学Docker
- JS URL()和URLSearchParams() API接口详细介绍
- 【前端开发技巧】npm install xxxx –legacy-peer-deps到底做了些什么?
- 彻底搞懂Vue中的Mixin混入(保姆级教程)
- 教你如何实现单卡iPhone实现双卡双待。
- 移动卡:无忧行(打电话、收短信)+和飞信(发短信)
- 两台 iPhone:iMessage 短信转发+呼叫转移
- 折磨人的携号转网:看清楚这4点再动手!:携号转网每个运营商 App 都有通道并且有教程。
- CXXZ#用户姓名#证件号码 发送至拟转出的运营商(电信10001,移动10086,联通10010)
- SQXZ#用户姓名#证件号码 申请授权码
- 携号转网,用不完的话费余额怎么办?
- iCloud账号转区教程
- 2022最全美版Paypal注册教程(绑定美版Apple ID+如何解除风控+注意事项)
20230715
- CGI是什么
- How To Install PHP 7.4 and Set Up a Local Development Environment on Ubuntu20.04:~~其实可以直接通过 docker 运行,这样就可以不考虑平台了。~~只用于部署的话,docker很合适,但是用于开发的话,就不大方便了,但不是不行。
- How to develop PHP inside a Docker Container using VS Code:核心是 devcontainer.json,不过要考虑到 apple m1 是 arm 而不是 amd64,这个可能导致问题,arm 服务器并不是主流。
- LearnKu:LearnKu 诞生的故事
- Python常用魔术方法:魔术方法在类或对象的某些事件出发后会自动执行,让类具有神奇的“魔力”。如果希望根据自己的程序定制自己特殊功能的类,那么就需要对这些方法进行重写。
- 压缩即泛化,泛化即智能
- 关于SIM和eSIM,看这一篇就够啦!
- DigitalOcean是如何计算费用
- DNS域名解析中A、AAAA、CNAME、MX、NS、TXT、SRV、SOA、PTR各项记录的作用
- Azure免费服务用量注意点集合,避免扣费暗坑
20230714
- 如果是 PC 跳到 web.iruca.ai,如果是 Mobile 跳到 m.iruca.ai:方法就是加一个判断,然后跳转;可以在服务端判断,也可以在客户端判断;可以用 UserAgent 判断,也可以通过 viewport 尺寸来判断。
-
export function useWebSelection() { const pcDomain = import.meta.env.VITE_PC_DOMAIN || '<https://testweb.iruca.ai/>' const mobileRegex = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i const isMobile = navigator.userAgent.match(mobileRegex) const isWide = matchMedia('(min-width: 1200px)').matches if (!isMobile && isWide) { window.location.href = pcDomain } }
20230713
- 经验
- Apifox:API 文档、API 调试、API Mock、API 自动化测试
- Mac 配置
- 安装 Xcode Command Line Tools,包含 git:
xcode-select --install
- 安装 Clash for Windows 或 ClashX/ClashX Pro:否则无法安装 Homebrew。推荐 ClashX Pro 搭配 Clash Premium 开启 Enhanced Mode (tun 模式)使用。
- 安装 Homebrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- 开启 openssh server:How to Turn On SSH on Mac
- 安装 Caffeine: Don’t let your Mac fall asleep.
- 复制配置文件:.oh-my-zsh、.zshrc、.zprofile、.npmrc、.ssh、.vimrc
- 安装开发 GUI 工具:item2、visual-studio-code、google-chrome、firefox、tailscale、postman、dbeaver-community、another-redis-desktop-manager
- 安装开发 CLI 工具:node@16、yarn、rust、openjdk@11
- 克隆公司仓库:coinphd、iruca
- 克隆个人仓库:dishizhihui-codes、dishizhihui-logs
- 安装其他软件:lark、wpsoffice、shottr、adrive、vlc、keyboardcleantool、neteasemusic
- 复制目录 Movies;备份 Projects
- 安装 Xcode Command Line Tools,包含 git:
20230712
-
How to copy with cp to include hidden files and hidden directories and their contents?
# 将 dir1 复制到 dir2 下,即 dir2/dir1 cp -av dir1 dir2 # 将 dir1 的内容复制到 dir2 目录下 cp -av dir1/. dir2 cp -av dir1/ dir2
-
COINPHD 项目技术栈
-
-
- Reactivity
- Class and Style Bindings
- Watchers:
watch(source, (newValue, oldValue) => {}, config)
- Components
-
<template>
: .vue 顶层<template>
下的<template>
不会直接显示,需要带有指令来控制其怎样显示<template v-if="true">
-
- Binding Multiple Properties Using an Object:在 React 中是
<CustomComponent {...propsObject} />
,而在 Vue 中是<CustomComponent v-bind="propsObject" />
- 设置多个类型与默认
-
Prop Validation/How can I set the local default value in defineProps?
const props = defineProps({ index: { type: [String, Number], required: true, default: 0 } })
-
withDefaults/How to import interface for defineProps
const props = withDefaults( defineProps<{ msg?: string labels?: string[] }>(), { msg: 'hello', labels: () => ['one', 'two'] } )
-
- Binding Multiple Properties Using an Object:在 React 中是
-
- Named Slots 可以在指定 slots 位置渲染
- Scoped Slots 让父组件访问子组件状态。列子如 How to handle a slot’s onClick event in VueJS。
-
- Plugins
- API
-
$nextTick():
await nextTick()
-
<script setup lang="ts"> import { getCurrentInstance } from 'vue' const instance = getCurrentInstance(); instance?.proxy?.$forceUpdate(); </script>
-
- Reactivity
-
Vue i18n
- vue-i18n@9(Vue3 i18n)/vue-i18n(Vue2 i18n)
- Getting started:大致用法
- Scope and Locale Changing
- Composition API:Vue3 的选项式 API。
- Add i18n and manage translations of a Vue.js powered website:不同于 lingui,vue-i18 是可以翻译变量的。
- @intlify/unplugin-vue-i18n for vite4,安装后可以使用 json 文件作为 message
- vue-i18n@9(Vue3 i18n)/vue-i18n(Vue2 i18n)
-
- Env Variables and Modes:
import.meta.env.VITE_SOME_KEY
- Glob Import:
const modules = import.meta.glob('./dir/*.js', { eager: true })
- Static Asset Handling
- vite-plugin-svg-icons:把 svg 处理为组件的库,需要重启以生效新 svg
- vue-social-sharing:社交媒体分享组件,同 react-share
- nprogress: progress bars
- Env Variables and Modes:
-
Nuxt: Vue.js Web Framework
-
- useRoute
- useRouter
- navigateTo:跳外站要用
navigateTo(url, { external: true })
-
Data fetching: useFetch, useAsyncData and $fetch
- ofetch: Works on node, browser and workers. nuxt 用于发送 ajax 请求的库。
-
Components Directory: Nuxt automatically imports any components in your components/ directory(同 uniapp,Nuxt
@/components
下组件也是自动引用与注册的) -
refreshNuxtData:类似 useSWR 的 mutate,重新请求 API,只限于当前页面。
-
device-module: detecting device type.
-
process.server
andprocess.client
:用于判断是否是 SSR,文档中没有相关词条,但是在别的词条的例子中有使用。-
How can I get window.location.href in Nuxtjs V3
if (process.client) { console.log(window.location.href) }
-
Nuxt Image:
<nuxt-img>
只支持 public 下的图片;使用原生<img>
,可以使用 vue + vite 项目的各种特性。- Assets:因为 assets/ 下的资源需要对应 build tool,因此
<img src="@/assets/img/nuxt.png" />
方式可以访问,<img :src="imagePath" />
中即使imagePath='@/assets/img/nuxt.png'
依旧不可以访问。 - Static Asset Handling/How to import and use image in a Vue single file component?
-
Importing Asset as URL:直接 import png 文件
-
new URL(url, import.meta.url)/Nuxt dynamic image - Require is not defined
const imgUrl = (png: string) => { return new URL(`../../assets/${png}`, import.meta.url).href }
-
- Assets:因为 assets/ 下的资源需要对应 build tool,因此
-
Nuxt Lifecycle:client 中,plugin 在 middleware 之前进行处理,要根据设备类型跳转到指定网址,那么我认为放在 plugin 比放在 middleware 更合适,原则是在跳转前执行最少的步骤。
-
- Basic Usage:使用
const { locale } = useI18n()
报错Cannot find name 'useI18n'.
,原因是因为要从 ‘#i18n’ 导入而非 ‘#imports’ 导入,而这些就定义在 tsconfig.json 的 paths 属性中,这表明自己对 ts 并不熟悉啊! - Routing & Strategies:为多语言添加路由前缀。Strategies 如果是 no_prefix,要用
@click="setLocale(code)"
方式以保存 cookie,如果是包含 prefix 方式,那么要用<NuxtLink :to="switchLocalePath(code)">
方式。 - Browser language detection:检测浏览器语言并存入 cookie。本地开发没有看到存的 cookie 键值对,但是上线后确实看到了 cookie 键值对。
- Lazy-load translations:通过目录 lang 下的 json 加载多语言。写在 i18n.config.ts 找不到 message,写在 nuxt.config.js 正常运行
- Lang Switcher
Property 'code' does not exist on type 'string | LocaleObject'.
,在返回的时候 computed 断言返回类型locales.value as LocaleObject[]
,从'#i18n'
中导入。- 这个会直接更改 Browser language detection 初始化的 i18n_redirected cookie 值。
- Locale fallback
- Per-component translations:可以从 useI18n() 中解构出 t 函数,让后通过
watch(locale, () => t('key'))
在<script>
中翻译。 - Composables:
useCookieLocale
- Basic Usage:使用
-
Element Plus: Vue 3 based component library
-
uni-app:uniapp 的文档不怎么好,定位是参考手册而非教程,不适合通过直接阅读来学习;它要求拥有 vue 基础,适合在编写项目过程中,通过解决各种问题来学习如何使用。uni-app 的 api 都是适用于多端的 api,因此最好使用它的提供的 api,而非原生的 h5 等 api;除非实在没有,那么就通过条件编译分别调用各平台 API。
-
- 页面:
- 每次新建页面,均需在pages.json中配置pages列表。
- onLoad生命周期函数: 其回调函数的参数为上个页面传递的数据
- onReachBottom、onPageScroll、getCurrentPages()
- 互相引用:通过 easycom,组件只要安装在项目根目录的components目录下,就可以不用引用、注册,直接在页面中使用。也不能去引用,比如 lang-switch 可以手动导入,lang-switcher 却提示找不到。这也将导致无法快速跳到组件定义文件。自定义配置查看 package.json 下 easycom
- 条件编译处理多端差异:可以指定某部分代码只编译到特定的终端平台。
- 页面:
-
- 网络
- 页面和路由
- uni.navigateTo(OBJECT):要打开web url,参考 u-link
- uniapp-router-next
- 适用于 uniapp 的 vue3 router,提供
router-navigate
组件用于路由。 - 使用
useRoute()
替代 getCurrentPages() ,更方便地获取当前的路由信息。
- 适用于 uniapp 的 vue3 router,提供
- uni-app 页面应用内跳转与应用外跳转的实现方式:即 web-view 方式
- uni-simple-router:支持路由别名 aliasPath
- 数据缓存
- 非 H5 端不支持自动保持 cookie,服务器应避免验证 cookie。
- 设备
- 剪贴板:
uni.setClipboardData(OBJECT)
- 剪贴板:
- 界面
- uni.showToast(OBJECT)
- uni.showLoading(OBJECT):
uni.setClipboardData(OBJECT)
- uni.createIntersectionObserver():观察者模式 api,用例 u-lazy-load
-
vk-uview-ui/uView:UI 库,组件都以
u-*
开头。- Image
- Select:从底部滑出菜单。本来想用 Dropdown,但是没有显示item的内容。
- Tabs
- Waterfall
- Card:只展示主题内容
:showHead="false"
- LazyLoad
- 表现为不能显示默认的 loadingImg 和 errorImg。只有 Safari,原因是 Safari 不会渲染字符数不能被 4 整除的 base64 图像。我将base64转为png图片再替代。
- 表现为首次进入页面高度很高,与宽度不成比例,过一会儿宽高成比例。Chrome 遇到几次,很快恢复正常;Safari 是每次,并且刷新才正常。(Safari即前端地狱)
- 原因是先使用默认高度450rpx,之后再用 widthFix 计算的高度值。尝试用
height: auto
,Safari 直接不显示图片,因为 Safari 的 height默认值为 0,Chrome 为图片高度。 - 要解决 Safari 中 height 默认值为 0,就必须给出具体的 height 值。通过获取容器宽度与图片的宽高,依照图片宽高比例计算出容器的高度。
- console.log 在safari中调试不显示:用console.debug代替console.log来解决
- uni.getImageInfo(OBJECT):获取图片比例
- uni.createSelectorQuery():获取容器宽度
- 在 Safari 中不 height 能用 rpx,会转换成 rem,导致图片变形,必须使用 px 才能正确够显示。
- 参见 lazy-load.vue
- 原因是先使用默认高度450rpx,之后再用 widthFix 计算的高度值。尝试用
- Popup:可从上下左右四个方向弹出。
- Field:
type="textarea"
使用文本框;默认label占有宽度,可以设置:label-width="0"
以使输入框占据全部宽度 - tabs:不能用 v-show 控制要显示的组件,因为会导致第二个组件宽度不对,与 SwipeAction 会导致其不能显示按钮(草,这里浪费了好多时间),应该用 v-if。
-
uni-z-paging:下拉刷新、上拉加载
-
-
ThinkPHP:编程语言是编程的基础,必须要整体学一下;框架则只需要看基础部分,剩下的用到哪些就看哪些,毕竟光看是学不会,也是很枯燥的;总之,判断的标准就是能不能开始写东西了,可以了就说明可以通过遇到问题来学习知识。
-
PHP 手册:官方教程部分没有翻译完,并且讲的太细,适合做参考手册,并不适合新人的教程。
- Unix 系统下的安装
- 魔术常量:
__DIR__
当前文件所在的目录。 - implode:同 js 的 Array.prototype.join() 方法。
-
PHP 入门到实战教程:非常好的入门教程,看完之后完全可以开始写东西了。
-
- 配置目录:
use think\facade\Config;
- 相同的数组名,下面的
[ArrayName]
定义会覆盖了上面定义,不会自动合并,因此要写在一起。
- 架构:至少看这部分,知道怎么个执行的流程(路由),如果要写,要在哪里加东西。
- 模型:即数据表的定义与操作
- 调试模式
- 缓存:Redis
- 多语言:
allow_lang_list
写的是全称,如 en-US,那么即使客户端 Accept-Language 为 en,依旧可以被识别为 en-US。Accept-Language
先于 use_cookie,但是最好还是一开始就设定好 cookie 的值,而不是去改变 Accept-Language。
- Libraries
- thinkphp-social:社会化登录扩展
- orhanerday/open-aiZ: OpenAI PHP SDK
- stripe/stripe-php
- ThinkPHP 6.0 速查表
- 配置目录:
-
- How do I embed PHP code in JavaScript?: 可以使用原生php代码
var my_var = <?php echo json_encode($my_var); ?>;
- How do I embed PHP code in JavaScript?: 可以使用原生php代码
-
-
-
Erase your Mac and reset it to factory settings: Erase All Content and Settings
20230711
20230710
- 经验
-
-
FreeBSD:ZeroTier 不需要开放端口
sudo pkg install zerotier sudo service zerotier enable # 自带 service,Nice! sudo service zerotier start sudo zerotier-cli join 233ccaac270f677c
-
How can zerotier on OSX be paused?
# You can stop the service with: sudo launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist # It will start on next boot or: sudo launchctl load /Library/LaunchDaemons/com.zerotier.one.plist
-
-
-
- 首先看一下 Getting Started
- 然后在 Community Contributions 中找到要安装的平台的安装包
- 最后设置防火墙 Firewall Setup:要打开 22000/TCP、22000/UDP、21027/UDP
-
Ubuntu 参考 Syncthing – Install and Setup Syncthing on Ubuntu/Debian:两个命令就安装好了
sudo apt install syncthing sudo systemctl enable syncthing@username.service
-
MacOS
# Install brew install syncthing # Test /opt/homebrew/opt/syncthing/bin/syncthing -no-browser -no-restart # Run as serivce brew services start syncthing # Access the GUI via the following URL: http://127.0.0.1:8384/
-
FreeBSD:需要打开对应的端口
sudo pkg install syncthing sudo sh -c "echo 'pass in proto tcp from ue0:network to port 22000' >> /etc/pf.conf" sudo pfctl -f /etc/pf.conf sudo crontab -e @reboot kurome:kurome sleep 60;/usr/local/bin/syncthing&
-
Tips:
- 在连接设置中,只打开了本地发现;传输速度受限于路由设备(随身 WIFI,不到 5MB/s)
- 只需要在一个设备添加文件夹就可以了,不需要两个设备同时添加,分享后就是双向同步的了
-
-
Pkg Primer: pkg search -f packageName 展示 remote package info;pkg info packageName 展示 installed packageName。
20230707
- 经验
-
VS Code Remote Development
-
curl -fsSL https://code-server.dev/install.sh | sh sed -i.bak 's/auth: password/auth: none/' ~/.config/code-server/config.yaml sudo systemctl restart code-server@$USER ssh -N -L 8080:127.0.0.1:8080 [user]@<instance-ip>
-
JS 反调试
-
NixOS 与 Nix Flakes 新手入门:NixOS 与 Flakes 一份非官方的新手指南
-
20230706
- 经验
-
Jest 实践指南:很好的教程
-
整合 Line 登录:Line 注册要手机号,国内手机号不支持
-
passport-line-auth:Line 的 Strategies 比较少,这个最近一年内更新了的,实际测试可用
-
nodejs/passport - Error: OAuthStrategy requires session support
// Authentication configuration app.use(session({ resave: false, saveUninitialized: true, secret: 'bla bla bla' }));
-
整合 Apple 登录:Apple 登录需要开发者账号,开发者账号要钱
20230705
- 经验
- iPhone 怎么复制短信中的部分内容?:选择转发,就可以在编辑栏再复制部分短信了。
- How to Fix PR_END_OF_FILE_ERROR: 3 Methods That Work:我配置 Firefox 的 Proxy DNS when using SOCKsv5 解决了访问 Gooogle 产生 Secure onnection failed 这个问题。
- Static Exports:Next.js 是可以来写静态博客部署到 Github Pages 的。
- How can I keep the code formatted as original source when I paste them to vim?:
:set paste
, then after:set nopaste
- 静态博客全文搜索简单调查
- Safari Translation Not Working On Mac/IPhone: How To Fix: Download Language for Offline Translation. System Settings > General > Language & Region.
20230704
- 经验
- CSS实现footer“吸底”效果
- 冷知识:不起眼但有用的String.raw方法
- How to set up NTP Clock Synchronization on FreeBSD with ntpd
- Using ssh_config Match to connect to a host using multiple IP or Hostnames
- Hugo setup:用 Github Action 部署 hugo 博客
- Hugo quietly builds empty index.html files: FreeBSD 上使用从 gihub release 上下载的 hugo 遇到此问题,没有报错,就是不 build content 下的博客,搞了一晚上都没有解决,最终通过 pkg install gohugo 解决,这个版本也是 freebsd hugo 的 extended edition,这在 github release 上是没有的。具体思路就是尝试 hugo 的 quick start 教程看看能不能正常运行,结果不能,主题报错,要求 extended edition。这也告诉我们,像 FreeBSD 这样本身更新很及时的,没有特殊需求,最好就用包管理安装软件。
20230703
- 经验
-
- 在Mac电脑中找出并选中要播放的视频
- 点击键盘按键command+I,打开文件简介
- 在文件简介窗口,找到打开方式一栏里单击下拉框,选择想要修改的程序
- 选择好后点选下面的“全部更改”在弹出的窗口中,点击“继续”即可完成。
-
视频直播方案
-
What’s a quick way to comment/uncomment lines in Vim?
- First, go to the first line you want to comment, press
Ctrl``V
. This will put the editor in theVISUAL BLOCK
mode. - Then using the arrow key and select until the last line
- Now press
Shift``I
, which will put the editor inINSERT
mode and then press#
. This will add a hash to the first line. - Then press
Esc
(give it a second), and it will insert a#
character on all other selected lines.
- First, go to the first line you want to comment, press
-
hugo server --theme=hugo_theme_robust --buildDrafts --bind "0.0.0.0" --baseURL "http://192.168.1.10:1313"
-
20230701
- 经验
-
A link to GitHub for downloading a file in the latest release: Get the latest release
curl -s https://api.github.com/repos/boxbilling/boxbilling/releases/latest | grep browser_download_url | cut -d '"' -f 4
-
crontab @reboot does not execute bash script when server is rebooted
@reboot root:wheel sleep 60;/home/kurome/clash/clash.sh @reboot root:wheel sleep 60;/home/kurome/bhyve/bhyve.sh
-
How to disable “screen blackening”
# !/bin/bash # screenblank - Toggle screen blanking/powersaving on/off XBLANKTEXT=$(xset -q | grep timeout | awk '{printf $2}') DPMSTEST=$(xset -q | grep " DPMS is Enabled") if [[ "$XBLANKTEXT" -gt 0 ]] || [[ -n "$DPMSTEST" ]]; then xset s off; xset -dpms echo " Disabled screen blanking and powersaving"; else xset s on; xset +dpms echo " Enabled screen blanking and powersaving" fi
或者直接添加到 .xinitrc
xset -dpms xset s off
-
Using “#define” in .Xdefaults?
- Try using xrdb(1) (it runs cpp(1)) in ~/.xinitrc, e.g.
xrdb -merge ~/.Xdefaults
- And make sure macros are substituted, e.g.
xrdb -query | egrep '(fore|back)ground'
- Try using xrdb(1) (it runs cpp(1)) in ~/.xinitrc, e.g.
-
VSCode Extension: Markdown Paste: Command + Alt + V
-
20230630
- 任务
-
const [isDesktop, setIsDeskop] = useState(true) useEffect(() => { const mql = matchMedia('(max-width: 1024px)') const handleMediaChange = () => { if (mql.matches) { // console.log('match') setIsDeskop(false) } else { // console.log('unmatch') setIsDeskop(true) } } handleMediaChange() // 首次查询 mql.addEventListener('change', handleMediaChange) return () => { mql.removeEventListener('change', handleMediaChange) } }, [])
-
设置锚点居页面顶部距离:页面滚动高度 = 元素到页面顶部高度 - 固定导航栏高度
const toAnchor = (id: string) => { const el = document.getElementById(id) if (el) { const react = el.getBoundingClientRect() const win = el.ownerDocument.defaultView if (win) { const offset = react.top + win.document.body.scrollTop const headerEl = document.getElementById('desktop-header') if (headerEl) { console.log('header height', headerEl.offsetHeight) window.document.body.style.scrollBehavior = 'smooth' window.document.body.scrollTop = offset - headerEl.offsetHeight } } } }
-
其他方法:锚点定位被顶部固定导航栏遮住的解决方案
-
let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
-
详解a标签中href=“javascript:“的几种用法:在a中调用js函数最适当的方法推荐使用
<a href="javascript:void(0);" onclick="js_method()"></a> <a href="javascript:;" onclick="js_method()"></a> <a href="#" onclick="js_method();return false;"></a>
-
let p = document.getElementById("pTwo"); let rect=p.getBoundingClientRect() let win = p.ownerDocument.defaultView; let offsetObj={ top: rect.top + win.pageYOffset, left: rect.left + win.pageXOffset } console.log(offsetObj,'win18')
-
-
FFMPEG
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -b:a 128k -c:a libopus output.webm
-
ffmpeg -i video.mp4 -c:v copy -c:a copy -f hls -hls_time 9 -hls_playlist_type vod -hls_segment_filename "video%3d.ts" video.m3u8 ffplay ./video.m3u8
-
- 合适的视频格式:WebM(VP9) 相较于 MPEG-4(x264) 来说会更小
- 视频压缩:HandBrake
- Video Streaming with Node.js / HLS
-
example
useEffect(() => { const hlsVideoSrc = '/videos/hls/chathomeai.m3u8' const videoEl = videRef.current if (videoEl) { videoEl.muted = true if (videoEl.canPlayType('application/vnd.apple.mpegurl')) { videoEl.src = hlsVideoSrc videoEl.onloadeddata = () => { videoEl.play() } } else if (Hls.isSupported()) { const hls = new Hls() hls.loadSource(hlsVideoSrc) hls.attachMedia(videoEl) hls.on(Hls.Events.MANIFEST_PARSED, () => { videoEl.play() }) } else { setIsSupportHls(false) } } }, [])
-
报错
SyntaxError: Unexpected keyword or identifier.
,则需要在 tsconfig.json、.eslintignore 和 .prettierignore 中将 HLS ts 文件忽略。
-
20230629
-
经验
-
Curl to grab remote filename after following location
# Specify --remote-header-name / -J curl -O -J -L $url curl --remote-name --remote-header-name --location $url # If you can use wget instead of curl: wget --content-disposition $url
-
unzstd filename.pkg.tar.zst tar -xvf filename.pkg.tar
-
How to untar an archive without the root folder, but keeping the full hierarchy inside it?: Easy. Just use
tar --strip-components=1
on the archive. -
FreeBSD Touchpad configuration:参考 libinput
$ sysctl hw.psm.elantech_support=1 $ sysctl kern.evdev.rcpt_mask=12 $ cat /usr/local/etc/X11/xorg.conf.d/30-touchpad.conf Section "InputClass" Identifier "touchpad" MatchIsTouchpad "true" MatchDriver "libinput" Option "AccelSpeed" "0.1" Option "ClickMethod" "clickfinger" # 用点击的手指代替触摸板实际的按键 Option "DisableWhileTyping" "on" Option "HorizontalScrolling" "off" Option "LeftHanded" "off" Option "NaturalScrolling" "true" Option "ScrollMethod" "twofinger" Option "Tapping" "on" # tap-to-click Option "TappingButtonMap" "lrm" # 1/2/3 指对应 left/right/middle 按键 EndSection
-
-
bspwm 没有创建 desktop,不能切换 desktop: bspwmrc 本质就是 shell 脚本,需要执行权限
chmod +x bspwmrc
20230628
- 经验
- next env
-
next.config.js Options
-
Iconfont:图标库
-
ICONFINDER:图标库
-
seeklogo:图标库
-
ShareButtons 关于图标对齐
// 如下两个不对齐,后面的比前面的矮一点,但是实际并没有 margin 或 padding 存在 <button aria-label={singleService} key={singleService} className='cursor-pointer bg-yellow-500 text-white rounded-full mx-1' > <div onClick={copyUrl} > <i className='fas fa-link w-8' /> </div> </button> <button aria-label={singleService} key={singleService} className='cursor-pointer bg-yellow-500 text-white rounded-full mx-1' > <div onClick={copyUrl} className="w-8 h-8 flex justify-center items-center" // 为了居中 icon 用 flex > <LinkIcon width={24} height={24} /> </div> </button> // 后面的用如下写法则对齐 <button aria-label={singleService} key={singleService} className="cursor-pointer bg-yellow-500 text-white rounded-full mx-1" > <div onClick={copyUrl}> <LinkIcon width={32} height={32} className="p-1" /> // 利用 padding 居中 icon </div> </button>
-
内容整体要水平居中,内容间要对齐:包一层
<div className="flex flex-col justify-start items-center"> <div> <p>a very long sentence</p> <p>a word</p> </div> </div>
- next env
20230627
- 经验
-
iphone frame:iPhone 边框
-
关于css position定位 top百分比的问题:css设置绝对定位后 top,bottom,设置百分比定位是按父元素的高度来计算的,同样left,right,设置百分比定位是按父元素的宽度度来计算的。
-
XFengCloud-小逢云:免费一天试用,可以看有哪些用户使用,感觉靠谱,openvpn 方式免流了 90%,shadowsocket 方式免流了 30%,价格10元/月,还行。
-
-
Windows OpenVPN GUI记住用户名和密码:在ovpn配置文件里增加
auth-user-pass pass.txt
,之后在ovpn配置文件所在目录建立一个pass.txt的文件,第一行为用户名,第二行为密码即可。 -
failed to negotiate cipher with server.:很多时候,把第一个错误解决了,剩下的错误都会消失(即所有剩下的错误都是由于第一个错误的产生而存在的)
cipher none # 在 data-ciphers 最后加上 cipher 指定的加密算法,即 none data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305:none
-
-
How to use curl to get public IP address
curl ifconfig.me curl icanhazip.com curl ipecho.net/plain curl ipinfo.io/ip
-
20230626
- 经验
- CFW 开启 TUN 模式后,homebrew 报错
LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443
。原因是有些地址解析到了 ipv6,但是 clash 设置中没有打开 ipv6,开启就好了。 - CFW 开启 TUN 模式后,git clone 报错
kex_exchange_identification: Connection closed by remote host
。添加规则- DST-PORT,22,DIRECT
,或改成通过443端口
- CFW 开启 TUN 模式后,homebrew 报错
20230625
20230621
- 经验
- Paste a rectangular block in Visual Studio: Click to the beginning of what you want to copy, press and hold Shift+Alt (Mac: Shift + Option) then click to the end of what you want to copy. Then release the keys and copy. When pasting, do the same for the column you want to insert.(快速翻译:首先选择并复制冒号后值为空的键放入Google进行翻译翻译,翻译后的文本做为值,之后利用块复制粘贴为值添加键,先放置值再放置键就可以保证同一个column实现块粘贴)
- Visual studio code - how to copy search results?
- CTRL + F
- Type your search string
- CTRL + SHIFT + L to select all occurrences found (max. 999)
- ESC (or close search dialog with top-right X)
- CTRL + I to select whole lines
- CTRL + C
- Open new file
- CTRL + V
- \u3000 是全角的空白符
- JS给数字加千位分隔符:
numObj.toLocaleString([locales [, options]])
20230620
- 经验
20230619
- 经验
-
“You must be an administrator to delete this job”
cancel -a -x
-
整合 Google 登录:其他的 OAuth2 认证基本类似。具体流程是,访问 api/google controller 执行 google.strategy 进行 Google 登录;获取信息后 validate 成功后 redirect 到 api/google/redirect controller,首先先通过 upsert 将用户信息保存到数据库,然后根据信息生成 token 放入 cookie 中,最后 redirect web 页面,web 页面使用 axios request interceptor,读取 cookie 中的token。
-
How to Implement Login with Google in Nest JS:
done
callback should not be used invalidate
method, because it is invoked internally by nestjs/passport. It is better to just return user object from validate. -
Error: redirect_uri_mismatch: The redirect URI (where the response is returned to) has to be registered in the APIs console, and the error is indicating that you haven’t done that, or haven’t done it correctly.
-
Access to fetch at https://accounts.google.com/o/oauth2/v2/auth has been blocked by CORS: The authentication flow must happen in a visible browsing context, not with a fetch request. In other words: You must navigate the current tab to (or open a new tab at) http://localhost:8000/api/mail/login.
-
InternalOAuthError: Failed to obtain access token 0:原因是在
google/redirect
controller 中执行没有正确返回,用的return { url: 'https://testweb.chathome.ai'}
,之后参考 Send a set-cookie header to a redirect url in node.js,就成功了res.cookie('access_token', token, { maxAge: 24 * 60 * 60, sameSite: true, secure: true, }) res.redirect(302, 'https://testweb.chathome.ai');
-
Attach Authorization header for all axios requests
// Add a request interceptor axios.interceptors.request.use(function (config) { const token = store.getState().session.token; config.headers.Authorization = token; return config; });
-
-
20230617
-
经验
-
ssh connection speed
-
pv: test transfer speed
yes | pv | ssh remote_host "cat >/dev/null"
- 如何使用 pv 命令监控 linux 命令的执行进度:数据量,花费的时间,传输速率,进度条,进度的百分比,以及剩余的时间。
- Linux命令之yes:重复输出字符串
-
sshping: MacOS - linking help with libssh?
+CFLAGS=-I /opt/homebrew/include -I ext -L /opt/homebrew/lib -lssh -bin/sshping: src/sshping.cxx /usr/include/libssh/libssh.h - g++ -Wall -I ext/ -o bin/sshping src/sshping.cxx -lssh +bin/sshping: src/sshping.cxx + g++ -Wall -I ext/ -o bin/sshping $(CFLAGS) src/sshping.cxx -lssh
-
Test ssh connection speed: scp transfer speed
-
-
-
How can I set my default shell to start up tmux
if command -v tmux &> /dev/null && [ -n "$PS1" ] && [[ ! "$TERM" =~ screen ]] && [[ ! "$TERM" =~ tmux ]] && [ -z "$TMUX" ]; then if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then exec tmux new-session -A -s "${USER}0" fi fi
-
command命令 – 调用并执行指定的命令: -v 搜索命令信息但是不执行
-
How to start tmux with attach if a session exists: The -A flag makes new-session behave like attach-session if session-name already exists; in this case, -D behaves like -d to attach-session.
tmux new-session -A -s main
-
How to determine if I’m logged in via SSH?
- If one of the variables
SSH_CLIENT
orSSH_TTY
is defined, it’s an ssh session. - The login shell’s parent process can be checked with
ps -o comm= -p $PPID
. If it issshd
, it’s an ssh session.
if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then SESSION_TYPE=remote/ssh else case $(ps -o comm= -p $PPID) in sshd|*/sshd) SESSION_TYPE=remote/ssh;; esac fi
- If one of the variables
-
-
-
How to append multiple lines to a file
# possibility 2: echo "line 1 line 2" >> greetings.txt # possibility 3: cat <<EOT >> greetings.txt line 1 line 2 EOT ``
-
-
ssh-keygen -p -f ~/.ssh/id_rsa echo ' AddKeysToAgent yes UseKeychain yes' >> ~/.ssh/config
-
重新生成公钥:Create a public SSH key from the private key?
ssh-keygen -f ~/.ssh/id_rsa -y > ~/.ssh/id_rsa.pub
-
从流量控制算法谈网络优化 – 从 CUBIC 到 BBRv2 算法:是拥塞控制算法。作用是决定发送方应该以多快的速度发送数据,并同时适应网络的变化。BBRv1 对带宽延迟积大、丢包率高的网络非常有效,能保持一个不错的吞吐量数字。
-
How to enable BBR on Ubuntu 20.04
echo ' net.core.default_qdisc=fq net.ipv4.tcp_congestion_control=bbr' >> /etc/sysctl.conf sysctl -p sysctl net.ipv4.tcp_congestion_control
-
给VPS上的FreeBSD开启BBR:要编译内核
-
-
KCP协议:从TCP到UDP家族QUIC/KCP/ENET:KCP是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。
-
Problem With Transmission Receive Buffer on FreeBSD
-
临时
sysctl kern.ipc.maxsockbuf=5242880 sysctl net.inet.udp.recvspace=4194304
-
永久:添加到 /etc/sysctl.conf
-
-
- virt-what:检测VPS是Openvz还是KVM还是Xen,
apt install -y virt-what; virt-what
- virt-what:检测VPS是Openvz还是KVM还是Xen,
-
- bench.sh:测试传输速度
wget -qO- bench.sh | bash
- bench.sh:测试传输速度
-
教程:记录 Linux 的点滴
-
Bhyve started from tmux:Start a virtual machine in background,在后台运行 bhyve 虚拟机,如下部分脚本只适用于 freebsd
# start bhyveload -m 8G -S -d /vm/freebsd/freebsd1.img freebsd1 sleep 8 /usr/local/bin/tmux new-session -d -s freebsd1 'bhyve -S -m 8G -c 8 -AHP -s 0,hostbridge -s 1,lpc -s 2:0,ahci-hd,/vm/freebsd/freebsd1.img -s 5:0,passthru,132/0/0 -s30,xhci,tablet -l com1,stdio freebsd1' # stop pkill bhyve sleep 10 bhyvectl --destroy --vm=freebsd1 tmux kill-server
-
KVM总结-KVM性能优化之CPU优化:绑定物理 CPU 到虚拟 CPU。
20230616
- 经验
- ForbiddenException: Forbidden resource 产生的原因来自于 guard。
- Oh-My-Zsh Git: Git Aliases
- Build a real-time chat application with Nestjs and PostgreSQL
20230615
20230614
- 经验
-
.deal::-webkit-textfield-decoration-container { background-color: #f0f3f9; } .deal::-webkit-inner-spin-button { -webkit-appearance: none; } .deal::-webkit-outer-spin-button { -webkit-appearance: none; /*有无看不出差别*/ }
-
How can I do Base64 encoding in Node.js?
Buffer.from("Hello World").toString('base64') // encode Buffer.from("SGVsbG8gV29ybGQ=", 'base64').toString('ascii') // decode
-
原来浏览器原生支持JS Base64编码解码:就是 window 的方法 atob 和 btoa
-
踩坑日记:如何修复“System limit for number of file watchers reached”错误
-
执行如下命令
sudo sysctl fs.inotify.max_user_watches=524288 echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf sudo sysctl -p
-
Increase fs.inotify.max_user_watches in docker container: Docker mounts /proc as read-only since many of its knobs are global. If you run that same command on the host, the container will transparently inherit the new setting.
-
-
how to make non root user as sudo user in docker alpine image?
-
command:
docker exec -it --user root mycontainer sh
-
dockerfile:
USER root # Run root operation here # Change user back to cassandra USER cassandra RUN whoami
-
-
node中__dirname、__filename、process.cwd()、process.chdir()表示的路径
- __dirname 表示__dirname所在文件所在的目录的绝对路径
- __filename 表示__filename所在文件的绝对路径
- module.filename ==== __filename 等价
- process.cwd() 返回Node.js 进程执行时的工作目录的路径
- process.chdir() 改变工作目录。
-
frp 将内网服务穿透到公网,可以在公网访问内网服务;tailscale 是 VPN,组件虚拟局域网,局域网内的设备可以相互访问。两者都通过公网路线访问,区别在于 frp 是暴露在公网,任何人都可以访问服务,tailscale是成员可以访问服务。就个人需求来说,当然是两者都用,一些服务能暴露到公网,一些服务只能成员访问。
- Configuring IPv6:FreeBSD 自己添加的 wlan0 并没有自动启用 ipv6
- Pv4 Gateway to access IPv6:有的路由器并没有支持或开启 ipv6,frp 报错 no route to host,可以利用 hax 的 share ipv4 端口来连接 frps 服务
- woiden.id 变为 non-renewable 的了,总比永远抢不到服务的好,现在至少能用3天,用来测试也够了。
- 支持 KCP 协议:降低延迟。报错 i/o deadline reached,用不了啊,quic 也一样。
-
20230613
- 经验
- Node+Puppeteer生成海报:其实就是利用 chrome 的 Capture node screenshot 将 node 节点内容转为图片
- 自定义二维码:了解QrCode的结构原理与实战
- 添加 Logo
- 二维码挡住哪些部分,不会影响扫描识别?:只要四角的定位符(就是那个方形的黑色粗线框)没有被挡住就行,剩下的其他地方与纠错级别相关,纠错级别越高,可被覆盖的地方越多。
- 前端如何优雅的制作带LOGO的二维码:用 canvas 将 logo 绘制到二维码上。
- 添加背景图:纯前端实现自定义二维码背景图,方法是把二维码黑色的部分数据拿到,然后将黑色的部分按照对应的背景图的颜色进行填充。
- qrcode.react
- 添加 Logo
20230612
- 经验
- Prisma 给数据库填充初始数据: Seeding your database
- upsert是一种数据库操作,如果表中已存在指定值,则更新现有行,如果指定值不存在,则插入新行。
- Prisma Models: autoincrement() optionnally starting at 0 ?: It’s not possible from the schema directly but you can modify the migration file to achieve this.
- 我有一台服务器能做什么:自架的服务整理 / Awesome-Selfhosted:免费或便宜的小鸡做打洞,实际服务在家里电脑中。
- Prisma 给数据库填充初始数据: Seeding your database
20230610
-
FreeBSD 最重要的信息还是安装软件后的 pkg message,这个是最适用的:
pkg info -D pkgname
-
wpa_supplicant/wpa_cli
-
wpa_cli error “Could not connect to wpa_supplicant: wlan0 - re-trying”?
-
在 MacOS 上查看 BSSID:如果多个 Wi-Fi 具有相同的 SSID,或者连接隐藏 SSID 的 Wi-Fi,则 FreeBSD 需要指定具体的 BSSID,在 FreeBSD 上可直接通过
ifconfig wlan0 scan
查看,在 Mac 上通过如下命令查看sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | grep BSSID
-
注意:用 wpa_passphrase 生成的 psk 可能导致 FreeBSD 无法连接 wifi,可尝试使用原本的 psk
-
How to mount exFAT formatted SD memory card on FreeBSD.
pkg install fusefs-exfat sysrc kld_list+=fusefs reboot mount.exfat /dev/da0s1 /mnt umount /mnt
-
How to check if a string contains a substring in Bash
# 1 [[ $string == *"My long"* ]] # 2 [ -z "${string##*$reqsubstr*}" ]
-
-
How to install Linux VM on FreeBSD using bhyve and ZFS:wlan0 与 tap0 组成 bridge0 后,vm 无法访问网络,因为只能用 wlan0,因此考虑 nat 模式;一般认同使用 zfs 比 truncate 可以获取更高的磁盘性能。另一篇文章RUNNING CENTOS WITH BHYVE
-
bhyve wireless NAT vm setup:nat 依托于防火墙,即 PF
- PF:
- 以 PF 架設 NAT 路由器及防火牆
- em1:network 相当于 em1 的局域网,但是不支持变量
- 以 PF 架設 NAT 路由器及防火牆
- 需要为 VM 设置 static ip 和 gateway
-
编辑
/etc/netplan/00-installer-config.yaml
,然后运行netplan try
以应用配置# # This is the network config written by 'subiquity' network: ethernets: enp0s2: dhcp4: no addresses: [10.0.0.2/24] nameservers: addresses: [114.114.114.114] routes: - to: default via: 10.0.0.1 version: 2
- PF:
-
resize truncated bhyve .img file
sudo pkg install e2fsprogs truncate -s<newsize> ubuntu.img mdconfig ubuntu.img gpart show md0 gpart recover md0 # in case of GPT you should run this before resizing gpart resize -iN md0 # N - the partition index resize2fs /dev/md0sN # could be md0pN in case of GPT scheme mdconfig -d -u0
-
sudo: ‘‘who where = (as_whom) what’’
-
20230609
- 经验
- 在部署的时候,GRPC 服务的 GRPC_CHATBOT=host:port 不能写在 .env 之中,否则报错 No connection established,写在 docker-compose.yaml 的 environment 中则可以正常连接。查看 Dockerfile 得知,
COPY .env ./
在RUN yarn build
之后,这是报错原因。 - Tools for managing and deploying Redis:AnotherRedisDesktopManager 替代收费的 RedisDesktopManager
- RabbitMQ CLI 管理工具 rabbitmqadmin(管理和监控)
- 在部署的时候,GRPC 服务的 GRPC_CHATBOT=host:port 不能写在 .env 之中,否则报错 No connection established,写在 docker-compose.yaml 的 environment 中则可以正常连接。查看 Dockerfile 得知,
20230608
-
IPFS
- 站在Web3.0 理解IPFS是什么
- IPFS 使用入门
- IPFS 新手指北
- IPFS 日用优化指南:在发布内容后,马上通过公开的 IPFS 网关访问,通常会很慢很慢,甚至到超时都无法访问,这是由 IPFS 的寻址过程导致的。随着访问内容的用户越来越多,他们的 IPFS 节点上会缓存你内容的数据,这个时候新节点再访问同一份内容,通常就会很快。这就是 IPFS 的特性,就跟 BT 下载的原理类似,数据在网络中存在的副本越多,就越能利用 P2P 网络的性能。
-
Zeal/Dash: offline documentation browser for software developers.
20230607
- 经验
- RESTful API 设计指南
- Docker ENTRYPOINT 入口点:实际执行时,将变为
<ENTRYPOINT> "<CMD>"
。 - 搞懂异地多活,看这篇就够了
20230606
- 经验
-
MailGun 同一个账号的 APIKEY 是一样的,但是 DOMAIN(ses.chatfo.ai) 可以不一样。
-
Easiest way to copy a table from one database to another?:跨 mysql server 复制数据表
mysqldump --user=user1 --password=password1 database1 table1 \ | mysql --user=user2 --password=password2 database2
-
腾讯工程师带你深入解析 MySQL binlog:二进制日志,主要用来达到 master-slave 数据一致的目的。
-
20230605
- 经验
-
DBeaver:干掉付费的 Navicat,操作所有数据库就靠它了!:DBeaver 好用!可以格式化查看数据内容。
-
sed changing all occurrences in a folder/How to limit directory depth with find command
find . -maxdepth 2 -type f -exec sed -i.bak "s/foo/bar/g" {} \;
-
sed fails with “unknown option to `s'” error: The problem is with slashes: your variable contains them and the final command will be something like sed “s/string/path/to/something/g”, containing way too many slashes.
replacement="/my/path" sed --expression "s@pattern@$replacement@"
-
Quick Reference: 英文版 Reference 的中文版本
-
20230602
- 经验
- Jenkins 有个 View,用于对 Jobs 分组。
- Linux终端下生成随机复杂密码的五种姿势:最通用的,能在 ubuntu & macOS 都可使用的,且不需要安装软件的是
openssl rand -base64 14
- Safari 阅读模式可以替代 Chrome 的 Reader View:Command + Shift + R
- ChatGPT: AiMapPro.com - 轻松探索 AI 世界
- 我的职业是前端工程师
- MySQL Workbench使用教程:MacOS Monterney M1 上使用 Select Rows–Limit 1000 来编辑表中的数据就会闪退。
20230601
- 经验
-
Replace all whitespace characters: You want \s
-
How do I replace all occurrences of a string in JavaScript?:
str.replace(/abc/g, '')
orstr.replaceAll('abc', '')
-
how do I check whether its a jpg/png/gif?: There is a comprehensive table of magic numbers here
var magic = { jpg: 'ffd8ffe0', png: '89504e47', gif: '47494638' }; const buffer: Buffer = (file as Express.Multer.File).buffer buffer.toString('hex',0,4) === magic.jpg && doSomeThing()
-
Using the Buffer
toString()
Function in Node.js:buf.toString([encoding[, start[, end]]])
是 node 的 api,非 js 原生的 toString(radix) -
如何在 Node.js 中判断一个文件/文件夹是否存在?:不用fs.exists,因为不是错误优先的回调函数,以及会产生竞态条件
private async makeDirExist(dir: string) { const accessAsync = promisify(fs.access) try { await accessAsync(dir, fs.constants.W_OK) } catch (e) { fs.mkdirSync(dir, { recursive: true }) } }
-
20230531
- 经验
-
问题:正式版,PDF Steam web 端无法显示。原因:通过 devtool 查看,发现数据正确返回了,对比
www.chathome.jp
与chathome.jp
,发现www.chathome.jp
api 调用都多了一个 preflight请求。解决:在部署环境中注释掉 env 中的NEXT_PUBLIC_WEB_API_DOMAIN=https://chathome.jp
环境变量,让 api 调用自动使用相应的域名,从而不产生 preflight请求。经过排查,发现是response.headers['content-disposition'].split['='](1)
报错error TypeError: Cannot read properties of undefined (reading 'split')
,因为www.chathome.jp
的 response header 只有content-type: "application/force-download"
,这里可以将 split 放在 try…catch 块中。为什么只返回改 header 字段呢?因为后台在跨域下只允许了特定的 header 可以被访问:allowedHeaders: [...allowedHeaders, 'content-type', 'Authorization'],
。 -
为啥JavaScript里,数组正常的索引不能用负数呢?:因为JS的Array实际是个Object,并不是真的array,
arr[-1] = 'a'
,但可以反向索引arr.reverse()[1]
或 使用arr.at(-1)
-
20230530
- 经验
-
vConsole:针对手机网页的前端开发者调试面板。
-
User-Agent
- HTTP请求头之User-Agent
- UAParser.js
- app内置浏览器是什么:App内置浏览器指的是一个手机应用程序内部包含的浏览器功能,可以让用户在应用程序内部直接浏览网页,而不需要跳转到手机自带的浏览器应用程序中。在技术上,应用程序内置浏览器通常是基于WebView技术实现的。
- 解决微信内置浏览器不能下载文件:判断用户的浏览器是否为微信内置浏览器,如果是弹出一个图层,提示用户点击在默认浏览器中打开。判断主流内嵌浏览器userAgent:
export const webView = () => { return /Feishu|DingTalk|MicroMessenger|Bytedance|NewsArticle|Zhihu|Weibo|AlipayClient|MQQBrowser/gi.test(window.navigator.userAgent); };
20230529
- 经验
-
生产环境的配置里面都不要用 10 开头的 ip 地址,10 开头的是虚拟lan 地址,依赖于 tailscale 服务器,万一这个服务器出问题了,会有影响;但是在本地运行 api 项目的时候,需要使用 10 开头的 ip 地址,例如
ClusterAllFailedError: Failed to refresh slots cache.
问题就是用 192 开头 ip 没有连接上 redis。 -
PDF stream:
- 后台:Streaming files:用 file stream 替代之前的 pdf url,解决安全隐患,防盗链,防爬虫遍历 static pdf 文件。
- 前台:
- 前端如何下载文件流:注意 a 标签的
download="filename.pdf"
,Safari 没这个下载为 Unknow.pdf。结果是 IOS QQ浏览器无法显示无法下载;IOS Chrome 可以显示,可以下载到本地 Chrome 目录;Safari 可以显示,点击下载后打开新页面,新页面可以选择 save to files ;IOS Firefox 可以显示,点击下载后打开新页面,无法下载;IOS Lark 打开的内嵌网页可以显示,点击下载无反应。 - 这将是你看到过最全的pdf预览解决方案:使用的是 iframe 来预览,在 chrome 浏览器开发者工具中选择手机端 device 后无法预览 pdf,但在 IOS 的 Safari 可以直接预览。
- file-saver: Due to restrictions in iOS saveAs opens in a new window instead of downloading。IOS 下无法实现点击直接下载文件,除了 Safari 开发者没有解决办法。
- 前端如何下载文件流:注意 a 标签的
-
20230526
- 经验
- 5 款 iOS Safari 广告拦截插件横评——看完你就知道用哪个了: Adblock 最有用,但还需要设定语言,才会下载对应语言的规则。
20230525
- 经验
- useSWR 如果验证没变,那么返回的应该是 304(作用于 GET,用的 etag 字段),如果是重新请求成功,POST 是 201,GET 是 200.
- Jackson Wu:研究某个复杂软件的源代码是一件很难的事情,推荐的做法是看它最早期版本,比如说 Linux Kernel,别看它现在有千万行代码,但其实它的核心设计在它只有几万行的时候就确定了。另一个推荐的做法是卡马克说的,自己尝试着去克隆某个项目,做一个玩具版的 xx,这样就能深刻理解它的运行原理。(500 Lines or Less)
20230524
- 经验
- 1-1评审了20份前端简历,其实每个人都有亮点:简历美化
- 伟大的公司需要多少人:不融资,不追求团队规模,更关注公司盈利能力
- ip 地址怎么到 kong 服务?:在域名解析只能解析到服务器的ip地址,不能具体指定到某一个端口,只有域名默认解析到 80 端口。要使用 kong 网关,需要将 80 端口转发到 kong 服务的 8000 端口,如果 kong 是通过 docker 运行,则有端口映射
0.0.0.0:80->8000/tcp, :::80->8000/tcp, 0.0.0.0:443->8443/tcp, :::443->8443/tcp
。 - Next Image 以 width 为主,height 是等比例缩放的,高度值其实可以是任意值的,完全不会影响 width。
20230523
- 经验
-
扇形进度条:Filling circle sector in CSS
-
原理是,渐变函数相当于画一个圆,这个圆一半为红色,一半为透明色;两个渐变函数就是画两个这样的圆叠起来,透明重叠的部分即为小扇形,红色重叠部分即为大扇形。面积大的扇形用渐变函数涂,面积小的扇形用背景色。
-
代码如下
if (radius <= 180) { return ( <div className="h-5 w-5 rounded-full border-2 border-solid border-[#6fba2c] bg-[#6fba2c]" style={{ backgroundImage: `linear-gradient(${90}deg, #fff 50%, transparent 50%), linear-gradient(${ radius - 90 }deg, #fff 50%, transparent 50%)`, }} ></div> ) } else { return ( <div className="h-5 w-5 rounded-full border-2 border-solid border-[#6fba2c] bg-white" style={{ backgroundImage: `linear-gradient(${-90}deg, #6fba2c 50%, transparent 50%), linear-gradient(${ (radius + 90) % 360 }deg, #6fba2c 50%, transparent 50%)`, }} ></div> ) }
-
-
20230522
- 经验
- How to Use TeamViewer Remote
- 小课堂:
- 举个例子,给你 1000块钱,100一张 ,10张,这10张100的,有没区别?从价值角度来说,没区别,因为都是100的,这个就是同质化的;从防伪角度来说,是不是一样的,不是,每个100的纸币,都有防伪码,唯一不可篡改的编码,这个就是非同质化。明白了吗?非同质化代币,对于区块链网络来说,就是在区块链上,不同编号的币,你先这么理解。
- RAW,real assets wrod ,他的目的是引入真实世界的资产到虚拟世界。在股票市有一个名词:资产证券化,和这个比较接近。例如你有一个价值100w的房子,你抵押给银行,银行给你 80万人民币。这个就可以理解为你把真的房子的资产映射到了金融世界。因为从物理角度来说,房子和钱币来说属于两个世界,raw 在区块链世界,就是你抵押你的房子,给你虚拟世界的资产,例如比特币。抵押给银行了,这个动作发生在真实世界,在虚拟世界就不能抵押,虚拟世界也没有真实世界的房子。但是你抵押给银行了,可以在虚拟世界,给你虚拟世界的账户,打一笔钱,这样你房子的价值,是不是映射到虚拟世界了。明白了吗?记住是价值映射,raw 本质就是价值传导
20230521
- 经验
- 负责淘宝业务前端开发9年,聊聊我的心得:第一步做好本职工作——既快又好(保质保量)的完成业务需求,并尝试做些改变(纯粹造个轮子、换个理念重新实现轮子、尝试前端领域一些新特性或者新框架)。
- 软件开发团队如何高质量、高效率?:软件开发要达到高质量、高效率,就需要在代码可读性、可维护性和可扩展性等多方面都达到较好的水平才可以。“代码编程”是软件开发中最关键的环节。首先要保证质量,才能提升进度。遵照“权限编程”的实践思路来进行培养高水平的开发人员(其实就是大佬轮流带队,向大佬学习)
- 技术的广度与深度:我提这个问题,目标是提升自己在就业大军中的竞争优势
- 全能程序员 vs 特长程序员:“绝大多数成熟的程序员都专攻某一个技术栈,因为这样更容易找到工作。 一些专家甚至认为,在不同的技术栈中工作是简历的污点。"(以公司角度)
- 知识广度 vs 知识深度:知识的广度能告诉你什么是正确的方向,知识的深度则可以让你在该方向上快速前进。雇主愿意为知识深度买单。因为你克服了技术难题,才有机会来领导团队。(以各自优势为角度)
- 技术的深度与广度,该如何取舍?:取决于你的屁股坐在哪一边。如果你的职业规划是在企业里步步高升,那么专注某个领域,并且努力成为那个领域的专家,会更符合企业对人才的要求。而如果你的志向在于体制之外,则各方面都懂一点,眼观六路耳听八方,时刻保持警惕,才是在残酷的大自然中繁衍生息的不二法则。(以人的不同位置为角度)
- 对于一个领域,深度重要还是广度重要?(可以拿自己所在领域举例,为后来人提供一些经验)?:初期的广度重要,“选择大于努力”;中期的深度重要,“高端人才永远短缺,初级人才永远内卷”;成熟期又变成广度重要。(以人发展的不同时期为角度)
- 如何平衡知识结构广度与深度?:知识的广度往往并不会产生直接的自我增值,知识广度本身是附着在某一个专业深度上的。(以学习的先后顺序为角度,先深后广)
20230520
- 经验
-
对于服务端来说,params 是动态路由,定义如
/test/:key
,如果实际 url 为/test/value
,则 params 对象为{ key: value }
,query 是查询参数,url 为/test?key1=value1&test2=value2
,则 query 对象为{ key1: value1, key2: value2 }
;对于客户端来说,查询参数就是 params,即 url ? 后面的部分。 -
next.js 下 css modules 选择器
.privacypolicy > p:first-child
不起作用,经过测试,我的写法是有效的,最后解决办法是不使用伪类,用.privacypolicy > nav
。 -
How can I get (query string) parameters from the URL in Next.js?
const router = useRouter() console.log(router.query);
-
20230519
- 经验
-
Property ‘scrollTop’ does not exist on type ‘EventTarget’
const st = (e.target as HTMLElement).scrollTop;
-
JavaScript 中那些不会冒泡的事件: 滚动事件不会冒泡,需要在捕获阶段或者直接在该滚动元素上完成委托。
-
vscode在自动填充后失去常规代码提示的问题(连续自动补充失效):
"editor.suggest.snippetsPreventQuickSuggestions": false,
-
20230518
- 任务
- 经验
- vue中使用setInterval()循环定时器的注意事项
- 问题:pinia 没有在多页面共享状态
- 解决方案:使用 vue router 的
<router-link>
组件 - 问题分析:vue 或 react 的 store 作用是在多页面共享状态,都是在页面不 reload 下生效的,而 a 标签会 reload 页面,因此需要第三方 router 库的路由组件来路由,防止页面 reload。
- 解决方案:使用 vue router 的
- Vue关于data为什么是函数这件事
- 轻松理解JS 原型原型链:JS 只有对象,关键就在于清楚
.__proto__
、.prototype
和.constructor
变量的指向。 - 前端们,贺老 Live 面试你了!:会一个知识点不能代表你牛逼,只能代表你知道,所以还需要继续考察,但要是你不会,三言两语就学会了,那你肯定牛逼了。
- rar/unrar for macOS:
brew install rar; unrar x filename
20230517
- 任务
- 经验
-
overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
-
How to listen for specific property changes in Redux store after an action is dispatched
const unsubscribe = store.subscribe(() => console.log('State after dispatch: ', store.getState().additon))
-
How can you replace entire state in Redux Toolkit reducer?:
return action.payload
-
vue3.0+vite (二) vite.config.js基本配置:主要是 Vue Vite 解决 CORS 部分,官方文档 server.proxy
server: { cors: true, // 默认启用并允许任何源 open: true, // 在服务器启动时自动在浏览器中打开应用程序 //反向代理配置,注意rewrite写法,开始没看文档在这里踩了坑 proxy: { '/api': { target: 'http://192.168.99.223:3000', //代理接口 changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } }
-
20230516
- 经验
- form 的 action 属性,就是 api 的路径,比如
action='/api/v1/i'
- 电信光猫F450——破解超级密码并配置无线IPTV
- How to Filter an Object by Key in JavaScript
- form 的 action 属性,就是 api 的路径,比如
20230515
20230512
- 经验
-
问题:受控的 input checkbox 选中后,依次点击浏览器后退、前进,会发现该 checkbox 值是 false,但是 ui 还是选中状态,点击两次该 checkbox ui 会变为非选中状态。原因:如果该页面是通过正常的路由进行访问的,而不是直接输入地址访问,则会正确的卸载与重建。
-
function getData(form) { var formData = new FormData(form); // iterate through entries... for (var pair of formData.entries()) { console.log(pair[0] + ": " + pair[1]); } // ...or output as an object console.log(Object.fromEntries(formData)); } document.getElementById("myForm").addEventListener("submit", function (e) { e.preventDefault(); getData(e.target); });
-
使用
for ... of
报错:Type 'IterableIterator<number>' can only be iterated through when using the '--downlevelIteration' flag or with a '--target' of 'es2015' or higher
,解决。 -
Redux 变化很大。
-
Array() vs new Array(): The spec says: When Array is called as a function rather than as a constructor, it creates and initialises a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.
-
How to access all the direct children of a div in tailwindcss?:
[&>*]:text-gray-200
or[&>*:hover]:text-blue-500
-
乌苏啤酒为什么被称为夺命大乌苏?:归根结底就是酿酒工艺差,杂醇多,导致上头感强,后劲极大,第二天醒来生不如死。
-
- 私活:国内的程序员客栈/飞援,国外的电鸭/upwork(更好)。(接私活不仅是赚钱,也能将学习的知识用于实际、增长经验)
- 经验:封装api/封装store/封装路由/封装公共方法,这四个大块做好了,其他的就是基本的页面逻辑,根据设计图填充就行了。
- 产品:原型——设计——开发,三个环节缺一不可。
-
问题:整个页面都是表单,数量非常多,考虑要在前进、后退中保存表单状态,使用了redux,但是非常繁琐。解决方案:考虑使用 keep alive 保存整个页面的状态,使用 form 的 onSubmit 自动获取表单数据。
-
20230511
- 经验
margin: 0 auto;
水平居中条件- 父元素有剩余空间
- 目标子元素为块级元素
20230510
- 经验
-
职场上好的沟通是生存优势。
-
代码不是先想好了再写,而是一边写一边想好。一个组件不知道怎么写,哪怕是看了文章后,虽然有思路,但是还是不知道具体怎么写,这是因为没有动手写,而不是你不会写。
-
double range slider input
-
看js使用input实现双向slider的实际代码
-
通过Creating A Custom Range Input That Looks Consistent Across All Browsers了解 range input 自定义样式相关选择器
-
React’s mouseEvent doesn’t have offsetX/offsetY: Get it from
e.nativeEvent.offsetX
. -
How to round to at most 2 decimal places, if necessary
Math.round(num * 100) / 100 Math.round((num + Number.EPSILON) * 100) / 100
-
Vant:轻量、可定制的移动端 Vue 组件库
-
20230509
- 经验
- 文章:图解 QUIC 连接
- 文章:Next.js小记
20230508
- 经验
- Chatfo 分享到微信:在桌面浏览器与不支持的手机浏览器中将展示二维码;在支持的手机浏览器上利用原生分享组件直接跳转:
-
为博客添加分享到微信功能:使用qrcode展示二维码
-
- Reference Error:Navigator not defined with nextjs: Browser objects like window , navigator etc should be define in useEffect first before use. Window it’s browser object, and the hook will run after it’s loaded, that’s why it will work.
useEffect(() => { // @ts-ignore TYPE NEEDS FIXING import('nativeshare').then((res) => { const nativeShare = new res.default() nativeShare.setShareData({ icon: `${window.location.origin}/icons/icon-192x192.png`, link: window.location.href, title: `问题 ${qid} | 佛说 AI`, desc: '佛说,AI智能平台。', }) setNativeShare(nativeShare) }) }, [qid])
-
react-share:社交媒体分享组件,同 vue-social-sharing
-
- Chatfo 分享到微信:在桌面浏览器与不支持的手机浏览器中将展示二维码;在支持的手机浏览器上利用原生分享组件直接跳转:
20230506
20230505
- 任务
- 群发邮件的api + UI接口,做到管理后台(要一个邮件模版)
- Mailgun
- 中后台前端
- Ant Design Pro
- ProComponents:ProComponents 是 antd 的超集,但文档没有 antd 细。
- Ant Design
- 社区精选组件:富文本编辑器 react-quill,修改样式参考 codepen 中的例子,基本上是通过类选择器来调整样式的。
- Pagination分页:ProTable 的分页设置
- 国际化:首先,需要写对 language code,这样才能自动为支持的语言添加图标;其次就是修改一下locales根目录的ts文件的导入
- HTML Email Template
- 群发邮件的api + UI接口,做到管理后台(要一个邮件模版)
20230428
- 经验
-
ubuntu 自动更新导致 docker 服务全宕机:How to Disable Automatic Updates in Ubuntu
$ sudo nano /etc/apt/apt.conf.d/20auto-upgrades APT::Periodic::Update-Package-Lists "0"; APT::Periodic::Download-Upgradeable-Packages "0"; APT::Periodic::AutocleanInterval "0"; APT::Periodic::Unattended-Upgrade "0";
-
「入坑指南」老司机带你玩转PSN账号:国服机器,外服需要备份还原大法,国服直接登录就行。
-
20230427
- 经验
- Vue深层级过渡与显式过渡时长:要在在深层级的元素上触发过渡效果,关键在于传入 duration prop 来显式指定过渡。
- 通过项目驱动来学习技术,这里的项目不是指学习者从零开始自己写一个项目,对于新人来说,这太难了,而且很容易走错方向,这个项目指的是现有的需求类似的项目,学习者这参照这个项目从头来实现,在实现的过程中,学习其写法、添加自己的想法等,最终实现自己的需求、学会这套技术栈。
- PlayStation®4用户指南
20230426
- 经验
- How can I accept all current changes in VSCode at once?: Its very easy just go to vs code and press
Ctrl
+shift
+p
(command palette) or go to view and open command palette manually and type “merge” in your command palette, now you can see the Accept all current changes.
- How can I accept all current changes in VSCode at once?: Its very easy just go to vs code and press
20230425
- 经验
-
[module not defined in Vue Project](https://stackoverflow.com/a/73353382: Add this to
.eslintrc.cjs
env: { node: true, },
-
How can I import a svg file to a Vue component?
-
一种安装包 vue-svg-loader,把 svg 处理为组件
import SomeIcon from './assets/some-icon.svg'; <SomeIcon class="icon" />
-
一种是直接导入,不需要安装任何包
<template> <img src="@/assets/my-svg-file.svg" /> </template>
-
-
20230424
- 经验
-
NextJS Image component with fixed witdth and auto height
<Image src={img1} width="0" height="0" sizes="100vw" className="w-full h-auto" />
-
Vue 报错
Virtual script not found, may missing <script lang="ts"> / "allowJs": true / jsconfig.json
,在 tsconfig.json 或 jsconfig.json 中加入如下内容{ "compilerOptions": { "allowJs": true } }
作用是在 ts 中导入 js 模块:Allow JS
-
Vue: How do I call multiple functions with @click?
<div v-on:click="firstFunction(); secondFunction();"></div> // or <div @click="firstFunction(); secondFunction();"></div>
-
20230423
- 经验
- 写后端 api 不仅是后端的事情,前端也需要根据自己的需要来向后端提供需求,帮助其完善 api。前端最好再自己画 UI 之前,把需要的 api 列表交给后端,这样前端 UI 与后端 api 可以同步进行。
20230421
- 经验
- 公司自动化流程是:GitHub =webhook=> Jenkins =ssh=> Shell 脚本 => Kong 服务。一般先写脚本,脚本是核心,当脚本能够正确运行了,再添加到 Jenkins,配置 kong 服务的等。
20230420
- 经验
-
Lingui 删除多余 message:
lingui extract --clean --overwrite
-
Prisma 存储中文字符串到 Mysql 后,通过命令行在 Mysql 查看,会发现中文显示为
?????????????
,这是因为默认用的 latin1 显示,参考两步解决MySQL无法显示中文即可解决show variables like '%character%'; set character_set_client=utf8mb3; set character_set_results=utf8mb3;
-
TypeError: (intermediate value)(intermediate value)(intermediate value) is not iterable
// 错误原因 You cannot destruct array value from undefined const filterValues = undefined const [startDate, endDate] = filterValues?.dateRange // 解决方案一 const [startDate, endDate] = filterValues?.dateRange ?? [] // 解决方案二 const dateRange = filterValues?.dateRange const startDate = dateRange?.[0] const endDate = dateRange?.[1]
-
TypeScript里的空值合并运算符(双问号)用法:当左侧操作数为 null 或 undefined 时,其返回右侧的操作数,否则返回左侧的操作数。
-
Bearer token in postman: You can just manually add an Authorization Request Header with a
Bearer <my_token>
value. -
MySQL高级 —— 查询性能优化:查询性能低下最根本的原因是访问的数据太多。
-
get full type on prisma client
import { Prisma, PrismaClient } from "@prisma/client"; const prisma = new PrismaClient(); const userInclude = Prisma.validator<Prisma.UserInclude>()({ cars: true, }); type UserWithCars = Prisma.UserGetPayload<{ include: typeof userInclude; }>; const usersWithCars = await prisma.user.findMany({ include: userInclude, });
-
20230419
-
经验
-
部署:正向合并 main => test => dev,反向合并 dev => test => main。
-
Github PAT
-
可以通过爱思助手将音乐导入 iphone apple music 中,如果提示有重复文件,就选择覆盖,否则可能出现音乐图片与音乐不匹配的情况,虽然我确实是删除了的。
-
待定的地方用
###
填位置,也方便搜索。 -
如果页面分别写了手机端与电脑端的页面,且页面差异较大,在客户端用媒体查询切换非常不自然,那么可以通过 Next Middleware 实现在服务端切换 UI,如:
// middleware.ts import type { NextRequest } from 'next/server' import { NextResponse } from 'next/server' import { UAParser } from 'ua-parser-js' // This function can be marked `async` if using `await` inside export function middleware(request: NextRequest) { const locale = request.nextUrl.locale const ua = request.headers.get('user-agent') const uap = UAParser(ua || '') const type = uap.device.type if (type && type.toLowerCase() === 'mobile') { if (!locale || locale === 'en' || locale === 'default') { return NextResponse.redirect(new URL('/mobile', request.url)) } return NextResponse.redirect(new URL(`/${locale}/mobile`, request.url)) } return NextResponse.next() } // See "Matching Paths" below to learn more export const config = { matcher: '/', }
-
大部分 require 改写 import,需安装 @types/bcrypt
// require 写法 const bcrypt = require('bcrypt') // 对应的 import 写法 import * as bcrypt from 'bcrypt'
-
20230418
- 经验
-
写 api 的时候,要想着,如果要换一个产品,那么当下产品哪些东西可以轻松地复用,而无关的东西可以轻松的删除掉,即,要把所有功能解耦合,这样才能在各个产品中方便地复用各种功能。
-
不论是写 api 还是看 api,都是通过 client 请求到 server 处理的流程来进行的。在 nest 中,就是先写 controller,在写 service,然后再不断完善相关的东西。比如写用户登录api也是如此,先添在 controller 中添加 register 的路由,在 service 中实现 register,先只考虑操作数据库,然后加上参数验证、验证码之类的东西。总之,先从简单的开始写起来,然后再在基础上不断添加东西。
-
nest.js grpc 遇到一个天坑
// 写法一:这样写无法调用 grcp 服务 await this.grpcMailService.sendMail({ from: '', to: captchaDto.email, ...this.getMailContent(code) }) return this.redis.set(key, code, 'EX', 3 * 60) // 写法二:这样写可以调用对应的 grpc 服务 await this.redis.set(key, code, 'EX', 3 * 60) return this.grpcMailService.sendMail({ from: '', to: captchaDto.email, ...this.getMailContent(code) })
参照 How to get non-Observable response when calling service from gRPC client?,原因是 sendMail 定义的返回类型是
Promise<SendMailResponse>
,实际的返回类型是Observable
,如果按照写法一来写,那么就不会等待 sendMail 执行完成就直接返回了。下面这样写就没问题了。const result = firstValueFrom( this.grpcMailService.sendMail({ from: '', to: captchaDto.email, ...this.getMailContent(code), }) as unknown as Observable<unknown>, ) await result
这也表明 js 根本不知道数据的实际类型,也不回去检查。
-
20230417
- 经验
-
Lingui.js 在 React Component 之外使用翻译
-
Question: Can I use Translation outside react component ?: The t function uses the React context to know the available language and namespaces to use during the translation. Then, you can use the t function outside components as long as you pass the t function(这位其实已经给了思路,但是在不同项目中,细节是不同的。这里的 t 在我司项目里其实指的是 const { i18n } = useLingui() 中的 i18n)
-
最终结果
import { I18n } from '@lingui/core' import { t } from '@lingui/macro' export const translate = (i18n: I18n) => { const result = i18n._(t`The Buddha said, AI intelligent platform.`) console.log(result) return result }
-
-
部署的时候,如果是网页应用,则只需要部署 test 与 prod,dev 相当前端本地起的服务,网页应用两个端口交替使用。如果是后端 api,则是需要部署 dev、test 与 prod,dev 用于前端本地起的服务使用,api 只需要一个端口。
-
20230414
-
经验
-
问题:本地开发即使开了代理也无法访问 openai api,但是服务器可以正常访问
-
chatbot 服务:建立一个 chatbot 服务,部署在服务器端,处理 openai api 相关的请求(唐伟现在使用的)
- 搭建 OpenAI 代理(成功的解决方案): Express + http-proxy-middleware 进行反向代理
-
代理 TinyProxy(无效)
-
Unauthorized connection:在于 Allow host,要么注释允许所有,要么正确设置
-
npm config set proxy http://10.2.0.10:8888 npm config set https-proxy http://10.2.0.10:8888
-
axios.post(url, data, { proxy: { host: "127.0.0.1", port: 7890, protocol: "http" } })
-
运行命令
docker run --rm --name tinyproxy -p 8888:8888 -e "ALLOWED=10.2.0.9" ajoergensen/tinyproxy curl --proxy 10.2.0.10:8888 -k https://www.google.com/
-
-
-
Docker compose global level logging
-
-
YAML anchor
version: "2" services: proxy: build: proxy image: kinoulink/proxy ports: - 80:80 - 443:443 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro container_name: ktv_manager_proxy environment: - HTTP_AUTH_PASSWORD=$KTV_MANAGER_PASSWORD logging: &logging driver: "awslogs" options: awslogs-region: eu-west-1 awslogs-group: docker rancher: image: rancher/server:v1.1.3 volumes: - rancher_mysql:/var/lib/mysql - rancher_cattle:/var/lib/cattle labels: ktv.infra.proxy.domain: 'rancher' ktv.infra.proxy.port: '8080' logging: <<: *logging
-
Extension field
version: "3.4" x-logging: &default-logging driver: "awslogs" options: awslogs-region: eu-west-1 awslogs-group: docker services: proxy: build: proxy image: kinoulink/proxy ports: - 80:80 - 443:443 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro container_name: ktv_manager_proxy environment: - HTTP_AUTH_PASSWORD=$KTV_MANAGER_PASSWORD logging: *default-logging rancher: image: rancher/server:v1.1.3 volumes: - rancher_mysql:/var/lib/mysql - rancher_cattle:/var/lib/cattle labels: ktv.infra.proxy.domain: 'rancher' ktv.infra.proxy.port: '8080' logging: *default-logging
-
-
cat <<EOF > /etc/docker/daemon.json { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } } EOF systemctl restart docker
-
其他
# 在重启 docker 前记住哪些容器是启动的,重启后对比一下(唐伟) docker container ls | awk '{print $1, $2}' > ~/containers # 在配置好后通过如下命令验证 docker inspect 89c551bd7ca0 | grep -i LogConfig -A 5
-
-
openai api stream
-
try { const res = await openai.createCompletion({ model: "text-davinci-002", prompt: "It was the best of times", max_tokens: 100, temperature: 0, stream: true, }, { responseType: 'stream' }); res.data.on('data', data => { const lines = data.toString().split('\n').filter(line => line.trim() !== ''); for (const line of lines) { const message = line.replace(/^data: /, ''); if (message === '[DONE]') { return; // Stream finished } try { const parsed = JSON.parse(message); console.log(parsed.choices[0].text); } catch(error) { console.error('Could not JSON parse stream message', message, error); } } }); } catch (error) { if (error.response?.status) { console.error(error.response.status, error.message); error.response.data.on('data', data => { const message = data.toString(); try { const parsed = JSON.parse(message); console.error('An error occurred during OpenAI request: ', parsed); } catch(error) { console.error('An error occurred during OpenAI request: ', message); } }); } else { console.error('An error occurred during OpenAI request', error); } }
-
HTTP Stream using Axios (Node JS)
const response = await axios.get('https://stream.example.com', { headers: {Authorization: `Bearer ${token}`, responseType: 'stream' }); const stream = response.data; stream.on('data', data => { console.log(data); }); stream.on('end', () => { console.log("stream done"); });
-
-
- Configuration:管理自定义配置
- HTTP module:用的 axiosInstance,返回的是 Observable
- Cookies:在服务端,需要通过多语言调用 chatgpt api,那么可以通过 cookies 获取客户端选择的语言,客户端应该尽量将语言存储到 cookies 中。
- Prisma:数据库
- Redis:缓存
- RabbitMQ:消息队列
- @types/amqplib
- Lifecycle Events:Consume 在 onMountInit 中调用
- Authentication:使用 JWT 作认证
-
Validation:Dto 添加参数验证,支持类型自动转换
-
Exception filters:过滤 Exception
-
gRPC:通过 grpc 调用 mail microserver。
-
Assets:通过在 nest-cli.json 添加如下配置,自动将 .proto 文件复制到 dist 目录下
{ "compilerOptions": { "assets": [{ "include": "**/*.proto", "outDir": "dist/src" }], "watchAssets": false } }
-
-
- JwtGuard 或者 RoleGuard。
- 注意 SetMetadata 只作用于特定的请求,不能作用于整个的 controller。
- Interceptors:用于自定定义返回格式,如
{ code: 1, message: 'ok', data }
- Swagger:
- 自动生成 api 文档,方便测试 api,可替代 postman
- 使用 DTO 和
@ApiProperty()
;如果是可选参数,参考 Automatically detect optional @Query,应该使用 swagger 的@ApiPropertyOptional()
而非 class-validator 的@IsOptional()
- Bearer authentication:在 swagger 中测试需要认证的 api
- CORS:允许特定域名跨域资源共享,设置在跨域下哪些 headers、methods 可以使用,详细配置查阅 Configuration Options
- File upload:文件上传。如果包含多个字段,只能用 FileFieldsInterceptor。
-
redis可以多key对应一个value吗?:以手机号可以直接查询用户数据(mobile->hash),如使用身份证的话,先找出对应的手机号(id->mobile),再根据手机号取hash数据;
-
-
Prisma:The table (not available) does not exist in the current database:执行package.json中如下命令
- Generating the client:在本地生成
node_modules/.prisma/client
- Prototype your schema:会创建、修改相应的数据库(危险)
"generate": "prisma format && prisma generate", "dbpush": "yarn generate && prisma db push"
- Generating the client:在本地生成
20230413
- 经验
-
后续技术组的所有docker文件,都加上log的最大限制
logging: options: max-size: 10m
-
20230412
- 经验
-
清除 Mac DNS 缓存:
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
-
lark 基于现有表格建立新表格:右键表格tab栏,选择 dulicate,然后在新表格中最左侧勾选选择全部checkbox,删除即可。
-
多语言不能存储在 state 中,否则更新不及时,如果要为多语言文本设置相关状态,可以用数组下标来对应
const { prompts } = usePrompts() // 多语言内容 const initSelectedPrompts = prompts.map(() => ({ selected: false })) // 对应的状态 const [selectedPrompts, setSelectedPrompts] = useState(initSelectedPrompts) // 对应的状态用于 state selectedPrompts .map((item, index) => ({ prompt: prompts[index], selected: item.selected })) .filter((item) => item.selected) .map((item) => item.prompt) .join(', ') // 处理
-
20230411
- 任务
- 看接口实现
- RabbitMQ
- Redis
- 看接口实现
- 经验
- chatfo-mail
- 用于发送验证码,没有自建邮件服务器,而是使用 Mailgun,可通过 post 或 grpc 调用。
- chatfo-mail
20230410
- 经验
20230407
- 任务
- chatfo SEO:
-
参考 FreeFrom 及如下文章做 SEO(只考虑技术性 SEO)
-
- next-seo:实现 Meta 标签内容多语言关键点——NextSEO 和 DefaultSEO 類似,這裡提供的信息可以覆蓋掉 DefaultSEO 內相同種類的結果。
- 什么是 Open Graph 标签?不懂你还做什么社交营销优化?
- 使用 JSON-LD 處理 SEO
-
<Script strategy="afterInteractive" src={`https://www.googletagmanager.com/gtag/js?id=${GOOGLE_ANALYTICS_TRACKING_ID}`} /> <Script id="gtag-init" strategy="afterInteractive" dangerouslySetInnerHTML={{ __html: ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '${GOOGLE_ANALYTICS_TRACKING_ID}', { page_path: window.location.pathname, }); `, }} />
-
提交 sitemap.xml & robots.txt
-
const siteUrl = process.env.NEXT_PUBLIC_WEB_API_DOMAIN || 'http://localhost:3000' module.exports = { siteUrl: siteUrl, priority: 1.0, alternateRefs: [ { href: `${siteUrl}/en`, hreflang: 'en', }, { href: `${siteUrl}/ja`, hreflang: 'ja', }, { href: `${siteUrl}/zh_CN`, hreflang: 'zh-CN', }, { href: `${siteUrl}/zh_TW`, hreflang: 'zh-TW', }, { href: `${siteUrl}`, hreflang: 'x-default', }, ], generateIndexSitemap: false, generateRobotsTxt: true, robotsTxtOptions: { policies: [ { userAgent: '*', allow: '/', disallow: ['/*.js', '/*?*'], }, ], }, }
-
了解 SEO:
-
- chatfo SEO:
- 经验
-
Error response from daemon: conflict: unable to delete … (must be forced): Both images have the same IMAGE ID. You can remove the image by its name instead of its ID
-
node 的环境变量写在 .env 文件中而非 docker-compose.yaml 中,万一构建失败,就可以使用原来的镜像,而不需要添加环境变量了。
-
EACCES: permission denied, unlink ‘/app/node_modules/.prisma/client/index.js’:原因在于混合使用 npm 与 yarn,全部使用 yarn 即可解决。
# RUN npm i -g @nestjs/cli RUN yarn global add @nestjs/cli #RUN npx prisma generate RUN yarn generate
-
20230406
- 任务
- 帮忙迁移服务器:整体参考Docker容器迁移到其他服务器的5种方法
-
一个一个地备份:用 docker commit、save 备份运行中的容器,参考docker:export/save/commit谁才是你心中那个她;然后备份相应的 volume,参考Docker 使用数据卷容器备份、恢复、迁移数据卷
# 备份容器 docker commit container-hash image-name docker save image-hash > image-name.tar # 恢复容器 cat image-name.tar | docker load # 备份数据卷 docker run --volumes-from volume-name -v $(pwd):/backup image-name tar cvf /backup/backup.tar /volume-moutpoint # 恢复数据卷 docker run -v /volume-moutpoint --name volume-name image-name /bin/bash # 创建一个空数据卷 docker run --volumes-from volume-name -v $(pwd):/backup busybox tar xvf /backup/backup.tar
-
- stat /var/lib/docker/overlay2/f7e0: no such file or directory:与镜像层有关,删除对应的容器与镜像
- failed to create rwlayer:docker 残留影响的,执行一下 docker 清理
docker system prune
-
- 帮忙迁移服务器:整体参考Docker容器迁移到其他服务器的5种方法
- 经验
-
How to copy an SSH public key to a server:
# 生成密钥对 ssh-keygen -t rsa -C "ubuntu@test" # 拷贝公钥 ## 方法一 ssh-copy-id -i ~/.ssh/other_key.pub user@remote-host ## 方法二 cat ~/.ssh/id_rsa.pub | ssh user@remote-host 'cat >> ~/.ssh/authorized_keys'
-
sudo sshd -T
输出有效 sshd_config 配置 -
Is a central location for authorized_keys a good idea?: Simply set up the sshd_config file like this:
AuthorizedKeysFile /etc/ssh/authorized_keys/%u
-
Linux ps 命令查看进程启动及运行时间:
ps -eo pid,lstart,etime |grep pid
-
top命令之TIME+:指的进程所使用的CPU时间,不是进程启动到现在的时间
-
20230405
- 经验
- 后端开发除了增删改查还有什么?:使用某种技术的目的,是为了解决问题、满足需求。对于平凡公司的平凡工人,我觉得提升自我的一个方法就是自己创造需求,只有喜欢钻研折腾的人,才能深挖技术。关键是你要有兴趣,去做了,才会遇到问题,去查了,才会学习成长。
- 重学 TS
- 一个项目并不是独立的,而是各种库、框架有机结合而成的。项目学习法,是以解决某个问题、满足某个需求为导向的,而不是以学会某个库、框架为导向的。因此,项目学习法,首先是去看能解决该问题、满足该需求的现有的项目;其次,是使其运行起来,有个直观感受;然后在阅读代码过程中,不断去学习相关的知识,使自己能够读懂代码;最后是,动手写一写代码,使其满足自己的具体需求、解决具体问题。(纯粹地阅读学习效果很不好,不仅没有学会、用不起来,而且还很容易枯燥,导致削减了学习兴趣,打击了学习热情)
- 独立博客:JSPang,技术胖
- 二十行代码,搞懂 Observable
- How do you grep a file and get the next 5 lines:
grep -A 5 '19:55' file
- Hard reset of a single file:
git checkout HEAD -- my-file.txt
- The special “option” – means “treat every argument after this point as a file name, no matter what it looks like.” This is not Git-specific, it’s a general Unix command line convention. e.g.
rm -- -f
deletes a file named “-f”.ref - 06.Git从放弃到入门: 命令checkout图解:
git checkout -- ./
回滚整个项目到最近一次的暂存或提交状态。
20230404
- 任务
- 解决 chatfo 头像缩略图:公司使用 node:16 作为基础 docker 镜像,要求在该 docker 中可以方便使用的方案。
- webp-converter
- 优点:自带 precompiled executables of WebP,无需额外 linux 包
- 缺点:只能压缩图片大小(KB),而非缩小图片尺寸(200x200)
- 替代:
-
可以更改尺寸的 Jimp,使用纯 JS 实现。
-
How convert jimp object to image buffer in node?
const Jimp = require('jimp'); const img = Jimp.read('img.png'); img.getBuffer(Jimp.MIME_PNG, (err, buffer) => { console.log(buffer); });
-
maxMemoryUsageInMB limit exceeded by at least 217MB:使用的时候遇到这个问题,还未解决,巨坑。
-
-
- gm:参考nodejs使用graphicsmagick生成缩略图
- 优点:使用业界知名的处理库,功能比较全
- 缺点:额外依赖 linux 包 ImageMagick 或 GraphicsMagick
- 替代:
-
同样知名的 sharp ,自带编译好了的 libvips,next.js 同样推荐使用 Sharp Missing In Production
let useThumb = thumbPrefer let thumbUrl = '' if (thumbPrefer) { try { const thumbFile = path.join(uploadPath, `${fileNameWithoutExt}_thumb.${ext}`) const img = sharp(fileFullPath) const { width, height } = await img.metadata() const thumbSize = this.configService.get<number>('upload.thumbSize') if (width > thumbSize || height > thumbSize) { if (width >= height) { await img.resize({ width: thumbSize }).toFile(thumbFile) } else { await img.resize({ height: thumbSize }).toFile(thumbFile) } } else { useThumb = false } thumbUrl = new URL(thumbFile.replace(uploadConfig.rootPath, ''), uploadConfig.staticUrl).href } catch (e) { console.log('Sharp: ', e) } }
-
node-canvascanvas 也可以生成缩略图
-
- imaginary: image processing microservice。
- 优点:本身是微服务,还有 node-imaginary 作为 client 搭配使用。
- 替代:nginx-lua-GraphicsMagick,这个就很复杂了。
- webp-converter
- 解决 chatfo 头像缩略图:公司使用 node:16 作为基础 docker 镜像,要求在该 docker 中可以方便使用的方案。
- 经验
- VisBug:助力前端开发的浏览器插件
- gRPC:
- 首先了解 gRPC 是什么:[gRPC初探——概念介绍以及如何构建一个简单的gRPC服务](https://www.cnblogs.com/takumicx/p/10059448.html)
- 然后了解怎么在 node 中使用 gRPC:开发基于 gRPC 协议的 Node 服务
- 最后把项目运行起来,使之可以用 bloomRPC 测试:[gRpc接口调试工具BloomRpc](https://juejin.cn/post/7129414359419191303)
- Prisma
- ORM 实例教程
- 精读《Prisma 的使用》
- Environment variable not found: DATABASE_URL.
-
add
.env
fileDATABASE_URL=mysql://root:0xAGroupu7e3@10.2.0.2:6306/chatfo-chatbot GRPC_CHATBOT=10.2.0.2:51151 GRPC_MAIL=10.2.0.2:51052 REDIS_NODE1_HOST=10.2.0.2 REDIS_NODE1_PORT=7001 REDIS_NODE2_HOST=10.2.0.2 REDIS_NODE2_PORT=7002 REDIS_NODE3_HOST=10.2.0.2 REDIS_NODE3_PORT=7003 STATIC_URL=https://teststatic.chatfo.ai URL=http://10.2.0.2:9188
-
run
yarn generate
-
20230403
-
经验
-
前端组件讲究复用,但 api 讲究调用次数越少越好,能一次返回就一次性返回。
-
How to Fix “localStorage is not defined” in Next.js: Next.js performs a server render before the client render.
if (typeof window !== 'undefined') { // Perform localStorage action const item = localStorage.getItem('key') }
-
…expression of type string cannot be used to index…
const someObj:ObjectType = data; const field = 'username'; // This gives an error const temp = someObj[field]; // Solution 1: When the type of the object is known const temp = someObj[field as keyof ObjectType] // Solution 2: When the type of the object is not known const temp = someObj[field as keyof typeof someObj]
-
-
需求是:
- 分享的时候,根据 url 链接中语言参数来选择语言;(通过 router.locale 来判断)
- 初次使用自动加载浏览器默认语言;可以通过语言选择按钮切换语言。(通过 cookie 来判断)
- 总结:路由中的 locale > cookie 中的语言选择 > 浏览器语言偏好 > 默认英文
-
解决方案:
useEffect(() => { async function load(locale: string) { // @ts-ignore TYPE NEEDS FIXING i18n.loadLocaleData(locale, { plurals: plurals[locale.split['_'](0)] }) const { messages } = await import(`@lingui/loader!./../../locales/${locale}.json?raw-lingui`) i18n.load(locale, messages) console.log(locale) i18n.activate(locale) } const LANG_TO_LANG = { 'zh-CN': 'zh_CN', 'zh-TW': 'zh_TW', ja: 'ja', } const defaultLanguage = LANG_TO_LANG[navigator.language as keyof typeof LANG_TO_LANG] // 路由中的 locale 参数 if (locale) { const localeCache = Cookies.get('NEXT_LOCALE') if (Object.values(LANG_TO_LANG).includes(locale)) { if (!localeCache || localeCache !== locale) { Cookies.set('NEXT_LOCALE', locale, { sameSite: 'lax', }) } load(locale) } else { // cookie 中的 locale 设定 if (localeCache === 'en') { load('en') } else { // 浏览器中的语言偏好 if (defaultLanguage) { router.replace(router.asPath, undefined, { locale: defaultLanguage }) } else { // 默认语言 load('en') } } } } else { load('en') } }, [locale, router])
-
-
-
js-cookie: A simple, lightweight JavaScript API for handling cookies
20230401
- 经验
-
- 自动优化图片的格式、大小
- 延迟(lazy)加载
- 利于 Google 搜索的 SEO
-
- shift+command+f
- 在视图中勾“选在全屏模式下始终显示工具栏”
-
Mac 固定窗口顺序方法:点击左上角的小苹果=>选择系统偏好设置=>选择调度中心=>进入调度中心界面(Mission Control),去掉“根据最近使用情况自动重新排列空间”选项即可。
-
useSWR 文档:useSWR 适合 Get 方法获取数据,不适合 post 调用传输数据,因为其要写在顶层,不能写在回调函数之中。
- 分页 useSWRInfinite:Global Mutate with useSWRInfinite,使用时需注意 getKey 函数的
if (previousPageData && !previousPageData.length) return null
行,因为不同接口放回的数据不一样,比如 previousPageData 不是数组,previousPageData.data 是数组,导致调用失败。 - 理解 SWR
- isLoading 和 isValidating
- 无论数据是否已加载,只要有一个正在进行中的请求,isValidating 都会变为 true 。
- 当数据尚未加载并且有一个正在进行的请求时,isLoading 会变为 true 。
- isLoading 和 isValidating
- 基于SWR的应用与实践
- 用 useSWR 实现轮询(Polling),这种方式比使用 setInterval 来手写轮询要简单得多得多啊!
-
函数方式
- swr-polling
- useSWR successfully fetches , but data returns undefined:要直接返回 axios 的 res,但是项目用了 interceptors 处理
-
整数方式
export function useImage(aid: number) { const refreshInterval = useRef(100) const { data, error } = useSWR(image(aid), getImage, { refreshInterval: refreshInterval.current, onSuccess: (data, key, config) => { if (data) { if (data.image === '') { refreshInterval.current = 100 } else { refreshInterval.current = 0 } } }, }) return { data, error } }
-
- 分页 useSWRInfinite:Global Mutate with useSWRInfinite,使用时需注意 getKey 函数的
-
Prevent back navigation out of the app and redirect to home page instead.:如果直接通过 URL 访问 app 某个页面,后退会跳出 app 到浏览器首页,期望是跳到 app 首页。解决办法是:
export const getServerSideProps: GetServerSideProps = async (context) => { const previousRoute = context.req.headers?.referer || '/' return { props: { previousRoute, }, } }
-
Dynamic Router 的 [id] 可以是任意大小的数字,但是实际上并没有那么多的页面,因此,对于超过范围的页面,需要跳到 404。解决办法参考 How to Redirect to 404 Page in NextJS When Using Dynamic Routes,在 getServerSideProps 添加如下内容:
const flag = Number(context.query.flag) if (flag) { if (flag < 0 || flag > 5) { return { notFound: true, // 关键部分 } } }
-
20230331
- 经验
-
await navigator.clipboard.writeText('Text');
-
所有文章链接尽量写进日记中,这样也方便搜索,文件搜的话还是不怎么方便。
-
GitHub Clone With OAuth Access Token:
https://oauth2:<token>@github.com/<Username>/<repository>.git
。 -
CSS scroll-behavior和JS scrollIntoView让页面滚动平滑
scroll-behavior: smooth;
-
武汉人才安居:这个可以先申请资格,而不是一申请就需要去租一个房子,而是在需要的、合适的时候用在上面找房子。
-
20230330
- 任务
-
在手机上调试(访问 macbook 上开启的 node 服务)
- 手机访问,加 http,因为默认是 https,可能访问不了
- 打开关闭飞行模式
- 关闭移动网络
-
课堂:
-
域名 => DNS解析 => IP(服务器)
- 域名(web) => Kong Router (Path 规则 /) => Service (web) => Host:Port
- 域名(api) => Kong Router (Path 规则 /api/v1) => Service (api) => Host:Port
- 细节:
-
Router 通过 Path 规则将不同域名请求分配给对应的 service 处理,而 service 对应实际的服务。
-
主要关注 Service 的 Host 与 Port(容器宿主机 ip 与 port),Router 的 Hosts 与 Paths(域名与 path)
- Router 需关闭 Strip path(默认开启),作用是将 /api/v1/hello 改为 /hello
- Unable to add a Route to a Service:不是普通的输入框,输入内容后需按 Enter
-
每一个正式发布都需要给源码打一个 tag(v1.0.0)
# 列出标签 git tag # 新增本地标签 git tag -a v1.0.0 -m "v1.0.0" # 删除本地标签 git tag -d <tag_name> # 推送标签到远程 git push origin --tags # 列出远程标签 git ls-remote --tags origin # 删除远程标签 git push --delete origin tagname
-
-
如果 svg 图标显示不全,可以尝试清除
id
属性和<defs>
与<mask>
元素,如果不能删除的考虑修改id
属性名称,保持不冲突。实在不行,就使用其他图标替代掉。 -
团队合作注意多沟通,编写页面时看看某个部分是否有在多个页面使用,考虑某一个人编写,其他人使用。
-
-
grep display filename before matching line: Try this little trick to coax grep into thinking it is dealing with multiple files, so that it displays the filename
grep 'pattern' file /dev/null
-
“url” parameter is not allowed next.js:为了保护您的应用程序免受恶意用户的侵害,需要进行配置才能使用外部图像。如果用 domain 的话,就不能指定 pathname,对于在子路径中的图片,可能会报错。
module.exports = { images: { remotePatterns: [ { protocol: 'https', hostname: 'example.com', port: '', pathname: '/account123/**', }, ], }, }
-
20230328
- 经验
-
安装新 npm 包,需要 yarn build 看能否打包,否则就不使用。
-
React Hooks: useEffect() is called twice even if an empty array is used as an argument:
useEffect(() => {}, [])
执行了两次,原因是因为启用了 React.StrictMode,对生产环境无影响。StrictMode renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them (which can be quite useful).
-
Sourcetree:查看 Git 代码树
-
变量以 $ 符号结尾,可能他是写 angular 来的。
$ suffix (popularized by Cycle.js) is used to indicate that the variable is an Observable. It could make it to the official style guide too but it’s not there yet
-
React Hot Toast:一个 Toast 库,主要还是改 Styling
-
du 命令计算隐藏文件夹或文件:
du -sh *.[^.]*
-
20230327
- 经验
-
Attach Authorization header for all axios requests:
-
Login 成功后,存储 token 在本地并设置默认 Heaer
localStorage.setItem('token', `Bearer ${result.token}`) axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${result}`
-
页面刷新后,需从本地重新取回 token
axiosInstance.interceptors.request.use((config) => { if (localStorage.getItem('token')) { config.headers.Authorization = localStorage.getItem('token') } return config })
-
-
接口要考虑别人使用,不要只考虑自己用着方便。
-
返回类型要写全,不要只写自己需要的部分。例如
export type UserInfoType = { id: number email: string username: string createdAt: string }
-
像这种信息可以存储在全局,而不是每次都需要获取。
-
-
function DataInfo() { const [dom, setDom] = useState(HTMLDivElement | null); const [logData, setLogData] = useState(''); // 获取数据的方法 function getLogPages () { ... } // 监听页面滚动 const handleOnScroll = () => { if (dom) { const contentScrollTop = dom.scrollTop; //滚动条距离顶部 const clientHeight = dom.clientHeight; //可视区域 const scrollHeight = dom.scrollHeight; //滚动条内容的总高度 if (contentScrollTop + clientHeight >= scrollHeight) { getLogPages(); // 获取数据的方法 } } }; return ( <div className="modal-body logHeight" style={{ height: '480px' }} ref={(dom) => { setDom(dom); }} onScrollCapture={() => handleOnScroll()} > {logData} </div> ) }
-
const keyDownHandler = (e: React.KeyboardEvent<HTMLDivElement>) => { const key = e.code; }
-
How to create an array containing 1…N:
Array.from(Array(10).keys())
-
react-simple-pull-to-refresh:下拉更新组件
-
CSS loaders and Spinners
-
- ChatGPT: AI提示词玩家
20230325
- 经验
-
du 命令计算隐藏文件夹或文件:
du -sh * .[^.]*
-
function findscroller(element){ element.onscroll = function () { console.log(element) } Array.from(element.children).forEach(findscroller) } findscroller(document.body)
-
getServerSideProps 函数:与 getStaticProps 只在build时生成一遍静态页面,或者定期重新生成页面不同,使用getServerSideProps,页面在每接收到一条传入请求就重新生成一遍。因为每次请求都是从数据库读数据重新生成页面,页面加载速度会变慢。但是使用getServerSideProps 可以访问 request 对象。如果页面不是需要每秒更新几次,或者不需要访问 request 对象,那么使用 getStaticProps 函数更好。getStaticProps 和 getServerSideProps 不能同时使用,参见 Use getStaticProps and getServerSideProps together
-
20230324
- 经验
- 记住,不要好逸恶劳,要生产自己的价值,要被人需要。
- 小课堂:
- 公司的部署流程:本地项目 push 到 Github => 触发 Github hooks => Jenkins 执行宿主机脚本 => 脚本拉取 Github 源码、build docker 镜像、运行镜像 => 其他(Kong服务、域名绑定等)。每一个 web 服务拥有两个端口,新的端口用起来后,停用旧端口,保证服务可用性。
20230323
- 经验
- 适配任意尺寸方法
- 宽度不写死,100% 宽度(
w-full
),然后加一个最大宽度(max-w-
),加 padding 调整间距。 - 高度不写死,内容撑高,然后加一个最大高度(
max-h-
),加 padding 调整间距,文本框还可用 row。 - 不能说为了 UI 而写死,也要考虑程序的写法。
- 宽度不写死,100% 宽度(
- 整个页面高度为 100vh,最后一个元素占据剩余空间,其仅有的子元素占据所有高度,子元素内容如果超过高度,则出现滚动条。
- 最后一个元素占满剩余可用高度:用
flex-grow: 1
,其他元素为flex-grow: 0
- 还需要在父元素上添加
overflow: hidden;
,子元素添加overflow-y: auto;
。即 How to make child div scrollable when it exceeds parent height?
- 最后一个元素占满剩余可用高度:用
- navigator.clipboard.writeText() not working on specific IOS devices:There are security limitations on this API in (Mobile) Safari, one of which is it has to be executed on a site secured with https, so will not work on localhost.
- iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天:有不错的系列中文文章。
- 适配任意尺寸方法
20230322
- 经验
-
获取焦点时移除placeholder,失去焦点重新获得placeholder内容
-
css
/*WebKit browsers*/ input:focus::-webkit-input-placeholder { color:transparent; } /*Mozilla Firefox 4 to 18*/ input:focus:-moz-placeholder { color:transparent; } /*Mozilla Firefox 19+*/ input:focus::-moz-placeholder { color:transparent; } /*Internet Explorer 10+*/ input:focus:-ms-input-placeholder { color:transparent; }
-
-
lodash.shuffle:将数组打乱顺序
-
- 在 seo.ts:
{ titleTemplate = 'Next SEO | %s'; }
- 在某个页面:<NextSeo title={i18n._(t
This is my title
)} />
- 在 seo.ts:
-
20230321
- 经验
-
md:
作为 Desktop 与 Mobile 的短点比sm:
要好。 -
Viewport meta tags should not be used in _document.js's <Head>
-
Set your viewport meta tag in pages/_app.js
-
Next.js 暴露了一个内置组件 Head,用于将 HTML 标签添加到页面的 head 中。
<Head> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> </Head>
-
-
禁止 IOS 移动端缩放
const lastTouchEnd = useRef(0) useEffect(() => { // 双指缩放 const handleTouchstart = (event: TouchEvent) => { if (event.touches.length > 1) { event.preventDefault() } } // 双击缩放 const handleTouchend = (event: TouchEvent) => { var now = Date.now() if (now - lastTouchEnd.current <= 300) { event.preventDefault() } lastTouchEnd.current = now } document.documentElement.addEventListener('touchstart', handleTouchstart, { passive: false }) document.documentElement.addEventListener('touchend', handleTouchend, false) return () => { document.documentElement.removeEventListener('touchstart', handleTouchstart, false) document.documentElement.removeEventListener('touchend', handleTouchend, false) } }, [])
-
20230320
- 经验
-
Apple Cannot Check It for Malicious Software:在 Finder 中右键打开就行。
-
首先考虑移动端怎么做,移动端优先;用 devTool 开手机模式,然后可以拖放检查。
-
daisyUI 可以选主题,可以配置主题,在 tailwindcss.config 中 daisyui 部分修改。
-
Tailwinds 有 vscode 插件 Tailwind CSS IntelliSense。可以看到像素对应的 tailwind css 类,选择最近似的就行。
-
Dropdown CSS 代码是看的懂得吧!
<style> .dropdown { position: relative; display: inline-block; } .dropdown-content { display: none; position: absolute; background-color: #f9f9f9; min-width: 160px; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); padding: 12px 16px; } .dropdown:hover .dropdown-content { display: block; } </style> <div class="dropdown"> <span>鼠标移动到我这!</span> <div class="dropdown-content"> <p>菜鸟教程</p> <p>www.runoob.com</p> </div> </div>
-
20230318
- 任务
- 调查google登录和apple登录的整合登录情况
- 经验
-
开发规范
- git 使用技巧
- git rebase 合并 commit,p 选择该 commit,s 向上合并,注意只能 rebase 没有 push 的 commit;
- git commit —amend 修改 commit message;
- git add -p 进入 patch mode ,让我们可以挑选一部分改动进行提交。
- 对开发的新功能,则命名为
feat-[功能名称]
;对修复的bug,则命名为fix-[bug描述]
;命名时使用-
减号来分割单词。 - 从dev上开新分支,完成后,合并dev分支到功能分支上,解决冲突(如果有)后提交PR到dev上。
- 在框架自动生成的多语言内容时,如果对应语言没有翻译内容,则不提交该文件。如果需要添加翻译内容,则运行yarn lingui让程序重新补充未翻译的内容。
- 网站内的路由跳转,使用链接(Next Link 标签)的方式跳转,而非 onClick 和 router.push,利于 SEO。站外链接统一用 “_blank” 方式打开。
- 可以使用 yarn lingui 生产对应的条目,git push 时需删除没有翻译的条目。
- git 使用技巧
-
headlessui 写的手机端菜单侧滑动画,关键在于清楚 CSS 的 transition 和 transform,不要被 tailwindcss 迷惑了。
<Transition show={isShow} as={Fragment}> <div className={classNames('fixed left-0 top-0 h-full w-full', maskClass)} onClick={onMaskClick}> <Transition.Child className={classNames('relative h-full w-1/2 bg-white', menuClass)} style={{ marginLeft: reverse ? 'auto' : '0' }} enter="transition ease-out duration-100" enterFrom={reverse ? 'translate-x-full' : '-translate-x-full'} enterTo="translate-x-0" leave="transition ease-in duration-90" leaveFrom="translate-x-0" leaveTo={reverse ? 'translate-x-full' : '-translate-x-full'} as="div" onClick={handleClick} > {children} </Transition.Child> </div> </Transition>
-
监听 window 的 resize 事件,如果调整窗口大于1280 (preWidth < 1280 && width >= 1280) 或小于 1280 (preWidth > 1280 && width <= 1280),则 reload 一次页面。
const { width } = useWindowSize() const preWidth = usePrevious(width) if (preWidth && width) { if ((preWidth > 1280 && width <= 1280) || (preWidth < 1280 && width >= 1280)) { window.location.reload() } }
-
next/image 要求固定的 width 和 height,可通过一下方式实现 next/image 响应式改变大小
<div className="relative w-16 h-16 shrink-0"> <Image src={avatar || DEFAULT_AVATAR} alt="avatar" fill className="object-cover rounded-full" /> </div>
-
在 React 中,不再 useEffect 中清除 timerID,通过 useRef 实现。
const timer = useRef<NodeJS.Timeout>() timer.current = setTimeout(() => {}, delay * 1000); clearTimeout(timer.current as number | undefined)
-
Prevent scroll when modal is open
useEffect(() => { if (isShow) { document.body.style.overflow = 'hidden' return () => { document.body.style.overflow = 'auto' } } }, [isShow])
-
20230317
- 经验
- 有问题,一定要说出来,就不是自己的锅了,而是大家的。
- 产品问题找产品负责人,技术问题找技术负责人,但最终所有问题都属于产品问题,由产品负责人负责。
- 所有问题(UI、产品、测试)都汇总在一个表格之中,解决后@负责人。
- 编写代码后,本地测试通过,自测通过后合并需再测试,总之,在所有问题解决之前,不要说完成了,不要部署到正式服务器。
20230316
- 经验
-
How to Darken an Image with CSS:影响最小、符合预期的是使用图片的线性渐变
background-image: linear-gradient(rgba(0, 0, 0, 0.5),rgba(0, 0, 0, 0.5)) , url(bg.jpg);
-
How to get a key in a JavaScript object by its value?
const getKeyByValue = (object: { [props: string]: string }, value: string) => { return Object.keys(object).find((key) => object[key] === value) }
-
20230315
- 经验
-
要在 Dropdown menu 中使用 Next.js 的 Link 标签,需要将 Link 标签放在最顶层,并且参考 Closing menus manually 手动关闭。
<Menu> <Menu.Button>Menu</Menu.Button> <Menu.Items> {menuItems.map((menuItem) => ( <Menu.Item key={menuItem.name}> {({ close }) => ( // get close function <Link href={menuItem.href} legacyBehavior> <a> // Component <div onClick={close}>{menuItem.name}</div> </a> </Link> )} </Menu.Item> ))} </Menu.Items> </Menu>
-
Using different API url for development and production with React and axios:利用
.env.development
和.env.production
文件来自动切换生产环境与开发环境的 API 的域名:const API_ENDPOINT = process.env.REACT_APP_API_ENDPOINT
-
20230314
- 经验
-
next/router:路由
const router = useRouter() router.push(url)
-
项目所有 url 都放在
src/config/share_url
-
next-seo:每一个 Page 都需要
<NextSeo title="desc" />
,至少要有 title 属性,用于 SEO,具体位置不限——不要求放在最顶层,因为最后其会生成在 head 标签中作为 meta 元素存在。 -
Next Link 链接写法:
<Link legacyBehavior key={item.key} href={item.href}> <a className="underline" target="_blank">{item.text}</a> </Link>
我偏向使用原生的 a 标签,没懂这样写是干嘛的。写法具体参考 next/link - If the child is a functional component,也就是如果你想使用 Link 组件,必须遵守对应的语法规则。
采用这种写法,可用通过 DevTool 来检查是否生效,可以看到其渲染为普通的带 href 属性的 a 元素,具体缘由参考 Next.JS “Link” vs “router.push()” vs “a” tag——即 Link 生成 a 元素并且不 reload page,单独用 a 元素会 reload page。
-
How to deploy a react app to a subdirectory: 今天张新勇老大遇到个问题,需要将 React App 到服务器 register 子目录,但是一直报错,因为其访问的资源指向根目录,解决办法需要将所有资源引用指向 register 这个子目录,解决方法如下:In package.json add homepage like below
{ "homepage": "https://domain-name.com/directory-name", //OR "homepage": "/directory-name", }
但问题并没有结束,其结果能让静态资源的引用指向
/directory-name
目录(index.html 中引用),但并没有解决超链接跳转问题。该项目使用 react 的类组件,使用 react-router-dom@5 来做路由。主要参考 React Router V4 but on a different homepage in package.json… fix 404 not found? 这篇文章-
方法一:除了要在 package.json 添加 homepage 属性外,还需要在
<BrowserRoter>
中添加 basename 属性,即<BrowserRoter basename="/directory-name"
,并且将所有 a 标签替换为 react-router-dom 的 Link 标签,因为其自动添加 basename。 -
方法二:使用
<HashRouter>
来解决,除了不需要添加 basename 外,其他一样,然后可以如下方式写(马梦圆喜欢这样写😂)onClick={() => { window.location.href = "#/Privacy_Policy"; }}
HashRouter 作用参考 React-router URLs don’t work when refreshing or writing manually,即客户端生成的路由,如 <www.example.com/home,服务器是不接受的,利用> hash history,即 <www.example.com/#/home> 就可以绕过这个问题,因为总是请求根域名 <www.example.com。>
总之,这些配置基于这样一个目的:在本地(开发环境)下可以直接运行,方便代码编写与调试;打包的时候自动处理从开发环境到生产环境的迁移,例如调整链接、精简代码之类的;打包后可以直接在服务器上部署运行。
-
-
为了告诉开发环境的服务器去代理任何开发环境中未知的请求到我们自己的api服务器,添加一个proxy到package.json的字段,但在 next 中无效,需要使用下面的 next-http-proxy-middleware
-
20230313
- 经验:
-
在谷歌浏览器中对颜色进行十六进制、rgba、hsl切换:按住shift键,点击颜色快,即可切换。
-
ESLint
-
ESLint + Prettier + Typescript and React in 2022:
- 除了需要安装对应的 modules 外,还需要在 vscode 安装对应的插件才能起作用
- ESLint:代码检测工具,Prettier:格式化代码。
-
ESLint + VSCode: How to Format Your Code Using .eslintrc:ESLint 可以将 prettier 作为插件,具备格式化代码的功能,参考 Integrating with Linters同时如下配置以启用
{ "eslint.format.enable": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": true } }
-
搞懂 ESLint 和 Prettier:eslint-config-prettier 和 eslint-plugin-prettier
-
Automatic Class Sorting with Prettier:
yarn add -D prettier-plugin-tailwindcss
-
<div className="bg-gradient-to-r from-[#9b4ae6] to-[#2b81e4]"/>
-
‘tsc command not found’ in compiling typescript:
npm install typescript@4.6.2 -g
,版本与项目一致 -
How to View Page Source in Safari on Mac
- Choosing “Preferences”, going to “Advanced” and checking the box to enable the developer menu
- Press Command + Option + U keyboard combination to view the page source
-
interface Test{ name: string; age: number; //可有可无 sex?:boolean, hobby:()=>string, //自定义key 任意值 [propname:string]:any, }
-
Typescript 传递子组建:利用解构赋值将变量重命名为大写
const SocialMedia: React.FC<SocialMediaProps> = ({ comp: SvgIcon, ...reset }) => { return <SvgIcon {...reset} /> }
-
macOS批量图片处理:例如 resize 图片
sips -Z 256 input --out output
-
Command-line application for converting SVG to PNG on Mac OS X
qlmanage -t -s 1000 -o . picture.svg
It will produce picture.svg.png that is 1000 pixels wide.(PS:除非必要——文件太大,否则就使用原本的图片)
-
20230311(🛌)
-
IBM LinuxONE Community Cloud:Virtual Server Deployment Guide
成功注册了。很简单,不需要银行卡,就一个 icloud 邮箱,理由写的 “open source“。说是有 120 天的试用,不知道试用时间完了之后怎么说,反正如果邮箱足够的话,是不是有无线使用期限呢?反正我现在有个小鸡使用就行了,也没有什么复杂的需求,也有不了,因为用的 IBM s390x 架构。
ssh linux1@148.100.79.64
-
How to Kill user sessions in Linux
pkill -9 -t pts/2
-
Are IPv4 ports separated from IPv6 ports?:是的,在防火墙中需要分别为 IPv4 与 IPv6 设置端口与协议。但是要确定 VPS 的 IPv6 地址是公网地址,不是就没必要设置了。
-
How to curl using IPv6 address?:浏览器也是同样格式
curl -g -6 'http://[fe80::3ad1:35ff:fe08:cd%eth0]:80/'
20230311
- 经验
-
知道一个工具能干什么的比知道该工具具体怎么用更重要,很多教程一上来就讲这样做、那样做就成了,但是没讲我为什么要这样做、那样做。
-
tailscale 是 VPN(虚拟私有网络),作用是让你可以在公开的网络线路上建立一个私有的子网,起连接设备作用。要翻墙需要配合 proxy server,作用是将客户端请求流量转发到目标网站或应用程序,然后将响应转发回客户端。
-
先有现在,才有未来,先把公司任务完成了,才有机会去学习更多的知识。总之,学习知识和掌握技能不是目的,发挥自己的价值获取报酬才是目的。
-
画 UI 的话,先把内容填上去,然后再逐渐地添加样式,最后添加行为(即先只写 HTML,再写 CSS,最后再写 JS)。
-
Change Visual Studio Code’s title bar color
"workbench.colorCustomizations": { "[Name of the Current Theme you are using]": { "titleBar.activeBackground": "#191919cc", "titleBar.activeForeground":"#ffffff", }, }, "window.titleBarStyle": "custom"
-
20230310
- 任务
- 我司流程:Github => CI/CD 工具(调用外部脚本打包并直接启动 web 服务器)
- 经验
- 即时设计:类 Figma
- cloudping.info:测试你的机器 ping 世界各地的亚马逊云服务器的速度。(AWS 云测速,一般需要关闭代理)
- 利用Docker 实现自动热部署
- 『前端进阶』🐳 Docker 部署 —> GitHub Active 自动部署
- 世界互联网基础设施地图
- printfriendly
20230309
-
任务
-
配置 Jenkins 的仓库同步与 docker 构建:关注点 Jenkinfile
-
Pull Repository(Freestyle project 方式)
-
credentials: Manage Jenkins > Manage Credentials
-
How to use Github Personal Access Token in Jenkins:username 随意,password 为 GitHub 的 PAT。(这里花了好长时间)
- Go to
credentials
>System
>Global credentials
>Add credentials
a page will open. - In Kind drop-down select Username and password.
- In User put a non-existing username like
jenkins-user
oruser
. - Add
Personal Access Token
in the password field
- Go to
-
ERROR: Couldn’t find any revision to build:master 改为 main
-
例子
-
How to use Jenkins to Sync between your code repository on Acquia and GitHub?:用 cron 做 tigger,即勾选 Poll SCM。
-
Jenkins GitHub Integration:用 Webhooks 做 tigger,即勾选 GitHub hook trigger for GITScm polling,需要 GitHub Plugin,这样仓库一有 push 就会执行 build 流程。
- go to your GitHub repository and click on ‘Settings’.
- Click on Webhooks and then click on ‘Add webhook’
- Click on Webhooks and then click on **‘Add webhook’**In the ‘Payload URL’ field, paste your Jenkins environment URL.
$JENKINS_BASE_URL/github-webhook/
— for example:https://ci.example.com/jenkins/github-webhook/
-
-
-
Pull Repository(Pipeline 方式)
-
Jenkins Pipeline Github | Complete Tutorial With Example
pipeline { agent any stages { stage('Build') { steps { git url: 'https://github.com/naiveskill/devops_cred.git', branch: 'main', credentialsId: 'github_creds' } } } }
-
-
Build Docker Image(Pipeline 方式)
- 流程
-
先在本地编写 .dockerignore 与 Dockerfile 并运行通过
-
.dockeringore
.git node_modules
-
-
然后编写 Jenkinsfile
docker.withRegistry('https://registry.example.com', 'credentials-id') { def customImage = docker.build("react-app-test", "-f ${dockerfile} ./dockerfiles") customImage.inside { sh 'echo "Stage Build Finished"' } customImage.push() }
-
- 流程
-
-
The user
jenkins
needs to be added to the groupdocker
, Then restart Jenkins.sudo usermod -a -G docker jenkins
-
或者,直接在 Jenkinsfile 中用 sudo(如果可以的话)
sh 'sudo docker image build -t react-app-test .'
-
-
How to tell jenkins not to kill processes after successful execution of job in multijob project?: Jenkins : ProcessTreeKiller for pipelines:
JENKINS_NODE_COOKIE=dontKillMe /your/mongodb/process
-
参考
-
其他
-
How to restart Jenkins manually?
(jenkins_url)/safeRestart
- Allows all running jobs to complete. New jobs will remain in the queue to run after the restart is complete.(jenkins_url)/restart
- Forces a restart without waiting for builds to complete.
-
Fix the ‘expected a step’ Jenkins error: Surround all code snippets in a
script { }
block -
How to keep environment variables when using sudo:
-E, --preserve-env
export HTTP_PROXY=foof sudo -E bash -c 'echo $HTTP_PROXY'
-
-
jenkins/jenkins:公司使用的部分
- Publish Over SSH:通过 ssh 执行宿主机脚本
- jenkins/ssh-agent:参见 Using Jenkins agents,用于 Jeinks master 连接、管理 slave。
-
-
经验:
20230308
-
经验
-
Hardhat:帮助开发人员管理和自动化构建智能合约和dApp的过程中固有的重复任务。
-
iTerm2 相关问题
-
Dedicated Hotkey Windows:设置系统快捷键 Command + Return 在其他 Window 上打开一个 iTerm Session
-
You have to specify the default window size in rows and columns. The setting can be found in iTerm > Preferences > Profiles > Window. (160 x 35)
-
How to open a new tab in iTerm in the same folder as the one that is open
Select “Reuse previous session’s directory” from the preferences of your profile.
-
How can I set an environment variable only for the duration of the script?
VAR=value
是我想要的,env VAR=value
会 export 到当前环境之中。https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
-
git clone https://mirrors.tuna.tsinghua.edu.cn/git/ohmyzsh.git cd ohmyzsh/tools REMOTE=https://mirrors.tuna.tsinghua.edu.cn/git/ohmyzsh.git sh install.sh
-
git clone --depth=1 git@github.com:zsh-users/zsh-autosuggestions.git $ZSH_CUSTOM/plugins/zsh-autosuggestions git clone --depth=1 git@github.com:zsh-users/zsh-syntax-highlighting.git $ZSH_CUSTOM/plugins/zsh-syntax-highlighting
.zshrc
plugins=(git macos zsh-autosuggestions zsh-syntax-highlighting)
-
-
-
运维相关
-
服务器:hp server、orcale server、google cloud、desktop、pi
-
操作系统:Ubuntu
-
mysql/mongodb
-
redis cluster
-
elasticsearch
-
ipfs
-
ribbitmq 消息队列
-
koa/nest.js 服务
-
管理:Portainer、Kong
-
ansible:批量系统配置、批量程序部署、批量运行命令等功能。
-
auditd:审计工具
-
cloud-init:云平台为Linux操作系统的虚拟机做系统初始化配置的开源服务软件。
-
tailscale P2P VPN 工具:
-
安装配置:
brew install --cask tailscale defaults write io.tailscale.ipn.macsys ControlURL http://104.199.128.36:8082
-
运行tailscale,点击log in,获取类似
headscale nodes register --user USERNAME --key nodekey:...
命令,发给管理员让他加你进入。- 注意关闭系统代理。
- 注意设置防火墙让 tailscale 通过。
- 如果无网则取消勾选 Use Tailscale DNS Setting。(Mac dns 也在 resolve.conf 中看)
-
最后与管理员沟通获取登陆具体服务器的信息,登陆用 VLAN IP。
-
连接之后是可以与 CFW 一起使用的!
-
-
OneDev CI/CD 工具:配置仓库同步(已弃,彭梓旭不喜欢 yaml)
- 获取 Github Person Token:就在个人设置的 Developer settings 中。
- 在面板中 Projects 栏中,点击 Import 导入 Github 仓库,根据提示填入对应内容。
- 查看 Commit and Push in Job配置 job secret,并为项目设置一个 checkout step(关键,否则不能 pull push),用 http(s) 认证。
- 参考在《OneDev里配置仓库同步》:
- 添加一个 pull(勾选 force) step(定义做什么),用于拉取 github 仓库。
- 设定 Cron Tigger 的 trigger(定义何时运行)。(Bruch update 只适合 push,pull 是不会自动的,除非用 github webhooks)
- 编辑后查看 .onedev-buildspec.yml 源文件,添加到项目中并同步到 github。
- 运行 Job 拉取 github 进行测试。
- 解释:同时加 push 与 pull step 的并勾选 force (必须,否则不能拉取最新的内容)的话,如果先 push,则会将 github 所有更改删除,先 pull 则会将 onedev 所有修改删除(即 .onedev-buildspec.yml 文件),因此干脆只用一个。
- 关键点在于 .onedev-buildspec.yml 这个文件。
-
20230307
- 经验
-
Mac 与 Windows 传输文件。我尝试了 FileZilla 与 Samba,都没成功,很烦。尝试使用 Snapdrop,体验没有 Aridrop 好(只有 2 MB/s 左右),问题例如:不能刷新,不能开代理,传输大文件中断。最后通过 python3 -m http.server 起个 http server 解决,http 本来就是分享资源的,完全可行。这里有个误区,传输老想着用传输工具,而不是使用现有的能够传输的东西。这里也发现 Mac 默认不开防火墙。
-
Orcale 永久免费云服务:很难申请成功。
-
Docker 相关问题:
-
How do I start the docker daemon on macOS?:
- 我用的 Macbook air 是 arm(M1),安装不了 virtualbox 啊!
- 用
brew install --cask docker
安装,在桌面启动 docker.app,在 terminal 运行 docker 命令就行了。
-
Dockerfile 中的 COPY 与 ADD 命令:COPY 可用于 multistage 场景下,把前一阶段构建的产物拷贝到另一个镜像中;ADD 解压压缩文件并把它们添加到镜像中。
-
常用命令:
# 创建 image 文件 docker image build -t freefrom -f Dockerfile.hardhat --platform linux/amd64 . # 查看镜像元数据,Layers 可看到镜像所有层 docker image inspect hello-world # 新建容器,容器的 3000 端口映射到本机的 8000 端口。 docker container run --rm -p 8000:3000 --name container-name -it koa-demo /bin/sh # 通过 docker-compose 新建容器 docker-compose up --build -d # 查看容器 logs,不论是 running 的还是 stop 的 docker contianer logs 69d1 # 进入容器 docker container exec -it 11fd20be74b6 sh # 清理 image、container、network、build cache docker system prune -af # 查看容器状态 docker container stats b901a13001a0
-
Puppeteer 报错:Puppeteer is a Node.js library which provides a high-level API to control Chrome/Chromium over the DevTools Protocol.
-
问题一:
The chromium binary is not available for arm64
因该是默认用当前系统架构,改架构用
--platform linux/amd64
。 但是问题是成功创建了 linux/amd64 镜像后,在 M1 的 Mac 上也运行运行不了啊! -
问题二:
ERROR: Failed to set up Chromium r800071!
因为只是测试 node_modules layer,所以暂时通过
--ignore-scripts
跳过。
-
-
-
How to copy multiple files in one layer using a Dockerfile?
COPY README.md package.json gulpfile.js __BUILD_NUMBER ./ COPY dir1/* dir2/* ./
-
docker build 前端项目的话,每次都需要下载 node_modules,这也太耗费流量了吧。 解决:
FROM node:16 COPY package.json /tmp/package.json COPY yarn.lock /tmp/yarn.lock RUN cd /tmp && yarn install --frozen-lockfile RUN mkdir -p /usr/app && cp -a /tmp/node_modules /usr/app WORKDIR /usr/app
解析:
- 所有docker 只用在命令“没有变化”时才会用缓存。而且,一但某一条命令没能利用缓存,那么后续的所有命令都不会使用缓存。除了 COPY 跟 ADD,只要 Dockerfile 里的指令行没有变化就认为没有变化。对于 COPY 跟 ADD ,还要比较文件内容跟属性。所以,如果先 COPY 整个项目,那么大多数情况下会有变化(没变化就不需要重打镜像了),于是不能使用缓存。
- docker image 是分层的 (layer) ,每一个命令增加一个新的 layer 。打包结束之后,在打包的机器上,dockerfile 每一条命令执行之后“镜像”都存在,只要把相应的 layer 取出来就可以了。dockerfile 指令的执行,其实是先拿到上一个指令生成的镜像,执行当前指令,再把结果保存成一个新的镜像。两次执行 dockerfile ,如果发现执行当前指令的镜像已经存在,就直接拿过来用了,而不会重新执行指令,这就是所谓“缓存”。
-
20230306
- 经验:
-
loader.load('./girl.fbx', function (fbx) { fbx.scale.set(0.1, 0.1, 0.1); scene.add(fbx); loader.load('./Walking.fbx', function (anim) { //创建了一个针对于该模型的混合器 mixer = new THREE.AnimationMixer(fbx); // 动画片段 var clip = anim.animations[0]; // 使用混合器和动画片段创建一个动画播放器来播放 var action = mixer.clipAction(clip); action.setDuration(1); action.play(); }); }); var clock = new THREE.Clock(); function animate() { // 向浏览器发送请求我希望你稍后调用函数,默认是每秒调用60次 requestAnimationFrame(animate) var time = clock.getDelta(); if (mixer) { mixer.update(time); } }
20230305(🛌)
- three.js 关注点(笔记):
- render(渲染器) 渲染 scene(场景) 和 camera(相机),scene 中添加 mesh(模型)和 light(光源),mesh 由 geometry(几何体) 和 material(材质) 构成。
- OrbitControls 鼠标操作三维场景。
- 参数widthSegments、heightSegments约束的是球面的精度,球体你可以理解为正多面体,就像圆一样是正多边形,当分割的边足够多的时候,正多边形就会无限接近于圆,球体同样的的道理。
- 辅助三维坐标系AxisHelper,光源辅助对象SpotLightHelper、PointLightHelper、DirectionalLightHelper,骨骼辅助显示 SkeletonHelper。
- 漫反射、镜面反射分别对应两个构造函数MeshLambertMaterial()、MeshPhongMaterial()。
- 类型数组之所以有类型这个定语,就是因为每一个构造函数对应一种 number类型里面细分的数据类型,例如构造函数Int8Array()创建的数组每个元素占据的内存是8位。
- 对于网格模型Mesh而言,几何体geometry由三个顶点为一组渲染出来的三角形组成。
- 平行光漫反射简单数学模型:漫反射光的颜色 = 网格模型材质颜色值 x 光线颜色 x 光线入射角余弦值
- 可以通过 .traverse() 递归遍历的算法去遍历Threejs一个模型对象的所有后代
- 所谓本地坐标系或者说模型坐标系,就是模型对象相对模型的父对象而言。世界坐标系默认就是对Threejs整个场景Scene建立一个坐标系,一个模型相对世界坐标系的坐标值就是该模型对象所有父对象以及模型本身位置属性.position的叠加。
- 纹理坐标:以图片左下角为坐标原点,右上角为坐标(1.0,1.0),图片上所有位置纵横坐标都介于0.0~1.0之间。纹理UV坐标和顶点位置坐标是一一对应关系。
- 关键帧KeyframeTrack和剪辑AnimationClip两个API来完成关键帧动画,通过操作AnimationAction和混合器AnimationMixer两个API播放已有的帧动画数据。
- 通过Bone类可以实例化一个骨关节对象,然后通过多个骨关节对象可以构成一个骨骼层级系统;通过Skeleton类可以把所有骨关节对象Bone包含进来;SkinnedMesh类的字面意思就是骨骼网格模型。
- 导出模型信息:
console.log(JSON.stringify(geometry.toJSON()));
20230304(🛌)
- 2022大前端总结和2023就业分析:
- 未来:AI 和 Cropto(PS:公司之前为区块链,现在人工智能机器人,完美覆盖啊)
- 2022年前端主流趋势
- 性能——构建工具:make => Grunt => Gulp => Webpack => Vite => Turbopack
- 运行时:Node.js、Deno、Bun
- 体积:SSR
- 通常产品开发都是先实现功能,然后再优化,然后再做周边
- 当你想提升性能的时候,除了万金油缓存外,减小体积就是最简单的方式
- 跨度领域:Gluon、Electron、Tauri、Neutralinojs
- Rust 写前端基建,是当下趋势
- 前端垂类,其实是最吃香的部分:比如互动游戏,3d,webrtc,比如可视化编辑器,AFFiNE,QUill,X6
20230303
- 经验
- 在 vscode 中,Command+点击 lingo 组件属性,就可以到类型定义文件 d.ts,然后就可以看到支持哪些属性及其类型,然后见名知意,或查找这些属性都起什么作用。
- 像 onClick 这样的属性,按照上面操作后定位到类型定义文件后,就可以看其路径,然后在原文件中导入类型就可以使用了。
- VSCode 插件 Live Server 解决跨域问题。
- 任务:
- 看完 Lingo3d.js 后,继续学 three.js(我司急需)
- three.js:首先看《Three.js入门》这篇入门文章,然后以《Three.js零基础入门教程》为主,加上配套视频教程,以《three.js 官方中文文档》为辅(主要用于看最新的API)进行学习。
- 看完 Lingo3d.js 后,继续学 three.js(我司急需)
20230302
- 经验
- lingo3d 关注点:官网可以用来调各种属性,看其作用(不完善且旧);GitHub 上有以
example-
开头的仓库,都是例子。World
组件Model
组件:放人物或场景模型src
属性:加载模型 fbx 文件,建议使用绝对路径animations
属性:加载自定义动画 fbx 文件animation
属性:使用模型本身包含的动画或自定义动画physics
属性:值为map
时,src
需要使用相应 scene(场景)模型,否则会发现,人物模型加了physics="character"
后,会不断的往下掉ref
属性:控制模型的移动ref.current.lookAt()
方法:人物看向目标点ref.current.moveForward(-1)
方法:往自己前方走onLoop
方法:每帧ref.current.lookTo
方法:看向,最后为转向速度ref.current.moveTo
方法:移动,最后为移动速度ref.current.onMoveToEnd
方法:移动结束事件
innerY
属性:模型相对于 xyz 中心移动intersectIDs
和onIntersect
属性:当碰撞intersectIDs
中指定 id 的模型时,会触发onIntersect
事件roughnessFactor
属性:粗糙度系数Find
组件:定鼠标瞄准时状态
Dummy
组件:官方提供的人体模型Cube
组件:立方体x
和y
和z
/depth
属性: x 轴、y 轴、z 轴id
属性:可用于碰撞检测texture
属性:材质textureRepeat
属性:如果糊的话,就使之重复次数变高onClick
属性:e.point
:位置(x、y、z)
OrbitCamera
组件:使相机按照一定的路径运动autoRotate
:自动绕y轴旋转
ThirdPersonCamera
组件:使相机看向并跟随放入其中的人物模型(Model 是其子元素)ative
属性:激活相机mouseControl
属性:鼠标控制innerY
属性:移动内部的相机lockTargetRotation
属性:解决人物不受控制fov
属性:焦距,人眼在 50 左右,焦距越小,中心面越广
Skybox
组件:需要360度环绕背景图片(equirectangular),或者 Poly HavenKeyboard
组件:同 useKeyboardLingoEditor
组件:同 EditorHTML
组件:直接添加 htmlEditor
组件:需要关闭相机的 active,同失效的 map-debug(放在 Word 外部会在屏幕中间挡住内容)
Reticle
组件:准星Setup
组件:代替在 World 组件中设置属性Reflector
组件:反光板useLoop(function, boolean)
hook:循环,不断做某事useKeyboard
hook:鼠标事件usePreload
hook:预加载模型,返回 progress
- Mixamo:
- 绑好骨骼的模型: with skin 下载(t-pose)
- 仅动作: without skin 下载,in place 复选框就不往前走(原地走)
@xstate/react
:状态机(超赞),例子链接,还有 xstate vscode 插件。- VSCode 快捷键
- Ctrl+鼠标左击:跳到定义
- Ctrl+-:返回
- Command+i:显示智能补全
- Command+.:quick fix
- Shift+Option+F:格式化代码
- Command+Option+左方括号:折叠代码块
- Command+Option+右方括号:展开代码块
- Command+/:单行注释
- Shift+Option+A:多行注释
- typescript 自定义类型:TypeScript 入门教程:如果需要看源代码的话,例如 lingo.js 官方文档不全,那么只能通过源码来看如何使用了,这就要求有足够的 typescript 知识。我之前虽然系统学过 typescript,但是在看 lingo 源码还是疑惑 class 即是类又是类型的,经过查找回忆了起来,总结如下
- 在定义 class 的时候会创建同名的实例类型
- 定义:
class ClassName {}
- 使用:
let a: ClassName = new ClassName()
class ClassNameB extends classNameA
- 定义:
- interface 定义接口类型
- 定义:
interface InterfaceName
- 使用:
let b: InterfaceName
class ClassNameB extends classNameA implements InterfaceNameA, InterfaceNameB
- 定义:
- type 用于类型别名
- 定义:
type TypeName = ClassName
- 使用:
let c: TypeName
- 定义:
- declare 声明类型:例如指定某变量为某种类型,用于代码补全、接口提示,多写在 d.ts 类型声明文件中
- 定义:
declare let d: ClassName
- 定义:
- 在定义 class 的时候会创建同名的实例类型
- lingo3d 关注点:官网可以用来调各种属性,看其作用(不完善且旧);GitHub 上有以
20230301
-
文章
- 任意两个点的曲线连接JS算法:衡量自己Web前端技术的一个简单办法就是,如果让你实现这样一个产品,你能否立刻在脑中形成实现方案,并完成之。
-
任务
- 学习 lingo3d
- 官网有点问题,因此以别卷了,快来玩 | React+Lingo 实现一个超好玩的3D游戏:美女与龙珠这篇文章做入门,一边看一边做,然后看其参考的Lingo3D官方B站视频,看一遍,之后根据具体需求,在 Github 上 lingo3d organizations 的仓库集中选择一个对应场景的
example-
开头的仓库作为例子来学习,最后尝试自己完成一个项目,用到所学习的知识。
- 官网有点问题,因此以别卷了,快来玩 | React+Lingo 实现一个超好玩的3D游戏:美女与龙珠这篇文章做入门,一边看一边做,然后看其参考的Lingo3D官方B站视频,看一遍,之后根据具体需求,在 Github 上 lingo3d organizations 的仓库集中选择一个对应场景的
- 学习 lingo3d
20230227
- 经验
-
VSCode Bookmarks 用于代码间跳转
- 使用 Command+Shift+P 搜索 bookmarks 可以看到所有快捷键
- 使用 Option+Command+K 为 Toggle
- 使用 Option+Command+L/J 为跳转
-
scrollbar 滚动到底部
- 在 typescript 中,需使用 useRef 并注意类型
- 创建时需要设定初始值范型
const inputEl = useRef<HTMLInputElement>(null);
- 访问时需要在条件语句中
if (inputEl.current) { inputEl.current.focus(); // Works! }
- 创建时需要设定初始值范型
- 可在 componentDidMount/componentDidUpdate 或 useEffect 中调用
- 作用在父容器,滚动到最底部方法为:
$div.scrollTop = $div.scrollHeight
- 作用在子元素,可用 scrollIntoView:例子
- 在 typescript 中,需使用 useRef 并注意类型
-
在 useEffect 中访问之前的状态(How to compare oldValues and newValues on React Hooks useEffect?):使用 usePrevious
// modified from https://usehooks.com/usePrevious/ export default function usePrevious<T>(value: T) { // The ref object is a generic container whose current property is mutable ... // ... and can hold any value, similar to an instance property on a class const ref = useRef<T>() // Store current value in ref useEffect(() => { ref.current = value }, [value]) // Only re-run if value changes // Return previous value (happens before update in useEffect above) return ref.current }
原理:jsx的渲染比useEffect早,
ref.current
是 preState,useEffect 是最新 state -
Mutation:类似 useState,用来修改更改远程数据及相关缓存
mutate()
/mutate(key)
:将数据标记为已过期并触发重新获取(revalidate is deprecated)mutate(key, data, options)
:修改本地缓存数据,可选是否重新获取
-
20230226
-
经验
-
如果不想在 useEffect 第二个参数数组中加入某个状态,但是在 useEffect 中又需要改变与访问该状态,则可以将一个返回新状态的函数传递给 setState。
const [currentState, setCurrentState] = useState(defaultState) useEffect(() => { // prevState为上一次的状态(previous) setCurrentState(prevState) => { const newState = { ...prevState, ...appendState } return newState }) },[])
-
-
setInterval in React:我记得在 React 文档中看到过,但是找不到了。
useEffect(() => { const interval = setInterval(() => { console.log('This will be called every 2 seconds'); }, 2000); return () => clearInterval(interval); }, []);
-
判断数组中是否存在某个元素:indexOf、find、some、includes
-
GitLens 可以增强 VSCode 内置 Git 的功能。例如 commits 搜索,历史记录和显示的代码作者身份
20230225
- 经验
-
参考建议添加以下规则,osx下有可能会导致偷跑流量 添加如下规则
- DOMAIN-SUFFIX,googletraveladservices.com,DIRECT - DOMAIN,dl.google.com,DIRECT - DOMAIN,mtalk.google.com,DIRECT - DOMAIN,safebrowsing.googleapis.com,DIRECT
-
最小的屏幕是 280px,Galaxy Fold
-
- transitionEnd事件会在CSS transition动画结束后触发。
- 当存在多个属性过渡变化时,结束时会多次触发transitionend事件。
-
20230224
-
经验
-
NEXT_PUBLIC_DEFAULT_CHAINID 就是不同的区块链,其是固定的,97 是公司测试链,1 是以太坊
-
ETIMEDOUT:This is caused when your request response is not received in given time(by timeout request module option).
-
代理下 git 无法 clone,cfw 可以绕过系统代理,这样就 OK 了,但在 TUN 模式下这个是无效的。
bypass: - "github.com" # 下面字段可不删除 - 127.0.0.1 - ...
更新:这种方式不好,这样用 git 确实是可以 clone 了,但是浏览 github 网页却很慢(即没被代理)——我的需求是,可以 git clone,同时在网页也能快速访问 github,即 git clone 不被代理,github 被代理。 尝试配置文件预处理 一直没成功,烦,现在暂时只能在需要 git clone 的时候关闭代理了。 CFW 本身就是用的 clash Premium,因此可以参考clash更新订阅时保留自己的规则,自己写一个带
proxy-providers
的配置文件,然后添加以下 rule 即可- PROCESS-NAME,git,DIRECT
-
SVG Screenshot:可以将网页保存为 svg (选择框或视口内容)
-
-
任务
- 除了 UI 图,还有产品文档,还有测试网站。根据产品文档+
测试网站开发网站(我觉得应该用开发网站,即用最新的nofar分支,yarn dev 来体验,这是最新的,bug 也是最新的)走通流程,然后去细看 UI 设计+项目代码,快速熟悉。
- 除了 UI 图,还有产品文档,还有测试网站。根据产品文档+
-
观点
- APP 的价值在于其对用户是有用的,要有用,前提是能用,所以没有 bug ,或者说没有影响正常使用的 bug 至关重要。
- 没有 bug 比各种新奇或者强大的功能更重要,老话说:”不要没学会走就开始跑“;比现代化、炫酷的 UI 更重要,Linux 上有很对 ui 简陋的工具,但是却是许多人的生活的一部分,
- 我还是赞同 Polly 总结的:产品没 bug + 很多人知道
20230223
-
经验
-
Error: Run autofix to sort these imports!
:与simple-import-sort/imports
相关,就是 import 导入顺序问题,需要在 VSCode 中安装 ESLint 插件,并在相关页面用 Command+. 快速 fix。 -
commit 提交需要根据 https://github.com/conventional-changelog/commitlint/#what-is-commitlint 填写信息。例如
git commit -m "feat(官网页面) : 多语言修改"
-
可以看《i18n与lingui-js总结》了解国家化原理:1.0 为哈希表,键为原文,值为翻译的文本,通过键取值;2.0 为键为原文,值为函数,通过函数实现支持变量插入;3.0 是引入 babel 实现开发友好。
-
CSS实战–实现侧边栏滑进滑出:菜单的遮罩层是必要的,这样就可以通过点击遮罩层来隐藏侧边栏菜单了。滑进滑出原理就是利用定位移出元素到视口外。
.mask { position: fixed; left: 0; top: 0; width: 100%; height: 100%; }
-
MouseEeventHander 区别于 MouseEvent
const handleAsideClick = (e: React.MouseEvent<HTMLElement>) => { e.stopPropagation() }
-
next-http-proxy-middleware:用于在开发环境中测试 api 调用,解决跨域问题。在 next.config.js 中添加
async rewrites() { return [ { source: '/api/v1/:path*', destination: 'http://10.2.0.10:9188/api/v1/:path*', }, ] },
添加还需要重启服务。
-
【flex布局】解决view中两个元素一个居左一个居中:其实就是建立第三个元素,其与第一个元素一样宽度,但是没有内容。
<div className="flex justify-between items-center"> <Menu className="w-[50px]" /> <LogoIcon /> <div className="w-[50px]" /> </div>
-
-
观点:
-
关于Tailwind CSS是一切堆到class里的歪门邪道这种说法如何评价?
- Tailwind解决了”CSS 类命名“、“样式冲突“、“模块复用”等问题
- 如果说传统的编程箴言是 DRY(Do not repeat yourself),那 Tailwind CSS 就应该是 TRY (Try to repeat yourself)
-
Tailwind CSS (可能)是名过其实的:一大堆类名污染 HTML 结构中的每一个元素
-
-
问题:
- Is there a difference between storing a const value in a variable vs in state?: Runs
useState
and compares the value with the previous state on every render which is “much more expensive” than declaring a variable.
- Is there a difference between storing a const value in a variable vs in state?: Runs
20230222
-
经验:
-
Icon 都在
components/Icon/index.tsx
中export const AppleIcon = (props: React.ComponentProps<'svg'>) => { return (<svg {...props} ></svg>); }
这里需要删除原图标的
wedith
与height
属性,并用{...props}
代替。还需要将clip-path
等替换为小驼峰命名方式clipPath
。
- 先完成大致的 UI 与 页面逻辑,细节之后再慢慢调。先完成任务,再把任务完成得好。
- 遇到什么页面问题需要与 UI 沟通调整的,可以先记录在记事本中,之后再在 UI 能回应时处理。
- 移动 UI 图为 750px,其是 2 倍图,需要除以 2 才等于实际的值,包括元素的宽度与字体大小,反像素值都除以 2。
- 用 tailwind css 的
last:
与first:
选取元素。
-
-
问题:
-
How to hide scroll bar in react app with allowing scrolling
可以在全局 css 样式表
src/styles/index.css
中添加如下内容.noscrollbar { /* hide scrollbar for IE, Edge and Firefox */ -ms-overflow-style: none; scrollbar-width: none; } .noscrollbar::-webkit-scrollbar { display: none; }
-
Horizontal Scroll Image Pure CSS
.scroll-container{ overflow: auto; white-space: nowrap; } .gridscroll{ display:inline-block; } .gridscroll img { margin: 0 15px; }
-
20230221
-
任务
- 基于 dev 分支开发新 Freefrom 官网。
-
经验
- Figma 导出 3x 图片就很清晰了
- svg 可以作为 React 组件,不能作为 img 的 src。使用为
<SvgName className="w-full h-full text-white" />
- 随便点击某个颜色属性,就会弹出color palettes(调色板),其中有 color picker
-
前端工具:
- Lighthouse:可以在 DevTools 中使用 Lighthouse 来审核页面的可访问性并生成报表。
- Measuremate:页面元素距离检查工具
20230220
-
任务
- 翻译NTFTOPSHOW官网内容
- 新建项目,迁移 Freefrom 官网,只要静态页面,不要多语言,能删的都删掉
- 图片要优化,不能太大,考虑webp格式。
可以使用 https://convertio.co/ 转换要不断切换页面,限制最多转换两个- 可以使用 cwebp,
brew install webp
- 学习优化,如优化工具 https://www.pingdom.com/。
-
经验
-
使用多语言步骤
// 引入 import { t } from '@lingui/macro' import { useLingui } from '@lingui/react' // 使用,需提前在在 locale 添加相应的翻译 const { i18n } = useLingui() {i18n._(t`Translation`)}
-
简单的库的话,直接看官方文档;大型的如 React 就先看入门教程
-
使用的话优先使用 import 而非 requires,因为有些时候 requires 无报错,但import话就有报错。
-
因为要支持多语言,因此最好不要使用 uppercase 等 text-transfrom 属性
-
公司项目使用的 UI/CSS 库
- @fullpage/react-fullpage: A simple and easy to use library that creates fullscreen scrolling websites (also known as single page websites or onepage sites) and adds landscape sliders inside the sections of the site.
- react-responsive: Media queries in react for responsive design
- Swiper: The Most Modern Mobile Touch Slider。主要通过看 Swiper Demos 来学习使用
- Safari jumps two slides on mouse-wheel with trackpad or magic-mouse:我也遇到这个问题,无法解决
- How to change swiper-slide width?:设置
slidesPerView="auto"
后自适应容器宽度,否则width: 3.35544e7px;
- How to disable vertical mouse wheel swiper react:
forceToAxis: true,
- daisyUI components: Use Tailwind CSS but write fewer class names
- tailwindcss-border-gradient-radius: Border Gradients Plugin for Tailwind CSS based on background-origin and background-image
- @fontsource/dm-sans: The CSS and web font files to easily self-host the “DM Sans” font.
- react-virtualized: React components for efficiently rendering large lists and tabular data
- heroicons: Beautiful hand-crafted SVG icons(Font icon 可以直接用 svg 代替),图标库
- @headlessui/react: UI components for React
- tailwindcomponents
-
-
featrues 特色的地方:
- 内容即NFT - 发布内容自动生成NFT,让内容上链,确定权利。
- 完全去中心化 - 通过集成开放性协议nostr,没有任何平台可以禁止或审查你。你可以控制你的数据和言论。
- 发帖赚钱 - 通过创造高质量内容获得粉丝的打赏奖励,同时获得平台激励。
- DAO社区增强 - 通过团结内容及粉丝来创建自己的去中心化的DAO社区
- 数字ID - 通过建立DID,创建一个Web3的独特身份,组织自己链上资产建立自己的Profile。
- 加密私信 - 端到端的加密的私人信息,让大公司远离你的DMs。
-
Mac 快捷键
- 切换vscode页面上面的标签 Option+Command+左右方向键
- Shift+Command+3 拍摄截屏幕
- Shift+Control+Command+3键会在剪贴板里获取整个屏幕的截图
- Shift+Command+4 捕捉的屏幕区域,再按下空格键可捕捉窗口
- Shift+Control+Command+4键则能使你通过拖动鼠标来截取部分屏幕,并复制图片到剪贴板,再按下空格键可捕捉窗口
- 退出全屏 Ctrl+Command+F 或 Fn+F
- 刷新浏览器:Command+R,强制刷新:Command+Shift+R
- Option + 方向键左,将光标移动到前一个单词
- Option + 方向键右,将光标移动到后一个单词
-
问题
-
Property ‘credits’ is not recognized as an available option
<ReactFullpage licenseKey='REDACTED' scrollingSpeed={500} credits={{ enabled: false }}
-
20230218
-
公司 next.js 项目流程和目录含义
- 首先看
src/layout
:布局类 - 其次看
src/pages
:页面,pages 页面对应着路由,src/pages/home/
路由就是localhost:3000/home/
,开发的时候也可以根据浏览器 URL 找对应的页面。 - 然后看
src/features
:每个 pages 对应的组件 - tailwind.config.js 有些样式写在这里
src/styles/index.css
为全局样式表src/src/styles/variables.css
定义全局字体
- Typography 组件用来排版的,主要是字体相关的属性
- 首先看
-
任务:
-
https://pancakeswap.finance/ 首页的图片,后续我们换成这样会动的,用css的来实现,你研究下他们这个。
-
首先通过 devtool 的 animation 找到对应的元素为 path.eye。
-
由于页面这个部分不断地跳(好像是不断的重新创建),因此用 command + s 保存离线网页。之后看到
.cSXBDs .eye { animation-delay: 20ms; }
实现动画的底层技术就是CSS或JS,这里可以看到用了 css 控制动画时长
-
通过 devtool 的 network 获取 css 样式表,用 css fromatter 格式化,找到 @keyframe,但好像都无关动画定义。
-
参考 SVG 动画 与 SVG 闪烁动画(Blink) 我认为使用 JS 实现的动画可能性更大。而且仔细看 devtool 的 animation 中的动画时长为 280 ms,远大于 animation-delay 的 20ms,而这个类主要用于 JS 控制元素。
-
-
-
技巧:
-
用
flex flex-1 justify-center align-center gap-[74px]
的 gap 来控制两个子元素间距,而非margin
-
尽量不要用
absolute
之类的定位写 ui,尽量让元素在正常文档流之内。 -
React.jsでlocation.hrefを用いた外部URLへの遷移
<div onClick={() => { window.location.href = "https://google.com"; }}>Googleへ</div>
-
<form action="mailto:youraddr@domain.tld" method="GET"> <input name="subject" type="text" /> <textarea name="body"></textarea> <input type="submit" value="Send" /> </form>
-
打开浏览器,
f12
进入开发者模式,使用快捷键Ctrl+shift+p
呼出命令面板,输入full
来过滤命令,找到一个 名叫Screenshot capture full size screenshot
的那一项,点击后稍等一会就会生成一整图片保存到本地。 -
使用yarn英文官方网站corepack 安装yarn方法在m1上老是失败,报错
must be built because it never has been before or the last one failed
,如果用普通的 npm -g 则没这个问题。
-
20230217
-
数支用到的工具:
- team task manager:asana
- 沟通工具:前端 钉钉,后端 teams(一星期两会)
- API:postman
-
现公司用
- 沟通工具 Lark(一天一会)
- team task manager:Trello
-
感悟:
- 我发现如果只是编写简单的 UI 的话,可以直接开个项目,当 UI 编写完毕之后再迁移到原来的项目。因为原项目东西太多,加载运行都非常慢,非常浪费时间,不如直接在简单环境中达到目标,然后再在复杂环境中。
-
问题:
-
冒号垂直对齐:可以使用 table
-
backgroundImage: 'linear-gradient(rgba(0, 0, 0, 0.4),rgba(0, 0, 0, 0.4)) , url(/images/home/bg.webp)'
-
React onHover Event Handling (with Examples)
<button onMouseEnter={() => setIsShown(true)} onMouseLeave={() => setIsShown(false)}> Hover over me! </button>
-
-
MacOS pkg(例如 node.js)清理工具 UninstallPKG
20230216
-
如何学习 Tailwind CSS?
- 针对特定框架安装 Tailwindcss
- 首先看Tailwind CSS中文文档核心概念部分
- 再在 Tailwind 英文 直接搜索需要使用的 CSS 属性
-
问题
-
Background image in tailwindcss using dynamic url (React.js)
style={{backgroundImage: `url(${fetchedImgSrc})`}}
-
How to work with background images in Tailwind CSS
<div class=" bg-no-repeat bg-cover bg-center bg-[url('../public/images/hero-mobile.jpg')] md:bg-none xl:bg-[url('../public/images/hero-desktop.jpg')] "></div>
-
// 定义,例如起一个文件名为globalData.js global.全局变量名称= { aaa:'111', bbb:[]', }; // 使用 // 方式一 import 全局变量名称 from './globalData'; // 方式二 <div>名称:{global.全局变量名称.aaa}</div>
-
Factory resetting your MacBook
- Click the Apple logo on the top left corner of your screen, and select System Preferences from the dropdown menu.
- Click the System Preferences option which appears next to the Apple logo in the menu bar and pick Erase All Contents and Settings in the dropdown menu*.*
-
20230215
- 经验:
- next/image,包装 NextImage
- next/config
- tsconfig/paths 设置别名后,import 报
Module not found: Error: Can't resolve
,如果不设置别名就无此问题,或者用tsconfig-paths - VSCode 噴 Unknown at rule @tailwind 解決方式
TailwindCSS 有使用到一些 TailwindCSS 自己自定義的 CSS 語法,所以在許多編譯器在會無法辨別而導致出現錯誤或警告,而我們本身使用 TailwindCSS 都會搭配 PostCSS,所以就會有一個 postcss.config.js 設定檔,這時候我們只需要替自己的 VSCode 安裝 PostCSS Language Support 套件就可以解決
Unknown at rule @tailwind
的問題囉。 - 在 Create React App 中修改 Webpack 設定,以調整 Webpack Alias 為例
20230214
-
问题:在无法用 export 导出 i18n 的路由
- 方法:
- 用现成解决方案
- 用传统打包
- 不用 i18n
- 解决步骤:
- 了解逻辑,大致了解 next.js,linugui
- 选择破坏或者更改最少的
- 或许可以使用 exportMapPath
- 链接:
- 方法:
-
技能:
- VSCode regex find & replace submatch math?
Given a regular expression of
(foobar)
you can reference the first group using$1
and so on if you have more groups in the replace input field. - Match linebreaks - \n or \r\n?
(\r\n|\r|\n)
is more correct.(这里正则匹配是一行为单位的,即使可以匹配空白符,也无法匹配多行)
- VSCode regex find & replace submatch math?
Given a regular expression of
-
其他:
-
Error: Image Optimization using Next.js default loader is not compatible with
next export
$ yarn add akamai $ vim next.config.js module.exports = { images: { loader: 'akamai', path: '', }, }
-
How to run Next Js application build (out) directory?
{ "private": true, "scripts": { "dev": "next", "build": "next build", "preexport": "npm run build", "export": "next export", "prestart": "npm run export", + "start": "serve out", "lint": "next lint" },
-
-
Meta Mask: table sister month eight offer dentist hair trophy field process define lady