DEV Community

Brian Schiller
Brian Schiller

Posted on • Originally published at brianschiller.com

Vue Browser Extensions with Parcel

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
Enter fullscreen mode Exit fullscreen mode

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'"
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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),
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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"
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

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!

screenshot of the extension running in chrome. It shows a popup with a solid square colored purple

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.

Oldest comments (1)

Collapse
 
picwellwisher12pk profile image
Amir Hameed

Does HMR work with this?