Skip to content

Safari incompatibility: gantt-layout-loader uses unguarded window.requestIdleCallback #8988

Description

@hylke-rozema

Describe the bug

Navigating to a project's Work Items page in Safari renders the React error boundary ("Looks like something went wrong") instead of the work items.

The root cause is a TypeError from gantt-layout-loader-*.js:

TypeError: window.requestIdleCallback is not a function.
(In 'window.requestIdleCallback(()=>{h.current&&(S.current=`${h.current.offsetHeight}px`)})',
 'window.requestIdleCallback' is undefined)
  at gantt-layout-loader-Bameferh.js:1:5524

Safari does not ship requestIdleCallback (still unimplemented as of Safari 17). The call site does not feature-detect.

React errors #418 and #423 follow, but those are cascade from the initial throw.

To reproduce

  1. Self-hosted Plane CE v1.3.0
  2. Open Safari on macOS or iOS, log in
  3. Open any project, click Work items
  4. Error boundary renders instead of the kanban or list

Backend is fine. A HAR capture shows all 366 requests returning 200, including /api/.../issues/... with valid grouped JSON.

Expected behavior

Work items render in Safari like they do in Chrome and Firefox.

Suggested fix

Feature-detect the API or ship a polyfill in the entry bundle.

Minimal feature-detect:

const ric = window.requestIdleCallback || ((cb) => setTimeout(() => cb({ didTimeout: false, timeRemaining: () => 50 }), 1));

The Gantt code path appears to use requestIdleCallback for non-critical layout measurement, so a setTimeout fallback should be visually acceptable. Polyfill packages like requestidlecallback-polyfill are well under 1 kB.

Workaround for self-hosters

Inject the polyfill via a reverse-proxy sub_filter on </head>. Tested on Plane 1.3.0 + Safari 17.x with nginx in front of plane-web:

location / {
    proxy_pass http://web;
    proxy_set_header Accept-Encoding "";
    sub_filter_once on;
    sub_filter '</head>' '<script>if(!window.requestIdleCallback){window.requestIdleCallback=function(c){return setTimeout(function(){c({didTimeout:false,timeRemaining:function(){return 50}})},1)};window.cancelIdleCallback=function(i){clearTimeout(i)}}</script></head>';
}

Environment

  • Plane CE 1.3.0, self-hosted (Docker)
  • Safari 17.x on macOS: broken
  • Firefox 129+ on macOS: works
  • Chrome 130+ on macOS: works

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions