plate icon indicating copy to clipboard operation
plate copied to clipboard

Plate website crashes when using safari

Open jonathanrose9 opened this issue 2 years ago • 6 comments

Description When I open https://platejs.org using Safari, the website crashes with the following error: Application error: a client-side exception has occurred (see the browser console for more information).

image

As additional information: When I open my Next JS application with Safari and navigate to a page where I use Plate, I receive a similar error message and the application crashes.

image

When I use Chrome or Firefox, both the Plate website and my application work as expected.

Steps to Reproduce

  1. Go to https://platejs.org with Safari
  2. Wait a few moments
  3. Go to console and see more detailed error

Environment

  • browser: Safari Version 14.1.1 (16611.2.7.1.4)

Funding

  • You can sponsor this specific effort via a Polar.sh pledge below
  • We receive the pledge once the issue is completed & verified
Fund with Polar

jonathanrose9 avatar Aug 01 '23 07:08 jonathanrose9

Array.prototype.at() was only added in Safari 15, hence why you're seeing this crash in Safari 14.

@zbeyens Do we have a minimum supported version for Safari?

12joan avatar Aug 01 '23 07:08 12joan

I'm trying to configure Plate's tsconfig.json to throw a compile error for newer JS features like Array.prototype.at().

This function was added to the array prototype in es2022, so I thought that changing esnext to es2021 would be enough to cause commentIds.at(-1) to fail in useCommentLeaf.ts, for instance. For some reason, however, changing the lib option doesn't seem to affect the output of yarn p:typecheck --watch.

-    "lib": ["dom", "dom.iterable", "esnext"],
+    "lib": ["dom", "dom.iterable", "es2021"],
     ...
     "target": "es2017",

Here's a TS Playground example of what the error should be.

@zbeyens Any idea why changing lib isn't working?

12joan avatar Aug 02 '23 15:08 12joan

unicorn's rule is enabled in the recommended config we use.

I don't think we should change esnext going forward. There is probably a way to add polyfills in the rollup config.

See:

  • https://forums.meteor.com/t/polyfill-for-array-at-method/57168/2
  • https://github.com/es-shims/Array.prototype.at
  • https://babeljs.io/docs/babel-preset-env#corejs

To support Array.prototype.at using the @babel/preset-env and core-js, you should include the "esnext.array.at" value in the core-js option of the preset. Here is an example of the configuration:

{
  "presets": [
    ["@babel/preset-env", {
      "corejs": {
        "version": 3,
        "proposals": true
      },
      "useBuiltIns": "usage"
    }]
  ]
}

Make sure you have @babel/preset-env installed as a dependency. The useBuiltIns option set to "usage" will automatically import the necessary polyfills from core-js based on the target environment and used language features.

zbeyens avatar Aug 02 '23 15:08 zbeyens

Polyfilling at is definitely an option. The only problem is this doesn't save us from writing incompatible code in the future, so users running older versions of macOS or iOS (and therefore WebKit) will see Plate-based apps randomly breaking.

Since developers are more likely to be running the latest OS version than regular users, and since users who don't update their OS regularly are less likely to know how to report crashes to developers, problems like this might go undiscovered for a long time. That's why setting TS to a recent but not cutting edge ECMAScript version would be a good idea.

For context, Safari is the only mainstream browser that doesn't autoupdate except through OS updates, since WebKit is built directly into macOS/iOS. It's not uncommon to see Safari users one or two major versions behind latest.

12joan avatar Aug 02 '23 15:08 12joan

That makes sense, we should start from es2022 and yearly update the corejs version to support the next ES versions.

zbeyens avatar Aug 02 '23 16:08 zbeyens

For anyone coming across this issue and wants plate to work on older browsers, here's a polyfill:

if (!Array.prototype.at) {
  Array.prototype.at = function (index) {
    index = Math.trunc(index) || 0
    if (index < 0) index += this.length
    if (index < 0 || index >= this.length) return undefined
    return this[index]
  }
}

zeckdude avatar Nov 13 '23 16:11 zeckdude