Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 12, 2022 09:17 pm GMT

Advanced Config for RPCE

RPCE for Vite has been in beta long enough for us to get a good sample of developer use cases. Thanks to everyone who has helped by creating issues and participating in discussions! Your input is super valuable.

These are some answers to the most common developer questions we've fielded. I'm Jack Steam, creator of rollup-plugin-chrome-extension, or RPCE for short. So if you're looking to add extra HTML pages, extend the manifest at build time, use the new Chrome Scripting API, and inject main world scripts, read on!

Table of Contents

  • Extra HTML pages
  • Dynamic manifest with TypeScript
  • Manifest icons and public assets
  • Web accessible resources
  • Dynamic content scripts
  • Injected main world scripts

Extra HTML pages

It's pretty common to need to build web pages that you can't declare in the manifest. For example, you might want to change the popup once the user signs in, or you want to open a welcome page when the user installs the extension. Devtool extensions like React Developer Tools don't declare their inspector panels in the manifest.

Given the following file structure and manifest, index.html and src/panel.html will be available during development but not in a production build. We can fix this in vite.config.ts.

. vite.config.ts manifest.json index.html src/     devtools.html     panel.html
// manifest.json{  "manifest_version": 3,  "version": "1.0.0",  "name": "example",  "devtools_page": "src/devtools.html"}

To build extra HTML pages, follow the pattern from the Vite Documentation for Multi-Page Apps:

// vite.config.jsimport { resolve } from 'path';import { defineConfig } from 'vite';import { chromeExtension } from 'rollup-plugin-chrome-extension';import manifest from './manifest.json';export default defineConfig({  build: {    rollupOptions: {      // add any html pages here      input: {        // output file at '/index.html'        welcome: resolve(__dirname, 'index.html'),        // output file at '/src/panel.html'        panel: resolve(__dirname, 'src/panel.html'),      },    },  },  plugins: [chromeExtension({ manifest })],  });

Dynamic manifest with TypeScript

RPCE treats the manifest as a config option and transforms it during the build process. Furthermore, since the manifest is a JavaScript Object, it opens up some exciting ways to extend the manifest.

Imagine writing your manifest in TypeScript. Use different names for development and production. Keep the version number in sync with package.json.

RPCE provides a defineManifest function that works like Vite's defineConfig function and provides IntelliSense, making it easy to extend your manifest at build time.

// manifest.config.tsimport { chromeExtension, defineManifest } from 'rollup-plugin-chrome-extension'import { version } from './package.json'const names = {  build: 'My Extension',  serve: '[INTERNAL] My Extension'}// import to `vite.config.ts`export default defineManifest((config, env) => ({  manifest_version: 3,  name: names[env.command],  version,}))

Manifest icons and public assets

If you've used Vite for a website, you might be familiar with the public directory. Vite copies the contents of public to the output directory.

You can refer to public files in the manifest. If RPCE doesn't find a matching file in public, it will look for the file relative to the Vite project root and add the asset to the output files.

This means you're free to put your icons in public or anywhere else that makes sense to you!

// manifest.json {  "icons": {    // from src/icons/icon-16.png    "16": "src/icons/icon-16.png",    // from public/icons/icon-24.png     "24": "icons/icon-24.png"  },  "web_accessible_resources": [{    matches: ['https://www.google.com/*'],    // copies all png files in src/images    resources: ["src/images/*.png"]  }]}

RPCE will also copy files that match globs in web_accessible_resources.

RPCE ignores the globs * and **/*. You probably don't want to copy package.json and everything in node_modules. The real question is, should a website be able to access every single file in your extension?

What are web accessible resources, anyways?

Web Accessible Resources

The files in your Chrome Extension are private by default. If your extension has the file icon.png, extension pages can access it, but random websites cannot (it's not a web accessible resource). If you want an extension resource to be web accessible, you need to declare the file in the manifest under web_accessible_resources.

What if I want to use an image in a content script? It has to be web accessible. Why? Content scripts share the origin of the host page, so a web request from a content script on https://www.google.com is the same as a request from https://www.google.com itself.

It can get tedious to update the manifest with every file you're using. We're using build tools, so why do a bunch of manual work? When you import an image into a content script, RPCE updates the manifest automatically.

All you need to do is wrap the import path with a call to chrome.runtime.getURL to generate the extension URL:

import logoPath from './logo.png'const logo = document.createElement('img')logo.src = chrome.runtime.getURL(logo)

These files are accessible to the same URLs where the content script runs. Also, these assets use a dynamic url, so malicious websites can't use it to fingerprint your extension!

Dynamic Content Scripts

The Chrome Scripting API lets you execute content scripts from the background of a Chrome Extension.

The manifest doesn't have a place to declare dynamic content scripts, so how do we tell Vite about them? Of course, we could add them to the Vite config like an extra HTML page, but how does RPCE know that we intend the added script to be a content script? Does it need the unique flavor of HMR that RPCE provides? What about web accessible resources?

RPCE uses a unique import query to designate that an import points to a content script. When an import name ends with the query ?script, the default export is the output filename of the content script. You can then use this filename with the Chrome Scripting API to execute that content script and profit from Vite HMR.

import scriptPath from './content-script?script'chrome.action.onClicked.addListener((tab) => {    chrome.scripting.executeScript({    target: { tabId: tab.id },    files: [scriptPath]  });});

The resources of a dynamic content script are available to all URLs by default, but you can tighten that up using the defineDynamicResource function:

import { defineManifest, defineDynamicResource } from 'rollup-plugin-chrome-extension'export default defineManifest({  ...manifest,  web_accessible_resources: [    defineDynamicResource({      matches: ['https://www.google.com/*'],    })  ]})

Main world scripts

Content scripts run in an isolated world, but sometimes a script needs to modify the execution environment of the host page. Content scripts usually do this by adding a script tag to the DOM of their host page. Like any other content script asset, the main world script must be web accessible.

A dynamic content script import gets us close, but a script imported using ?script includes a loader file that adds Vite HMR. Unfortunately, the loader relies on the Chrome API only available to content scripts; it won't work in the main world execution environment. What we need is a simple ES module.

You can skip the loader file using the ?script&module import query:

// content-script.tsimport mainWorld from './main-world?script&module'const script = document.createElement('script')script.src = chrome.runtime.getURL(mainWorld)script.type = 'module'document.head.prepend(script)

Now get out there and read global variables, reroute fetch requests, and decorate class prototypes to your heart's content!

Roadmap

The next thing on RPCE's roadmap is proper documentation and a better release process. But, don't worry, we're not done adding features and fixing bugs; you can look forward to Shadow DOM in content scripts and better Vue support in the future. I'm also incredibly excited about adding official support for Svelte and Tailwind!

If RPCE has improved your developer experience, give us a star on GitHub or a shoutout on Twitter. See you next time.


Original Link: https://dev.to/jacksteamdev/advanced-config-for-rpce-3966

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To