How we built TinySnap: the anatomy of a browser extension

The story behind the birth of TinySnap.

How we built TinySnap: the anatomy of a browser extension
Photo by Glenn Carstens-Peters / Unsplash

Background

We understand there's a plethora of screenshot extensions on the Chrome Web Store. However, the core idea of TinySnap is to help creators, developers, and marketers improve their productivity. TinySnap is best suited for people obsessed with getting soulful stuff done efficiently. Our product comes with an in-built post-processing section and cloud synchronization. And in an ideal scenario, our users can snap a screenshot, annotate it, and share it with anyone quickly and easily.

As Leila Hock points out: “It’s not hard work–work is work, and yes, some work requires more brain power, but most of us smart people like that and want more of it, so let’s stop calling it hard. Let’s call it productive. Effective. Valuable. Anything that speaks to nature over quantity, because that’s what we need more of.”

And that's why we built TinySnap.

Obviously, when it comes to building a browser extension, Google Chrome, which takes the #1 market share, is the primary option, and we will start from here.

Google Chrome is ambitious on web extensions, it no longer accepts Manifest V2 extension on building, so we have to start with Manifest V3.

Manifest V3

Manifest V3

Compared to Manifest V2, Manifest V3 changed a lot. For us, it means:

Remote script

Remote script is not allowed to execute in Manifest V3, so all the scripts have to be bundled with the extension, even Google Tag Manager/Google Analytics has to be downloaded to local and bundled to the extension.

Background

Background was changed from background pages to service workers, which means all the DOM-related APIs do not work anymore.

Host permissions

host_permissions was split from permissions, and now it's a new field.

Shortcuts

Shortcuts must be explicitly defined in commands, otherwise, the browser will not allow the extension to get temporary activeTab permission.

Technical stack we use

Based on our experience in front-end development, webpack takes a century to wait on both development and bundling. Ridiculously, a small change on a big project takes several seconds to refresh on save, and it takes minutes on bundling, so we desperately need a ⚡lightning-fast tool to replace it.

Vite gave us an awesome development experience, it directly sends the converted ES module code to supported browsers, allowing the browser to load dependencies by itself, and some of the latest ES syntaxes do not need to be converted into the old syntaxes to be compatible with developer's browser, which significantly saves our development time. Vite is very fast and stable and is already our first choice for new projects.

Even though we are experts in React, we chose Vue 3 as the framework, we want to give it a try for knowledge diversity. Vue 3 + Pinia + Typescript make us feel much better compared to Vue 2 + Vuex. In some scenarios, Vue is faster than React in development.

Browser compatibility

Firefox is said to support Manifest V3 by the end of 2022, so we got down to resolve the Manifest V2 compatibility issue after we completed the V3 part. To our surprise, the process went swift. Below is what we encountered that required additional handling:

Manifest

We defined an environment variable so that different browsers can be distinguished when developing or packing, thereby generating different manifest.json files.

if (process.env.FIREFOX) {
    delete manifest.action
    delete manifest.host_permissions

    manifest = {
        ...manifest,
        manifest_version: 2,
        permissions: [
            ...,
            '<all_urls>'
        ],
        background: {
            scripts: ['./dist/background/index.mjs'],
        },
        browser_action: {
            default_icon: {
                "32": "./assets/icon-512.png"
            },
            default_popup: "./dist/popup/index.html",
        }
    }
}

Canvas

Background in Manifest V3 does not support any DOM-related API, so we have to choose OffscreenCanvas for image rendering. Although Firefox claims to support this API, it cannot be used in the Background page in the actual development process. Maybe we didn't get it right.

Clipboard

Another difference between Firefox and Chrome is the clipboard. Firefox does not support ClipboardItem, which means that navigator.clipboard.write cannot be used to copy images to the clipboard. However, Firefox supports browser.clipboard.setImageData, an API that Chrome has deprecated.


Overall, we didn't meet many difficulties while developing TinySnap, and the development experience was much easier than the traditional web development without having to consider those old browsers.