跳到主要内容

代码片段关键字替换

· 阅读需 1 分钟
1adybug
子虚伊人

有的时候我们需要在代码片段同时进行两种替换,比如下方,我们要将 api 移除,并将其转换为驼峰式命名法:

烤肉串式命名法 (Kebab-case)驼峰式命名法 (CamelCase)
api.my-filemyFile
api.another-example-fileanotherExampleFile
api.yet-another-oneyetAnotherOne

这种替换的难点在我们无法确定 - 的数量为多少

这时候可以使用以下代码实现:

const prefix = "api\\\\.([^-]+)"

const unit = "-([^-])([^-]*)"

const max = 6

const regExp = Array(max)
.fill(prefix)
.map((item, index) => ["^", item, ...Array(index).fill(unit), "$"].join(""))
.join("|")

const replacer = Array(max)
.fill(0)
.reduce(
(acc, item, index) => [
...acc,
[
(acc.at(-1)?.at(-1) ?? 0) + 1,
...Array(index * 2)
.fill(0)
.map((item2, index2) => (acc.at(-1)?.at(-1) ?? 0) + 1 + index2 + 1),
],
],
[],
)
.map(item => item.map((item2, index2) => (index2 % 2 === 0 ? `$${item2}` : `$\{${item2}:/upcase}`)).join(""))
.join("")

const body = `\${TM_FILENAME_BASE/${regExp}/${replacer}/}`

console.log(body)

想要最大支持多少个 - ,只需要修改 max 的值即可。

重新学习 React Router

· 阅读需 2 分钟
1adybug
子虚伊人

前言

React Router 在推出 Remix 后变成了一个全栈框架,在 V7 版本之后,更是将 React RouterRemix 合并在一起,提供了一个全栈的解决方案。

常见问题

  1. loaderclientLoader 有什么区别?

    • 执行环境

      • loader: 在服务器端执行
      • clientLoader: 在客户端(浏览器)执行
    • 运行时机

      • loader: 在页面初始加载和每次导航时在服务器上运行
      • clientLoader: 在客户端导航时运行,首次页面加载时不执行
    • 数据获取能力

      • loader: 可以访问服务器资源(数据库、文件系统、内部API等)
      • clientLoader: 只能访问浏览器可用的资源(如公共API、localStorage等)
    • 安全性

      • loader: 可以包含敏感逻辑和凭证,因为代码不会发送到客户端
      • clientLoader: 所有代码会发送到浏览器,不应包含敏感信息
    • 用途场景

      • loader: 适用于需要服务器权限或敏感数据的操作
      • clientLoader: 适用于提升客户端导航体验,减轻服务器负担的场景

    这两个函数通常可以配合使用:loader 用于初始数据加载和服务器相关操作,clientLoader 用于优化后续的客户端导航体验。

    loader 将在你首次打开页面就是这个路由时执行,clientLoader 将在你由其他路由导航到这个路由时执行。clientLoader 在首次页面加载时不会执行。在 clientLoader 中,你可以使用 serverLoader 调用 loader

    import type { Route } from "./+types/product"

    // route("products/:pid", "./product.tsx");
    import { fakeDb } from "../db"

    export async function loader({ params }: Route.LoaderArgs) {
    return fakeDb.getProduct(params.pid)
    }

    export async function clientLoader({ serverLoader, params }: Route.ClientLoaderArgs) {
    const res = await fetch(`/api/products/${params.pid}`)
    const serverData = await serverLoader()
    return { ...serverData, ...res.json() }
    }

    export default function Product({ loaderData }: Route.ComponentProps) {
    const { name, description } = loaderData

    return (
    <div>
    <h1>{name}</h1>
    <p>{description}</p>
    </div>
    )
    }

日期格式 Bug

· 阅读需 2 分钟
1adybug
子虚伊人

最新发现一个 JavaScriptDate 对象的特性(bug),记录一下,以下是 Claude 的回答:

在JavaScript中,new Date("2025-01-01")new Date("2025/01/01") 的结果确实会不同,这是因为JavaScript解析这两种格式的日期字符串的方式不同:

  1. new Date("2025-01-01") - 这是ISO 8601格式,被解析为UTC时间(协调世界时)。

  2. new Date("2025/01/01") - 这是非标准格式,被解析为本地时间(你电脑所在的时区)。

所以,如果你在不同时区运行相同的代码,使用斜杠格式(2025/01/01)会得到根据你的本地时区调整后的日期时间,而使用连字符格式(2025-01-01)会得到相同的UTC时间,然后显示时会根据本地时区进行转换。

举个例子,如果你在东八区(北京时间):

  • new Date("2025-01-01") 会被解析为UTC的2025年1月1日0时0分0秒,但显示时会转换为东八区的2025年1月1日8时0分0秒
  • new Date("2025/01/01") 会直接被解析为东八区的2025年1月1日0时0分0秒

这种差异可能会导致日期计算出现错误,因此在处理日期时要特别注意格式和时区问题。

React Strict Mode

· 阅读需 3 分钟
1adybug
子虚伊人

以下是 React 官网的解释:

`React` 中,`Strict Mode` 是一个用于开发环境的工具,用于帮助开发者发现潜在的问题。它会在开发环境中执行额外的检查,并提供警告信息。

严格模式启用了以下仅在开发环境下有效的行为:

- 组件将 额外重新渲染一次 以查找由于非纯渲染而引起的错误。
- 组件将 额外重新运行一次 `Effect` 以查找由于缺少 `Effect` 清理而引起的错误。
- 组件将 额外重新运行一次 `refs` 回调 以查找由于缺少 `ref` 清理函数而引起的错误。
- 组件将被 检查是否使用了已弃用的 `API`

以下是测试代码:

import { FC, useEffect, useMemo, useRef, useState } from "react"

let stateCache: any
let refCache: any
let memoCache: any
let stateCache2: any
let refCache2: any
let memoCache2: any

const App: FC = () => {
const [state, setState] = useState(() => (console.log("calculate state"), {}))
const ref = useRef({})
const memo = useMemo(() => (console.log("calculate memo"), {}), [])

if (stateCache) console.log(state === stateCache)
else stateCache = state

if (refCache) console.log(ref === refCache, ref.current === refCache.current)
else refCache = ref

if (memoCache) console.log(memo === memoCache)
else memoCache = memo

useEffect(() => {
if (stateCache2) console.log(state === stateCache2, stateCache === stateCache2)
else stateCache2 = state

if (refCache2) console.log(ref === refCache2, ref.current === refCache2.current)
else refCache2 = ref

if (memoCache2) console.log(memo === memoCache2, memoCache === memoCache2)
else memoCache2 = memo
}, [])

return <div></div>
}

export default App

在 React 18 中,以下是打印结果:

calculate state
calculate memo
calculate state
calculate memo
false
false false
false
true false
true true false false
true false

可以看出,组件额外渲染了一次,staterefmemo 都额外重新获取了一次值,并且返回的第二次获取的新值。

Effect 额外运行了一次,但是获取到的 staterefmemo 的值是相同的,并且是第二次获取的新值

在 React 19 中,以下是打印结果:

calculate state
calculate state
calculate memo
calculate memo
true
true true
true
true true
true true true true
true true

可以看出,组件额外渲染了一次,staterefmemo 都额外重新获取了一次值,然而返回的却是第一次获取的旧值。

Effect 额外运行了一次,获取到的 staterefmemo 的值是依然是相同的,并且是第一次获取的旧值,

以下是 React 官网的解释:

### StrictMode changes

React 19 includes several fixes and improvements to Strict Mode.

When double rendering in Strict Mode in development, useMemo and useCallback will reuse the memoized results from the first render during the second render. Components that are already Strict Mode compatible should not notice a difference in behavior.

As with all Strict Mode behaviors, these features are designed to proactively surface bugs in your components during development so you can fix them before they are shipped to production. For example, during development, Strict Mode will double-invoke ref callback functions on initial mount, to simulate what happens when a mounted component is replaced by a Suspense fallback.
区别React 18React 19
组件额外渲染一次
staterefmemo 额外重新获取一次值
render 阶段获取到的 staterefmemo旧值/新值旧值/旧值
Effect 在首次渲染时额外运行一次并且立即执行卸载
Effect 阶段获取到的 staterefmemo新值/新值旧值/旧值

使用 wsl 版的 docker desktop

· 阅读需 1 分钟
1adybug
子虚伊人

如果在内网安装 docker desktop,那么 docker desktop 会强制要求升级 wsl,否则无法使用。只需要修改 docker desktop 的配置文件:

// C:\Users\用户名\AppData\Roaming\Docker\setting-store.json
{
// 添加这一行
"WslUpdateRequired": false
}

使用 nginx 作为 ai 应用反向代理

· 阅读需 2 分钟
1adybug
子虚伊人

很多 ai 应用都是使用流式传输,需要对 nginx 进行配置,才能正确的反向代理。

events {
worker_connections 1024;
}

http {

server {
listen 11435;
server_name 0.0.0.0;

location / {
proxy_pass http://host.docker.internal:11434;

# 关闭缓存,确保流式输出
proxy_buffering off;
proxy_cache off;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;

# 增加超时时间,防止长响应被中断
proxy_read_timeout 1800s;
proxy_connect_timeout 60s;
proxy_send_timeout 1800s;

# 首先清除上游服务器可能发送的 CORS 头部
proxy_hide_header 'Access-Control-Allow-Origin';
proxy_hide_header 'Access-Control-Allow-Methods';
proxy_hide_header 'Access-Control-Allow-Headers';
proxy_hide_header 'Access-Control-Expose-Headers';
proxy_hide_header 'Access-Control-Max-Age';

# 移除 CORS 限制
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

# 处理 OPTIONS 请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}

# 代理设置
proxy_set_header Host $host;
# 传递真实 IP,如果后端服务屏蔽了客户端 IP,可以注释掉下面两行
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}

windows 版本的 docker desktop

· 阅读需 1 分钟
1adybug
子虚伊人

之前为了便于 wsl 中的系统直接使用 windows 的代理,我将 wsl 的网络模式都设置为了 mirrored,这样就导致了无法使用 ip 访问 docker 中的应用,所以必须将网络模式设置为 NAT,这样就可以通过 ip 访问 docker 中的应用了。

[wsl2]
# 注释掉或者改为 NAT
# networkingMode=mirrored
networkingMode=NAT

关闭 wsl,然后重启 docker desktop,这样就可以通过 ip 访问 docker 中的应用了。

wsl --shutdown

contentRect、contentBoxSize 和 borderBoxSize 之间的区别

· 阅读需 1 分钟
1adybug
子虚伊人

这些尺寸属性之间的主要区别如下:

  1. contentRect:

    • 表示元素的内容区域的尺寸
    • 不包含内边距(padding)和边框(border)
    • 是最内层的测量值
  2. contentBoxSize:

    • 与contentRect测量相同的区域
    • 同样只包含内容区域的尺寸
    • 主要区别在于返回值的格式不同:contentBoxSize返回一个包含width和height的对象
  3. borderBoxSize:

    • 测量元素的完整尺寸
    • 包含内容区域、内边距和边框
    • 是最外层的测量值
    • 计算公式:内容区域 + padding * 2 + border * 2
    • inlineSize:沿着文本方向的尺寸,一般为 width
    • blockSize:垂直于文本方向的尺寸,一般为 height

这些属性在实际应用中的使用场景:

  • contentRect/contentBoxSize:当你需要知道元素实际内容区域大小时使用,比如计算文本区域
  • borderBoxSize:当你需要知道元素在页面上占据的总空间时使用,比如布局计算

如果你对某个具体的使用场景有疑问,或者想要了解更多细节,请随时告诉我

同步 Cursor 设置

· 阅读需 1 分钟
1adybug
子虚伊人

使用办法

  1. 覆盖保存

    • 下载 settings.jsonC:\Users\用户名\AppData\Roaming\Cursor\User 目录下
    • 下载 global.code-snippetsC:\Users\用户名\AppData\Roaming\Cursor\User\snippets 目录下
  2. 使用 zixulu 进行同步

    npx zixulu sc

设置

代码片段