makeplane / makeplane/plane

Work Items / Modules list crashes on Safari & iOS browsers: window.requestIdleCallback is not a function

Open Beginner friendly
#9,439 2 comments 1 reaction 0 assignees View on GitHub

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
  1. Self-host Plane CE, create a project with a Module or a few Work Items
  2. Open the instance in Safari (any Apple platform)
  3. Navigate to the project's "Work Items" list, or open a Module's detail view
  4. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.