Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

2.0 rc: subFetch swaps the global Promise during hydration; user-cached import() becomes a never-settling MockPromise

Đang mở
#4,332 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
45/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
javascript, typescript, vite
Lĩnh vực
backend, frontend

Hướng nghiên cứu

Read dist/solid.js:422-429 to trace how subFetch swaps and restores the global Promise during hydration, and compare this with the fix for #4013 in #4019. Reproduce the cached import() case using the supplied example and verify whether a promise created during hydration remains pending after another component calls the cache. Done means the cached load resolves after hydration without breaking the existing lazy() and lazyModule() behavior.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Versions: solid-js 2.0.0-rc.18 (also present in 2.0.0-rc.19: dist/solid.js:429), @solidjs/web 2.0.0-rc.18, Vite 8.3.5.

Related: #4013, fixed by #4019 for lazy()/lazyModule(). This is the same root cause reaching user code that #4019 doesn't cover.

What happens

While hydration traces an adopted async computation, subFetch (dist/solid.js:422) sets the global Promise = MockPromise (:428) and window.fetch to return a MockPromise, runs the computation, then restores both. MockPromise's then/catch/finally/resolve/all return new mock promises that never settle.

Any user code that creates a promise during that window and keeps it gets a promise that never resolves. A common case is a module-level de-duplication cache for lazy imports. Vite's __vitePreload, which wraps every built import(), starts with let promise = Promise.resolve(), reading the global at call time, so the stored import() is a MockPromise.

Repro
// messages.js
const loads = new Map()
export function load(key) {
  let p = loads.get(key)
  if (!p) loads.set(key, (p = import("./catalog.js"))) // built: goes through __vitePreload
  return p
}

// component (SSR'd inside <Loading>, then hydrated)
const data = createMemo(() => load("x"))
  1. SSR the component inside <Loading> so the memo's value is serialized, then hydrate.
  2. During hydration the memo runs only to track reads, under subFetch, so load("x") stores a MockPromise in loads.
  3. Unmount, then mount another component that calls load("x").

Expected: it resolves with the module.
Actual: it stays pending forever. No request for catalog.js is made, and in an app this froze client navigation.

Suggested fix

Don't replace globals. Pass the mock explicitly where Solid needs it, or restore the globals before user code can create promises it keeps. At minimum, document that promises created inside a computation while it hydrates are fake and must not be cached.

Workaround

On the client, when the memo already holds the hydrated (serialized) value, write it into the cache, so later callers never touch the stored mock promise.

Ngôn ngữ chính
TypeScript
Star
36.2k
Fork
1.1k
Merge trung bình
10 giờ 57 phút
Pull request đã merge (30 ngày)
360

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của solidjs/solid

Tất cả issue của solidjs/solid

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.