JBook, fixing iframe and better error handling

After the major changes with the useEffect and useState hooks, it was time to fix some the iframe window inside of preview.tsx. The problem was that when a user executes a code inside the editor, the code would get executed, displayed and immediately removed from the screen. To fix this problem we added a timeout inside the useEffect hook. The update code:

....//old code
useEffect(() => {
iframe.current.srcdoc = html;
// new code
setTimeout(() => {
iframe.current.contentWindow.postMessage(code, '*');
}, 50);
//old code
}, [code]);
....

Following this change, the const html was ready for some refactoring. The current code:

....
const html = `
<html>
<head>
<style>html {background-color: white; } </style>
</head>
<body>
<div id="root"></div>
<script>
window.addEventListener('message', (event) => {
try {
eval(event.data);
} catch (err){
const root = document.querySelector('#root');
root.innerHTML = '<div style="color: red"><h4>Runtime Error</h4>' + err + '</div>'
console.error(err);
}
}, false);
</script>
</body>
</html>
`;
....

isn’t handling errors well. We removed the following:

...
const root = document.querySelector('#root');
root.innerHTML = '<div style="color: red"><h4>Runtime Error</h4>' + err + '</div>'
console.error(err);
...

and we added the following above:

const handleError = (err) => {
const root = document.querySelector('#root');
root.innerHTML = '<div style="color: red"><h4>Runtime Error</h4>' + err + '</div>'
console.error(err);
}

and where the code we removed was, we placed:

handleError(err)

So the const html now looked like this:

const html = `
<html>
<head>
<style>html {background-color: white; } </style>
</head>
<body>
<div id="root"></div>
<script>
// new code
const handleError = (err) => {
const root = document.querySelector('#root');
root.innerHTML = '<div style="color: red"><h4>Runtime Error</h4>' + err + '</div>'
console.error(err);
}
//old code
window.addEventListener('message', (event) => {
try {
eval(event.data);
} catch (err){
//replaced code
handleError(err)
//old code
}
}, false);
</script>
</body>
</html>
`;

The const html still looks like a lot to process, probably will need some refactoring, but now it’s better suited to handle errors. The errors it didn’t handle yet are async errors. We fixed that with the inclusion of the following code:

window.addEventListener('error', (event) => {
event.preventDefault();
handleError(event.error)
});

And to wrap everything error-wise up, we added a try catch around the bundler. We changed the code following code:

....
const result = await service.build({
entryPoints: ['index.js'],
bundle: true,
write: false,
plugins: [unpkgPathPlugin(), fetchPlugin(rawCode)],
define: {
'process.env.NODE_ENV': '"production"',
global: 'window'
},
});
return result.outputFiles[0].text;
....

to this:

try {
const result = await service.build({
entryPoints: ['index.js'],
bundle: true,
write: false,
plugins: [unpkgPathPlugin(), fetchPlugin(rawCode)],
define: {
'process.env.NODE_ENV': '"production"',
global: 'window'
},
});
return {
code: result.outputFiles[0].text,
err: ''
}
} catch (err: any){
return {
code: '',
err: err.message,
}
}

Really great progress on error handling with Jbook completed. Next week I will write about the implementation of the MD editor.

Leave a Reply