This week I've release Omatsuri – open source browser only application with 9 frontend and design focused tools. In this post I'll go through some technical challenges that I've faced during development.
About application
Omatsuri translates to «festival» from Japanese (お祭り) and includes a festival of 9 tools:
- CSS Triangle Generator
- Color Shades Generator
- Curved Page Dividers Generator
- SVG compressor
- SVG to JSX converter
- Base64 encoder
- Realistic Fake Data Generator
- HTML/CSS Symbols Collection
- Lorem/Samuel/Poke Ipsum Generator
Some technical details
My initial purpose was to make Omatsuri a browser only application. This approach allows to reduce costs for hosting server that does heavy jobs, like svg compression, prettier transformations and other heavy things.
SVG compression
Did you know that there is actually only one good library for svg compression (svgo) written in JavaScript? And it does not have browser support, only node.js. I found it very strange as svg compression is based entirely on string parsing and does not include any node specific logic.
So my first task was to migrate svgo to browser. It was pretty easy, since all core logic did not require any modifications. And now you can use svgo-browser library in your projects if you ever need svg compression in browser.
Web workers
As I said before, some task are very heavy and can block your browser for several seconds. To fix this, we can put them in separate thread using web workers so that they run in background without blocking the main thread.
I was surprised how easy it is to work with web workers in webpack. All you need is worker-loader that will handle all worker bundling for you.
Here is an example of web worker usage for transforming svg to jsx with prettier and svg compression:
// svg-to-jsx.worker.js
import prettier from 'prettier/standalone';
import prettierBabel from 'prettier/parser-babel';
import svg2jsx from 'svg-to-jsx';
import optimize from 'svgo-browser/lib/optimize';
function generateComponent(svg) {
return `import React from 'react';\n\nexport default function SvgComponent() { return ${svg} }`;
}
onmessage = (event) => {
const { payload } = event.data;
optimize(event.data.content)
.then((content) => svg2jsx(content))
.then((svg) =>
prettier.format(generateComponent(svg), { parser: 'babel', plugins: [prettierBabel] })
)
.then((code) => postMessage({ error: null, payload, code }))
.catch((error) => postMessage({ error, payload, content: null }));
};
// react component
import React, { useState, useLayoutEffect } from 'react';
import Svg2jsxWorker from '../../workers/svg-to-jsx.worker';
const svg2jsx = new Svg2jsxWorker();
export default function SvgToJsx() {
const [result, setResult] = useState({ loading: false, error: null, content: null });
const handleMessage = (event) => {
setResult({ loading: false, error: event.data.error, content: event.data.code });
};
const postMessage = (text) => svg2jsx.postMessage({ content: text });
useLayoutEffect(() => {
svg2jsx.addEventListener('message', handleMessage);
return () => svg2jsx.removeEventListener('message', handleMessage);
}, []);
return (/* ... */);
}
SPA prerendering
As app does not have any server logic it can be fully prerendered. To make that happen there is a webpack pugin that automatically prerenders all app routes on production builds. You can view my configuration for this plugin here.
Contributing
If you've been waiting to contribute to open source project, now is your chance! There are lots of features that can be added to the app, here is some of them:
- Offline support with service workers
- Dark theme support (automatically detected from user os)
- New application – e.g. gradient generator
If you decide to contribute don't forget to add yourself to hall of fame on the About page.
What do you think?
Do you like this project? Will you use it? Don't be shy, comment about anything, I'll be happy to receive any feedback.
Top comments (0)