iOS WebKit: gantt-layout-loader throws on missing window.requestIdleCallback — global error boundary on every issues-list view
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 59.6k
- Forks
- 5.8k
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 49
Description
Description
Plane CE's lazy-loaded gantt-layout-loader chunk calls window.requestIdleCallback without feature detection or a polyfill. iOS WebKit (Safari, iOS Chrome, iOS Firefox — all WebKit-backed under Apple's App Store rules) has never implemented requestIdleCallback — open WebKit gap since 2016 (webkit.org#164193). The throw propagates up, React's error boundary catches it, and the user sees the generic "Looks like something went wrong" page on every issues-list / project view.
Steps to reproduce
- iPad (any iOS / iPadOS version), Chrome (CriOS user-agent — but iOS Safari and iOS Firefox would all fail the same way; see "Why the matrix is weird" below).
- Sign in to a Plane CE instance.
- Navigate to any project's
/projects/<uuid>/issues/page. - The full error boundary fires.
Console error (from Safari Web Inspector against the iPad)
TypeError: window.requestIdleCallback is not a function.
(In 'window.requestIdleCallback(()=>{h.current&&(S.current=`${h.current.offsetHeight}px`)})', 'window.requestIdleCallback' is undefined)
— gantt-layout-loader-BH8Iumhn.js:1:5524
React Router caught the following error during render
— componentDidCatch (chunk-EPOLDU6W-PsE1YSAx.js:4:2496)
[also] Minified React error #418 (hydration failed) and #423 (client-side recovery also failed)
— both downstream of the same throw.
Why the matrix is weird (and the cause is clear)
| Browser | Result | Why |
|---|---|---|
| iOS Chrome (CriOS) | Error boundary | UA hints route through the bundle that lazy-loads gantt-layout-loader → hits missing API |
| iOS Safari | Works | UA routes through a different bundle that doesn't load the gantt chunk |
| iOS Chrome with "Request Desktop Site" | Works | Desktop UA routes through the desktop bundle (gantt chunk apparently feature-detects or skips on the desktop layout calculator path) |
| macOS Safari / macOS Chrome | Works | Engines implement requestIdleCallback natively |
So the bug has been sitting hidden behind a UA-sniffing branch that only one of three iOS browser paths exercises.
Suggested fix
Either:
A — Polyfill requestIdleCallback once at app entry:
if (typeof window.requestIdleCallback !== 'function') {
window.requestIdleCallback = (cb) => {
const start = Date.now();
return setTimeout(() => cb({
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start)),
}), 1);
};
window.cancelIdleCallback = (id) => clearTimeout(id);
}
B — Feature-detect inside gantt-layout-loader and fall back to setTimeout(fn, 0) for the height-measurement use case (which doesn't actually need idle-time semantics; it's just deferring a layout measurement).
Either is a few lines. (A) catches every other requestIdleCallback use in the codebase.
Environment
- Plane CE v1.3.1 (self-hosted, full upstream image set)
- Client: iPad (any), Chrome on iOS / iOS WebKit
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
Locate the source for the lazy-loaded gantt-layout-loader and the application entry point, then reproduce the failure on an iOS WebKit browser using the project's issues-list or project view. Choose the fallback approach that fits the existing structure; done means the view renders without the global error boundary when requestIdleCallback is unavailable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 64/100