Work Items / Modules list crashes on Safari & iOS browsers: window.requestIdleCallback is not a function
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 59.6k
- Forks
- 5.8k
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 49
Description
Title: Work Items / Modules list crashes on Safari & iOS browsers: window.requestIdleCallback is not a function
Body:
Bug description
Opening the "Work Items" list or a Module's detail view crashes the app with a generic
"Looks like something went wrong!" error screen on Safari (macOS) and on any iOS browser
(Safari, Chrome/Brave/etc. on iOS — all forced to use WebKit by Apple's platform policy).
Root cause
gantt-layout-loader.js calls window.requestIdleCallback(...) without a feature check
or fallback. WebKit/Safari has never implemented requestIdleCallback (long-standing,
unresolved WebKit position — see https://bugs.webkit.org/show_bug.cgi?id=180002), so the
call throws:
TypeError: window.requestIdleCallback is not a function.
(In 'window.requestIdleCallback(()=>{h.current&&(S.current=`${h.current.offsetHeight}px`)})',
'window.requestIdleCallback' is undefined)
This is uncaught and bubbles up through React Router's render error boundary, producing the
generic error screen.
Environment
- Self-hosted Community Edition (Docker Compose),
makeplane/plane-frontend:stable - Reproduced on: Safari (macOS), Safari/Brave/Chrome (iOS/iPadOS)
- Not reproduced on Chromium-based desktop browsers (which do implement
requestIdleCallback)
Steps to reproduce
- Self-host Plane CE, create a project with a Module or a few Work Items
- Open the instance in Safari (any Apple platform)
- Navigate to the project's "Work Items" list, or open a Module's detail view
- Page loads briefly, then the global error boundary fires
Suggested fix
Add a small guard/polyfill for requestIdleCallback (fallback to setTimeout), e.g.:
window.requestIdleCallback = window.requestIdleCallback || function (cb) {
const start = Date.now();
return setTimeout(() => cb({
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start)),
}), 1);
};
window.cancelIdleCallback = window.cancelIdleCallback || function (id) {
clearTimeout(id);
};
Either bundled globally (e.g. injected once in index.html / entry point) or applied at the
specific call site in the Gantt/Timeline layout code.
Happy to open a PR with the polyfill if that's a welcome approach — just wanted to confirm the
preferred fix location first (global shim vs. call-site guard).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in gantt-layout-loader.js, where the issue reports the unguarded window.requestIdleCallback call, and inspect the surrounding Gantt/Timeline layout code. Verify the Work Items list and Module detail view in Safari or an iOS browser, then confirm they load without the React Router error boundary while Chromium behavior remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100