Error recovery with Next

Almost 3 years ago, I wrote about recovering from runtime JavaScript errors thanks to a carefully crafted server-side rendering solution. This is something I was very proud of, and I think a testament of the quality of work that went into the N26 web p…


This content originally appeared on Kitty Giraudel and was authored by Kitty Giraudel

Almost 3 years ago, I wrote about recovering from runtime JavaScript errors thanks to a carefully crafted server-side rendering solution. This is something I was very proud of, and I think a testament of the quality of work that went into the N26 web platform.

The idea is to intercept runtime JavaScript errors, and reload the page with a query parameter which causes the JavaScript bundles not to be rendered, thus simulating a no-JavaScript experience. This way, the user can browse the no-JS version instead of being stuck on a broken page.

I recently announced Gorillas’ new website built with Next, which almost fully support JavaScript being disabled. So I was eager to try add a similar error recovery feature.

The problem

While we do use Next, we do not use the runtime. We essentially use Next as a static site generator. When deploying the site, we build all pages statically (with Next’ static HTML export), and serve them via Netlify. There is no Node server or anything like that. It’s just a bunch of HTML files eventually enhanced by a client-side React application.

This means that the HTML files do contain <script> tags at the bottom of the body element to execute our bundles. We can’t decide not to render them because, once again, this is all just static files—there is no running server that can modify the response.

So that’s not even really Next’s fault per se. Any static site generator would have the same problem. Once the browser receives the HTML response, it’s done, we can’t modify it. It will read the <script> tags, download the files, parse them and execute them. So… rough one to solve I guess.

Hacking a solution

If we can’t do anything about the script tags being rendered in the HTML response, maybe we can prevent the browser from executing them? Well, again, not really. Browsers do not offer a fine-grained API into their resources’ system to tell them to ignore or prioritize certain assets.

Did you know about window.stop() though? ‘Cause I didn’t until today. That’s a method on the window object that essentially does what the “Stop” button from the browser does. Quoting MDN:

The window.stop() [function] stops further resource loading in the current browsing context, equivalent to the stop button in the browser. Because of how scripts are executed, this method cannot interrupt its parent document's loading, but it will stop its images, new windows, and other still-loading objects.

What if we called window.stop() before the browser reaches the <script> tags rendered by <NextScript />? Let’s try that by updating ./pages/_document.js (see Custom Document in Next’s documentation):

class MyDocument extends Document {
static getInitialProps(ctx) {
return Document.getInitialProps(ctx)
}

render() {
return (
<Html>
<Head />
<body>
<Main />
{/* Trying to prevent <script> elements rendered by
`<NextScript />` from being executed. The proper
condition will be covered in the next section. */

<script dangerouslySetInnerHTML={{ __html: `
if (true) window.stop()
`
}}
/>

<NextScript />
</body>
</Html>
)
}
}

Performing a Next export and serving the output folder before loading any page yields positive results: not only are the <script> tags not executed, but they’re not even rendered in the dev tools. That’s because window.stop() literally killed the page at this point, preventing the rest of the document from being rendered.

    <script>if (true) window.stop()</script>
</body>
</html>

Building the thing

Of course, we do not want to always prevent the scripts’ execution. Only when we’ve captured a JavaScript error and reloaded the page with a certain query parameter. To do that, we need an error boundary.

class ErrorBoundary extends React.Component {
componentDidCatch(error, info) {
const { pathname, search } = window.location

window.location.href =
pathname + search + (search.length ? '&' : '?') + 'no_script'
}

render() {
return this.props.children
}
}

We can render that component around our content in ./pages/_app.js (see Custom App in Next’s documentation).

function MyApp({ Component, pageProps }) {
return (
<ErrorBoundary>
<Component {...pageProps} />
</ErrorBoundary>
)
}

Finally, in our ./pages/_document.js, we can check for the presence of this URL parameter. If it is present, we need to stop the execution of scripts.

class MyDocument extends Document {
static getInitialProps(ctx) {
return Document.getInitialProps(ctx)
}

render() {
return (
<Html>
<Head />
<body>
<Main />
<script dangerouslySetInnerHTML={{ __html: `
if (window.location.search.includes('no_script')) {
window.stop()
}
`
}} />
<NextScript />
</body>
</Html>
)
}
}

That’s it, job done. Hacky as hell, but heh. It seems to work okay. For the most part at least, as it has some potentially negative side-effects: any ongoing request, such as for lazy loaded images, will be interrupted. That can cause some images not to render. Still better than a broken page due to a JavaScript error in my opinion, but I guess the choice is yours.

Alright people, lay it on me. How bad is this, and how ashamed shall I be?


This content originally appeared on Kitty Giraudel and was authored by Kitty Giraudel


Print Share Comment Cite Upload Translate Updates
APA

Kitty Giraudel | Sciencx (2021-03-15T00:00:00+00:00) Error recovery with Next. Retrieved from https://www.scien.cx/2021/03/15/error-recovery-with-next/

MLA
" » Error recovery with Next." Kitty Giraudel | Sciencx - Monday March 15, 2021, https://www.scien.cx/2021/03/15/error-recovery-with-next/
HARVARD
Kitty Giraudel | Sciencx Monday March 15, 2021 » Error recovery with Next., viewed ,<https://www.scien.cx/2021/03/15/error-recovery-with-next/>
VANCOUVER
Kitty Giraudel | Sciencx - » Error recovery with Next. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/03/15/error-recovery-with-next/
CHICAGO
" » Error recovery with Next." Kitty Giraudel | Sciencx - Accessed . https://www.scien.cx/2021/03/15/error-recovery-with-next/
IEEE
" » Error recovery with Next." Kitty Giraudel | Sciencx [Online]. Available: https://www.scien.cx/2021/03/15/error-recovery-with-next/. [Accessed: ]
rf:citation
» Error recovery with Next | Kitty Giraudel | Sciencx | https://www.scien.cx/2021/03/15/error-recovery-with-next/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.