Skip to content

Handle uncaught plugin errors to prevent live sites from breaking #1741

Closed
@jhildenbiddle

Description

@jhildenbiddle

Feature request

Docsify should handle uncaught plugin errors to prevent JavaScript execution from halting and breaking docsify sites.

What problem does this feature solve?

Docsify sites are rendered on the client using JavaScript. When a plugin error occurs, JavaScript execution is halted. The result for site visitors is a "broken" site typically rending only a "Loading..." message or an unresponsive UI (depending on when the plugin was invoked and what type of error occurs).

The problem with uncaught plugin errors is that they often go unnoticed by site owners and plugin authors and end up breaking live sites. For example, here are just a few uncaught plugin error issues that I have personally worked on:

Every issue above was the result of a plugin author using an unsupported method or ES6+ syntax, and each one prevented docsify sites from rendering properly in IE10/11. These bugs went undetected until I started testing docsify-themeable with various plugins in all supported platforms (which at the time included IE10 as well as IE11). If Docsify handled those uncaught plugin errors, the sites would have rendered properly (albeit without the expected plugin functionality).

The examples above are all "legacy" browser related, but this is not a legacy browser issue. The same issue exists for evergreen browsers since browser vendors choose if and when they will adopt new ES202X methods and syntax changes. For example, consider ES2022's Array.prototype.at() feature which is currently supported by all evergreen browsers except Safari:

window.$docsify = {
  // ...
  plugins: [
    function (hook, vm) {
      hook.beforeEach(function (content) {
        console.log('Plugin 1');
        console.log(['fail', 'success'].at(1));
      });
    },
    function (hook, vm) {
      hook.beforeEach(function (content) {
        console.log('Plugin 2');
        console.log(['fail', 'success'].at(1));
      });
    }
  ]
}

Chrome 99:

CleanShot 2022-03-09 at 15 09 57@2x

Safari 15.3 (latest):

CleanShot 2022-03-09 at 15 10 06@2x

This seems like an obvious error that one might expect to be caught by either the site owner or the plugin author, but it is not that simple:

  • What if the site owner and/or plugin author does not have the knowledge or resources to test on all supported platforms?
  • What if the plugin error is caused by a conflict with another plugin?
  • What if the plugin error occurs only when a specific configuration option is set?
  • What if the plugin error occurs only when an infrequent event occurs (e.g., malformed markdown or HTML, local storage limits exceeded, interaction on mobile device in landscape mode, etc.)?

These are not theoretical examples. We have real-world examples of each of them: #1057, #1392, #1526, #1538, ... etc. Obvious bugs are easy to detect, but not all bugs are obvious.

Ideally, plugin authors would conscientiously handle their own errors and thoroughly test on all platforms supported by Docsify. We know from years of docsify plugin development that this doesn't happen. The best we can do to prevent these issues is to make Docsify more resilient when possible and provide some best practiceson our Write a Plugin section.

Note: Asynchronous code will require plugin authors to implement their own try/catch/finally blocks directly in their code. An update to the official documentation that explains this would be helpful.

hook.afterEach(function (html, next) {
  try {
    // Async tasks...
    console.log("Plugin 1");
    console.log(["fail", "success"].at(1));
  } catch (err) {
    // ...
  } finally {
    next();
  }
});

What does the proposed API look like?

A catchPluginErrors configuration option can be added to allow uncaught plugin errors to throw as usual. This may be useful for docsify contributors, plugin authors, and site owners who rely on uncaught errors for their development or site monitoring tools.

  • Type: boolean
  • Default: true
window.$docsify = {
  catchPluginErrors: true // default
}

How should this be implemented in your opinion?

As a non-breaking change with documentation updated accordingly.

Are you willing to work on this yourself?

Yes

Metadata

Metadata

Assignees

Labels

docsrelated to the documentation of docsify itselfenhancementpluginrelated to plugin stuff.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions