Vue CLI offers a great workflow for most web apps. Run a command, choose which plugins to enable, and you're off to the races. But if you want something off the beaten path it is a little more difficult. I've found that setting up webpack takes longer than I'm willing to spend for a quick project. Instead, I use Parcel, which requires (almost) zero config.
Today we'll walk through how to use Vue (or React, or Typescript, or anything else that needs a build step) in a Browser Extension. Our browser extension will work in both Chrome and Firefox (using the webextension-polyfill project).
The hard part, as it should be, is deciding what to build. We'll punt on that one, and just make a widget that shows a color depending on the date.
To get started, initialize your project and install a couple dependencies.
npm init -y # set up a package.json, accepting all default # (drop the '-y' if you want to choose a name, license, etc, by hand) npm install --save-dev parcel parcel-plugin-web-extension
Next, borrow a couple of scripts we'll need for building the release: scripts/remove-evals.js and scripts/build-zip.js. I originally got these from another boilerplate, but made some changes to remove dependencies. It looks like remove-evals.js is used because chrome extensions ship with a content-security-policy that disallows eval
. build-zip.js is used to package up a production build of your extension.
Next, we'll make a manifest file, describing the extension's entry points. Our extension is fairly simple with only a popup, but yours might have content scripts, a background script, or an options page.
{ // src/manifest.json "browser_action": { "default_popup": "./popup.html" }, "description": "Color of the Day", "manifest_version": 2, "name": "color-of-the-day", "permissions": [], "version": "1.0.0", "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" }
Next, make a small file matching your default_popup
's name: popup.html
. This will be used as a parcel entry point, so parcel will bundle any resources it finds in this file.
<!-- src/popup.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> </head> <body> <div id="app"></div> <script src="./popup.js"></script> </body> </html>
When parcel sees <script src="./popup.js"></script>
, it will visit that file to see what other code needs to be bundled. That will be our Vue entry point.
// src/popup.js import Vue from "vue"; import App from "./App.vue"; new Vue({ el: "#app", render: (h) => h(App), });
Similarly, parcel will now pull in both vue
and App.vue
.
<template> <div class="color-of-the-day" :style="{ 'background-color': backgroundColor }" ></div> </template> <script> export default { computed: { hue() { return Math.floor(Math.random() * 360); }, backgroundColor() { return `hsl(${this.hue}, 100%, 50%)`; }, }, }; </script> <style> .color-of-the-day { width: 200px; height: 200px; } </style>
Finally, we'll need to add a few items to the scripts section of our package.json:
{ // package.json // ... "scripts": { "build": "npm run pack && npm run remove-evals && npm run zip", "dev": "parcel watch src/manifest.json --out-dir dist --no-hmr", "pack": "parcel build src/manifest.json --out-dir dist", "remove-evals": "node scripts/remove-evals.js", "zip": "node scripts/build-zip.js" } // ... }
Now run npm run dev
to build your extension. The first time you run this, parcel will notice you're working with Vue and download some packages you need (eg, vue
, vue-template-compiler
). Once it says "Built in 14.03s", or however long, you can load the extension in your browser.
Visit chrome://extensions
or about:debugging#/runtime/this-firefox
, depending on your browser. You may need to turn on developer mode if this is the first time you've loaded an extension from a file on this computer. Load the dist
folder (chrome) or the manifest.json file (firefox), and your extension is ready!
All the code from this post is available at https://github.com/bgschiller/vue-parcel-web-extension
More goodies
Parcel is smart enough to handle almost any web technology. If you want to use Typescript, just change
popup.js
to popup.ts
and make a tsconfig.json file. Want to use scss? Add lang="scss"
to the <style>
tag in your Vue component. Reportedly, it can even handle Rust code, though I haven't tried it.
Top comments (1)
Does HMR work with this?