V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  epiloguess  ›  全部回复第 4 页 / 共 6 页
回复总数  106
1  2  3  4  5  6  
从客户端的角度上来说,如果服务端配置了 no-cache,对于客户端的非首次请求,headers 里应该有 if-none-match.
如果没有的话,有两种可能
1.服务端一开始没有配置 no-cache,客户端缓存了内容,服务器此时配置 no-cache 是无效的,但客户端不应该收到 no-cache 的响应头
2.客户端没有发送`if-none-match`的能力,导致虽然配置了 no-cache,但是只能用`last-modified`作为 fallback,这种情况虽然少见,但是确实可能存在

OP 可能需要清空客户端的缓存,再做几组测试
246 天前
回复了 ccc00 创建的主题 程序员 求助,不会写前端代码的困惑
可以考虑做一些自己的项目,做公司的项目你可能没办法全身心投入,或者工作本身也不允许你选择.

即使是做博客,也要考虑到字体,markdown 的解析,目录的递归渲染,性能优化,排版,进入退出动画,客户端导航,脚本的位置,托管,缓存,网站统计,评论.

不过这些可能不是你困扰的

多写笔记,不一定要公开.
尽量从原理上搞懂一个事情,以及有哪些替代方案,替代方案的兼容性如何,哪种是最佳实践,都有什么优缺点.

1.加群问人不如问 ChatGPT,很多都是水群的,在群里问效率太低了,说实话,群就是个聊天的,不会真的有技术群吧,群这种东西就不适合讨论问题,讨论问题最起码要在论坛或者社区里
2.看视频的效率也很低,无关信息太多
3.看文章挺好的
4.google 一般搜关键词,不要尝试把自己的问题翻译成英文去搜索,效率很低,你的搜索内容加了很多"噪音"
5.看官方文档最好的(前提是文档本身不错,而不是 api 大全),掘金很多文章还不如 chatgpt,一般来说,官方文档>技术问答社区(对于已存在的问题)>=ChatGPT>英文博客>中文博客>掘金文章>技术社区提问>问同事>问群友>=看视频
6.同事很忙,你也要理解
7.掌握好思路,做什么都一样
@seres 掘金的时间流做的一塌糊涂,推送的内容很多都是几年前的,本来 JS 发展就快,作为一个前端为主的技术社区,实在不应该.
我发的帖子可以做到 0 回复 0 点赞 0 收藏
外面套个娃?
254 天前
回复了 Cola98 创建的主题 程序员 nextjs 正确使用方式
@horizon nextjs 写后台是没问题的,现在客户端导航 CSR , 非常完善, 纯 SPA 的优势在哪里我不知道...MPA 一样可以做到预读取,无缝渲染,路由权限也可以用 并行路由/条件路由来实现...
ssr 对我来说挺好用啊,整体将 react 的组件树扁平化
服务器渲染的内容可以在 react.js 下载之前就显示出来,server action 可以在 js 加载之前就能向服务器提交操作
服务端组件和客户端组件的搭配,可以让服务器只将必要的序列化的数据传给客户端组件,昂贵的计算逻辑也可以交给客户端组件来做
我觉得 nextjs+react 提供了一个清晰明了的网络边界,这是我最喜欢的部分
它指示了什么内容应该在服务器上渲染,什么内容应该在客户端上渲染,和 spa 的目标是不一样的
nextjs 更适合被称为同构渲染框架而不是 ssr,它是包括 csr+ssr 的
我觉得是一种合理的进化
当然这些概念十几年前就有了,如何将它和现代前端框架融合才是工作的重点.技术是螺旋上升的,如果从俯视的角度来看,确实是个圈,但不能否认这个圈越来越大了
有一个叫做 tmm 的 支持自动刮削 不过也没有那么自动 不知道你试过没有
259 天前
回复了 vinciarts 创建的主题 程序员 国内用 Svelte + Supabase + Vercel 的全栈多吗
@willx12123 NPM 的数据经过处理了,为了和 CNPM 做比较,实际上,NPM 上工作日的时候一天下载量大概在 17W 左右.大概是 react 的 1/24,vue 的 1/5. 用的人还是不少的. 但是国内用的就比较少了,大概是 vue 的 1/32,而且没有形成稳定的工作日-休息日间隔,说明很多都是业务爱好,没有投入生产
259 天前
回复了 vinciarts 创建的主题 程序员 国内用 Svelte + Supabase + Vercel 的全栈多吗
svelte 不能说很多,只能说...
https://npmstats.com/package/svelte
260 天前
回复了 coffeygao 创建的主题 健康 在不剧烈运动的情况下我怎么能快速减肥?
减肥不用剧烈运动,反而是要选择你能坚持最久的运动,如果你把每天的热量缺口目标设置在 500 大卡,在不控制饮食的情况下,你只需要每天走 10000 步就能达成目标,大概需要一个半小时,如果控制饮食就更快了.每天 500 大卡,一个月大概可以瘦 2-4 公斤
文科学这些东西是给你赋能,就赋能来说,py js 很适合,不是让你拿爱好挑战别人的饭碗 就算是前端没个全身心半年也学不明白达不到初级开发的水平
我 12450H,用 win11,任务栏经常冻结
express 挺好的,就是万年不更新,也不是自带 battery ,nest 其实用的人不多,只有 express 的 1/10 ,选技术也要考虑一下以后招人难不难
https://npmstats.com/tags/node.js%20framework
syncthing
个人首页似乎有点卡
264 天前
回复了 weijancc 创建的主题 Vue.js 升级 Vue3, 开发体验非常糟糕
下载量对比可以来我这看 https://npmstats.com/package/vue
最近给 nextjs 提 pr 的时候,就不小心把别人的 commit 加进去了还 push 了,给 pr 加了一对额外的标签还 request 了不需要的人,尴尬的要死,要是早点看到帖子就好了
更正:
倒数第二个水平线
---
那我们思考一下访问会访问什么

会调用 patch 过的 fetch,传入的 revalidate 是 0,走到刚才那个逻辑,如果没有提前设置 isUnstableNoStore 为 true,就会 else{
cache reason = 'auto cache'
}
--

传入的是 revalidate undefined ,不是 0 写错了

---

关于 debug npm link 应该也可以 不过我没怎么用过

毕竟我不是天天 debug..............

你也可以不用这么麻烦,毕竟你都用 canary,直接修改本地某个版本的包就行,反正注意一下别的项目不再用了就可以,比如只修改.50

---
翻了一下最开始的评论,还行,对的比错的多,笑死.

计划整理一下所有回答的内容,可以给后来者一点明确的参考,毕竟我们这帖子太乱了.

不过可能还要几天,毕竟总结的越早,错误的地方也就越多.
@lazyczx 这个文件下不了呀

关于 debug,因为我一直用的都是 pnpm,node_module 里面都是 pnpm 处理的硬链接
如果是 npm,每个项目都不共用吧,除非装 global

不管怎么说,理论上,直接修改本地文件应该就可行吧,比如说你 import 了 noStore 这个函数,这个函数在本地就是以 js 格式存在的,是源码处理过后的,在源码中是以 ts 的格式存在的

> 我做的时候,用的是 npm link ,下了 nextjs 仓库然后 link 替换掉了 dashboard 项目里的 next ,但是运行命令的时候提示 next 找不到,于是我全局安装了 next ,但是运行各种命令都报错,报什么 m...interface 什么找不到,我去 next 里 npm i 了也没用(虽然好像默认是不需要自己跑过去 npm i 的吧?)。

所以我不太懂你这一步 ,npm link 是干嘛的...

如果想快速 debug,最方便的应该就是直接修改你当前项目里面 node_module 目录下的 next 包里面的函数值,这种方式一般也叫 heck

如果想从源码 debug,需要 git clone next 的仓库,一边修改一边测试,修改完之后 build,再替换你本地用的 next 包.

这样就比较麻烦了,特别是如果你不熟悉项目的情况下..

---
最后补充一下我昨天的内容
下面是我打的一部分断点,我查了一下 patch-fetch 的 commit,勉强搞明白了到底是怎么回事.
这是没有 noStore 的时候的断点
我们都知道 nextjs 扩展了 fetch,具体实现,
next build 的时候,首先就会对每个路由,patch 原生的 fetch,它并不在乎路由里面有没有 fetch 的调用,这样就比较麻烦了
实现的效果就是,以后在渲染这些路由的时候,在调用 fetch 的时候,调用的就是 patch 过的 fetch,而不是原生的 fetch


call patchFetch from entry-base
Function patchFetch at patch-fetch.js being called [Function: g]
urlPathname from patchFetch Begining / // 所以断点日志的前三部分,就是不同的 urlPathname
revalidate from patchFetch Begining undefined
isUnstableNoStore from patchFetchBegin false

call patchFetch from entry-base
Function patchFetch at patch-fetch.js being called [Function: g]
urlPathname from patchFetch Begining /_not-found
revalidate from patchFetch Begining undefined
isUnstableNoStore from patchFetchBegin false


call patchFetch from entry-base
Function patchFetch at patch-fetch.js being called [Function: g]
urlPathname from patchFetch Begining /dashboard
revalidate from patchFetch Begining undefined
isUnstableNoStore from patchFetchBegin false



// 这是 fetch 函数在 next 中的定义
// fetch(`https://...`, { next: { revalidate: false | 0 | number } })
// 完成上面的工作之后,next/webpack,开始渲染页面/页面中的组件

rendering...RevenueChart component
Fetching revenue data... //已经在 try...catch 里面了,下一步就是获取 data

using patchFetch fetch //调用 patch 过的 patch
// 这时候我们能看到 input 和 init,分别是 fetch 的 url 和 option,option 也就是第二个参数
// 这里也就是说,@vercel/postgre 中的 sql`` 是通过 fetch 调用的
// 值得注意的是,如果没有配置 option 里面的 option.next.revalidate ,这个值默认是 undefined,sql``是没有配置的
input https://ep-blue-star-a4zoprb8-pooler.us-east-1.aws.neon.tech/sql
init {
method: 'POST',
body: '{"query":"SELECT * FROM revenue","params":[]}',
headers: {
'Neon-Connection-String': 'xxxx',
'Neon-Raw-Text-Output': 'true',
'Neon-Array-Mode': 'true'
}
}

isRequestInput false
curRevalidate undefined
fetchCacheMode undefined
isUsingNoStore false
revalidate undefined
isUsingNoStore false
cacheReason
revalidate false
cacheReason auto cache



rendering...RevenueChart component
Fetching revenue data...
input https://ep-blue-star-a4zoprb8-pooler.us-east-1.aws.neon.tech/sql
init {
method: 'POST',
body: '{"query":"SELECT * FROM revenue","params":[]}',
headers: {
'Neon-Connection-String': 'xxxx',
'Neon-Raw-Text-Output': 'true',
'Neon-Array-Mode': 'true'
}
}
using patchFetch fetch
isRequestInput false
curRevalidate undefined
fetchCacheMode undefined
isUsingNoStore false
revalidate undefined
isUsingNoStore false
cacheReason
revalidate false
cacheReason auto cache


Fetched revenue data...
Fetched revenue data...


---

所以错误是怎么产生的?
你会发现,RevenueChart 被渲染了两次,假设我们现在有另一个组件,其中调用了 noStore()
一开始,为路线 patchFetch
然后渲染组件 RevenueChart,调用 patch 过的 fetch,没有问题
然后渲染组件 with noStore(),noStore()函数会调用 markCurrentScopeAsDynamic,也就是说,会标记当前 scope 作为动态渲染,因此,有 noStore 的组件,在 build 过程中,不会调用后面的 try..catch 块的里面的 await sql``


---
这里补充一下 scope 的知识
关于 https://nextjs.org/docs/messages/ppr-caught-error
里面提到过
> Alternatively, insert unstable_noStore() before the try/catch.

try..catch 就是一个独立的 scope,同理,unstable_cache 也一样
unstable_noStore 不期望在这些 scope 中被调用,否则会错误
因为 markCurrentScopeAsDynamic 期望 mark 到一个 suspense 边界,如果 unstable_noStore 在页面顶层/或者一个没有被 suspense 包裹的组件内,(本质上一样)被调用,外面没有 suspense,那会发生什么?
答案很简单,整个页面都会被 suspense,这一点参考
> https://nextjs.org/docs/app/api-reference/file-conventions/loading

整个世界就是一个大大的佩拉(误)
整个页面就是一个大大的 suspense

--
先回顾一下上上部分最后一行.

但是,noStore 函数调用的时候,会 store.isUnstableNoStore = true;这个 store 是路线共用的
所以在第二次渲染 RevenueChart 的时候,isUnstableNoStore 会变为 true,其中我记得有个简单的逻辑
if(revalidate === undefined){
if(isUsingNoStore/重命名了){
{revalidate = 0}
cache reason = 'noStore call'
}else{
cache reason = 'auto cache'
}

正是这一步,导致我们以同样的操作第二次渲染 RevenueChart 的时候,revalite 为 undefined 变成了 0
导致后面没有调用 trackFetchMetric 而是 trackDynamicFetch 并最终把 revalite0 送到了 postpone 手里,产生了报错

---

所以我上次给的临时解放方案,在 markCurrentScopeAsDynamic 之后 isUnstableNoStore = false
才会奏效

但是,其实这并没有解决根本问题

---
那么,为什么会这样?为什么会有这个逻辑
if(isUsingNoStore/重命名了){
{revalidate = 0}
cache reason = 'noStore call'
}else{
cache reason = 'auto cache'
}

这个逻辑是在这时候被添加的 https://github.com/vercel/next.js/pull/60630

他的解释

```
When you're using noStore() with fetch it's currently saying "auto cache" in cache missed reason, adding "noStore call" here to show it's caused by using with unstable_noStore
当您使用 noStore() with fetch 时,它当前在缓存错过原因中显示“自动缓存”,在此处添加“noStore 调用”以表明它是由使用 with unstable_noStore 引起的

GET /no-store 200 in 4069ms
│ GET https://next-data-api-endpoint.vercel.app/api/random?another-no-cache 200 in 257ms (cache: SKIP)
│ │ Cache missed reason: (noStore call)

```

如果不添加这个逻辑,不在 noStore 里设置 isUnstableNoStore 为 true
会发生什么?
直接走到了 else 的最后一步,revalidate 为 undefined 的 ,cache reason 设置为 auto cache,这适用于
fetch 的时候不写 revalidate 的函数,组件会被默认预渲染
而 noStore 这个不会被预渲染的,也用的是相同的 cache Reason,显然不符合不对的,所以这个 commit 就这么被提交了

---

总结和补充一些内容

1.每个路线上的 fetch 都会被 patch,组件,会被渲染两次,关于这个渲染两次,官方 doc 里面也有提过,你就理解成在服务器上模拟客户端的操作?
2.revalidate 为 undefined 的,没有 noStore 的,会正常渲染
3.有 noStore 的组件,会被标记为动态渲染,从而不调用组件里的 fetch?那什么时候调用?当然是访问页面的时候,build,start 以后访问页面就能看见

那我们思考一下访问会访问什么

会调用 patch 过的 fetch,传入的 revalidate 是 0,走到刚才那个逻辑,如果没有提前设置 isUnstableNoStore 为 true,就会 else{
cache reason = 'auto cache'
}
发现了吗,不正确的 cache reason

---

加上的这一步会影响什么?


if(isUsingNoStore){
revalidate = 0
cache reason = 'noStore call'
}

使用了 noStore 的组件是舒服了
但是没使用 noStore 组件却被 revalidate = 0 给坑了,错误就是这么来的

---
所以我昨天的解决方法是解决了我自己的问题,但没解决那个 commit 想解决的问题

可以说,干脆就把 noStore 里面赋值那一行删掉就可以解决问题

不过我的问题比较关键好吧,他的问题不过是调试才会发现的问题,根本不影响使用...


---





@lazyczx
1  2  3  4  5  6  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2820 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 33ms · UTC 13:52 · PVG 21:52 · LAX 05:52 · JFK 08:52
Developed with CodeLauncher
♥ Do have faith in what you're doing.