From ca29537bbcdf2a36c5ecf118a6de01bdf3f8721b Mon Sep 17 00:00:00 2001 From: Aaron Klinker Date: Fri, 23 Jun 2023 21:17:41 -0500 Subject: [PATCH] feat: Virtualized content script entrypoint Generalized the background logic so it can be reused with mulitple entrypoint types --- package.json | 3 ++- src/utils/buildEntrypoints.ts | 8 +++++- src/utils/getInternalConfig.ts | 2 ++ src/vite-plugins/index.ts | 1 + src/vite-plugins/virtualEntrypoint.ts | 35 +++++++++++++++++++++++++++ templates/template-vars.d.ts | 11 +++++++++ templates/virtual-background.ts | 13 ++++++++++ templates/virtual-content-script.ts | 9 +++++++ 8 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/vite-plugins/virtualEntrypoint.ts create mode 100644 templates/template-vars.d.ts create mode 100644 templates/virtual-background.ts create mode 100644 templates/virtual-content-script.ts diff --git a/package.json b/package.json index 5401bd93..15c50341 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "author": "Aaron Klinker", "license": "MIT", "files": [ - "dist" + "dist", + "templates" ], "bin": "dist/cli/index.cjs", "main": "./dist/index.cjs", diff --git a/src/utils/buildEntrypoints.ts b/src/utils/buildEntrypoints.ts index 8925bf2d..4a865037 100644 --- a/src/utils/buildEntrypoints.ts +++ b/src/utils/buildEntrypoints.ts @@ -32,10 +32,16 @@ async function buildSingleEntrypoint( entrypoint: Entrypoint, config: InternalConfig, ): Promise { + // Should this entrypoint be wrapped by the vite-plugins/virtualEntrypoint plugin? + const isVirtual = ['background', 'content-script'].includes(entrypoint.type); + const entry = isVirtual + ? `virtual:exvite-${entrypoint.type}?${entrypoint.inputPath}` + : entrypoint.inputPath; + const libMode: vite.InlineConfig = { build: { lib: { - entry: entrypoint.inputPath, + entry, formats: ['iife'], name: entrypoint.name, fileName: entrypoint.name, diff --git a/src/utils/getInternalConfig.ts b/src/utils/getInternalConfig.ts index 311b04fd..61692be2 100644 --- a/src/utils/getInternalConfig.ts +++ b/src/utils/getInternalConfig.ts @@ -79,6 +79,8 @@ export async function getInternalConfig( merged.vite.plugins.push(plugins.download(merged)); merged.vite.plugins.push(plugins.devHtmlPrerender(merged)); merged.vite.plugins.push(plugins.unimport(merged)); + merged.vite.plugins.push(plugins.virtualEntrypoin('background')); + merged.vite.plugins.push(plugins.virtualEntrypoin('content-script')); return merged; } diff --git a/src/vite-plugins/index.ts b/src/vite-plugins/index.ts index a18d3ee4..83ef53c8 100644 --- a/src/vite-plugins/index.ts +++ b/src/vite-plugins/index.ts @@ -2,3 +2,4 @@ export * from './download'; export * from './unimport'; export * from './multipageMove'; export * from './devHtmlPrerender'; +export * from './virtualEntrypoint'; diff --git a/src/vite-plugins/virtualEntrypoint.ts b/src/vite-plugins/virtualEntrypoint.ts new file mode 100644 index 00000000..2dcbcc6f --- /dev/null +++ b/src/vite-plugins/virtualEntrypoint.ts @@ -0,0 +1,35 @@ +import { Plugin } from 'vite'; +import { Entrypoint } from '../types'; +import fs from 'fs-extra'; +import { resolve } from 'path'; + +/** + * Wraps a user's entrypoint with a vitual version with additional logic. + */ +export function virtualEntrypoin(type: Entrypoint['type']): Plugin { + const virtualId = `virtual:exvite-${type}?`; + const resolvedVirtualId = `\0${virtualId}`; + + return { + name: `exvite:virtual-entrypoint`, + resolveId(id) { + // Id doesn't start with prefix, it looks like this: + // /path/to/project/virtual:background?/path/to/project/entrypoints/background.ts + const index = id.indexOf(virtualId); + if (index === -1) return; + + const inputPath = id.substring(index + virtualId.length); + return resolvedVirtualId + inputPath; + }, + async load(id) { + if (!id.startsWith(resolvedVirtualId)) return; + + const inputPath = id.replace(resolvedVirtualId, ''); + const template = await fs.readFile( + resolve(`node_modules/exvite/templates/virtual-${type}.ts`), + 'utf-8', + ); + return template.replaceAll('{{moduleId}}', inputPath); + }, + }; +} diff --git a/templates/template-vars.d.ts b/templates/template-vars.d.ts new file mode 100644 index 00000000..b62adf05 --- /dev/null +++ b/templates/template-vars.d.ts @@ -0,0 +1,11 @@ +// Types required to make templates happy. + +declare module '*?raw' { + const content: any; + export default content; +} + +declare module '{{moduleId}}' { + const variable: any; + export default variable; +} diff --git a/templates/virtual-background.ts b/templates/virtual-background.ts new file mode 100644 index 00000000..a427d94e --- /dev/null +++ b/templates/virtual-background.ts @@ -0,0 +1,13 @@ +import definition from '{{moduleId}}'; + +try { + const res = definition.main(); + if (res instanceof Promise) { + console.warn( + "The background's main() function return a promise, but it must be synchonous", + ); + } +} catch (err) { + console.error('The background script crashed on startup!\n\n', err); + throw err; +} diff --git a/templates/virtual-content-script.ts b/templates/virtual-content-script.ts new file mode 100644 index 00000000..1a167622 --- /dev/null +++ b/templates/virtual-content-script.ts @@ -0,0 +1,9 @@ +import definition from '{{moduleId}}'; + +(async () => { + try { + await definition.main(); + } catch (err) { + console.error('The content script crashed on startup!\n\n', err); + } +})();