Skip to content

Commit

Permalink
Added template web view providers (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjcouch-sil authored Jun 13, 2023
2 parents 0b4732b + 9cf57cf commit f50db2b
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 42 deletions.
2 changes: 1 addition & 1 deletion lib/extension-template.web-view.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import papi from "papi";
import { useState } from "react";
import { QuickVerseDataProvider } from "extension-types";
import { Button } from "papi-components";

const {
react: {
hooks: { useData, useDataProvider },
components: { Button },
},
logger,
} = papi;
Expand Down
104 changes: 80 additions & 24 deletions lib/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@ import extensionTemplateReact from "./extension-template.web-view";
import extensionTemplateReactStyles from "./extension-template.web-view.scss?inline";
// @ts-expect-error ts(1192) this file has no default export; the text is exported by rollup
import extensionTemplateHtml from "./extension-template-html.web-view.ejs";
import type { WebViewContentType } from "shared/data/web-view.model";
import type {
SavedWebViewDefinition,
WebViewContentType,
WebViewDefinition,
} from "shared/data/web-view.model";
import type { UnsubscriberAsync } from "shared/utils/papi-util";
import type { IWebViewProvider } from "shared/models/web-view-provider.model";

const { logger } = papi;

console.log(import.meta.env.PROD);

logger.info("Extension template is importing!");

const unsubscribers = [];

type QuickVerseSetData = string | { text: string; isHeresy: boolean };

class QuickVerseDataProviderEngine
Expand Down Expand Up @@ -129,6 +133,50 @@ class QuickVerseDataProviderEngine
}
}

const htmlWebViewType = "paranext-extension-template.html";

/**
* Simple web view provider that provides sample html web views when papi requests them
*/
const htmlWebViewProvider: IWebViewProvider = {
async getWebView(
savedWebView: SavedWebViewDefinition
): Promise<WebViewDefinition | undefined> {
if (savedWebView.webViewType !== htmlWebViewType)
throw new Error(
`${htmlWebViewType} provider received request to provide a ${savedWebView.webViewType} web view`
);
return {
...savedWebView,
title: "Extension Template HTML",
contentType: "html" as WebViewContentType.HTML,
content: extensionTemplateHtml,
};
},
};

const reactWebViewType = "paranext-extension-template.react";

/**
* Simple web view provider that provides React web views when papi requests them
*/
const reactWebViewProvider: IWebViewProvider = {
async getWebView(
savedWebView: SavedWebViewDefinition
): Promise<WebViewDefinition | undefined> {
if (savedWebView.webViewType !== reactWebViewType)
throw new Error(
`${reactWebViewType} provider received request to provide a ${savedWebView.webViewType} web view`
);
return {
...savedWebView,
title: "Extension Template React",
content: extensionTemplateReact,
styles: extensionTemplateReactStyles,
};
},
};

export async function activate() {
logger.info("Extension template is activating!");

Expand All @@ -137,6 +185,16 @@ export async function activate() {
new QuickVerseDataProviderEngine()
);

const htmlWebViewProviderPromise = papi.webViews.registerWebViewProvider(
htmlWebViewType,
htmlWebViewProvider
);

const reactWebViewProviderPromise = papi.webViews.registerWebViewProvider(
reactWebViewType,
reactWebViewProvider
);

const unsubPromises = [
papi.commands.registerCommand(
"extension-template.do-stuff",
Expand All @@ -146,31 +204,29 @@ export async function activate() {
),
];

papi.webViews.addWebView({
id: 'Extension template WebView React',
content: extensionTemplateReact,
styles: extensionTemplateReactStyles,
});

papi.webViews.addWebView({
id: 'Extension template WebView HTML',
contentType: 'html' as WebViewContentType.HTML,
content: extensionTemplateHtml,
});
// Create webviews or get an existing webview if one already exists for this type
// Note: here, we are using `existingId: '?'` to indicate we do not want to create a new webview
// if one already exists. The webview that already exists could have been created by anyone
// anywhere; it just has to match `webViewType`. See `paranext-core's hello-someone.ts` for an example of keeping
// an existing webview that was specifically created by `paranext-core's hello-someone`.
papi.webViews.getWebView(htmlWebViewType, undefined, { existingId: "?" });
papi.webViews.getWebView(reactWebViewType, undefined, { existingId: "?" });

// For now, let's just make things easy and await the data provider promise at the end so we don't hold everything else up
const quickVerseDataProviderInfo = await quickVerseDataProviderInfoPromise;

return Promise.all(
unsubPromises.map((unsubPromise) => unsubPromise.promise)
).then(() => {
logger.info("Extension template is finished activating!");
return papi.util.aggregateUnsubscriberAsyncs(
unsubPromises
.map((unsubPromise) => unsubPromise.unsubscriber)
.concat([quickVerseDataProviderInfo.dispose])
const htmlWebViewProviderResolved = await htmlWebViewProviderPromise;
const reactWebViewProviderResolved = await reactWebViewProviderPromise;

const combinedUnsubscriber: UnsubscriberAsync =
papi.util.aggregateUnsubscriberAsyncs(
(await Promise.all(unsubPromises)).concat([
quickVerseDataProviderInfo.dispose,
htmlWebViewProviderResolved.dispose,
reactWebViewProviderResolved.dispose,
])
);
});
logger.info("Extension template is finished activating!");
return combinedUnsubscriber;
}

export async function deactivate() {
Expand Down
91 changes: 76 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"lint": "tsc"
},
"dependencies": {
"papi-components": "file:../paranext-core/lib/papi-components",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand All @@ -29,7 +30,7 @@
"glob": "^10.2.2",
"papi-dts": "file:../paranext-core/lib/papi-dts",
"patch-package": "^7.0.0",
"rollup-plugin-import-manager": "^0.6.2",
"rollup-plugin-import-manager": "^0.6.3",
"rollup-plugin-string": "^3.0.0",
"sass": "^1.62.1",
"typescript": "^4.9.3",
Expand Down
6 changes: 5 additions & 1 deletion vite/vite-web-view.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const webViewConfig = defineConfig(async ({ mode }) => {
],
// Since Vite is in library mode `process` is not replaced by default and that won't work in the
// renderer.
define: { 'process.env.NODE_ENV': JSON.stringify(mode) },
define: { "process.env.NODE_ENV": JSON.stringify(mode) },
build: {
// This project is a library as it is being used in Paranext
lib: {
Expand Down Expand Up @@ -75,6 +75,10 @@ const webViewConfig = defineConfig(async ({ mode }) => {
rollupOptions: {
// Do not bundle papi because it will be imported in Paranext
external: paranextProvidedModules,
output: {
// Disable code splitting and chunks. Extension WebViews must be a single file
manualChunks: () => "webView",
},
},
// Bundle the sourcemap into the webview file since it will be injected as a string
// into the main file
Expand Down
4 changes: 4 additions & 0 deletions vite/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ const extensionConfig = defineConfig(async () => {
rollupOptions: {
// Do not bundle papi because it will be imported in Paranext
external: paranextProvidedModules,
output: {
// Disable code splitting and chunks. Extension main must be a single file
manualChunks: () => "main",
},
},
// Generate sourcemaps as separate files since VSCode can load them directly
sourcemap: true,
Expand Down

0 comments on commit f50db2b

Please sign in to comment.