Skip to content

Commit

Permalink
inject window-provider at build time
Browse files Browse the repository at this point in the history
into provider bridge

The async fetch call to load the `window-provider.js` runtime
caused some really bad race conditions, so we needed a way
to have the content of the `window-provider.js` readily available
when the provider-bridge starts running.

This functionality had to work in both dev and prod environments
so the solution was to create a webpack plugin for this.

The trickiest part was finding the proper hooks in webpack
and escaping the source code so it can be stored as a string.
  • Loading branch information
Gergo Nagy committed Mar 22, 2022
1 parent 902be0a commit 6e686bb
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 8 deletions.
55 changes: 55 additions & 0 deletions build-utils/inject-window-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Compilation, Compiler } from "webpack"

const PLUGIN_NAME = "RuntimeDefine"
const WINDOW_PROVIDER_FILENAME = "window-provider.js"
const PROVIDER_BRIDGE_FILENAME = "provider-bridge.js"

export default class InjectWindowProvider {
// eslint-disable-next-line class-methods-use-this
apply(compiler: Compiler): void {
compiler.hooks.thisCompilation.tap(
PLUGIN_NAME,
(compilation: Compilation) => {
compilation.hooks.processAssets.tap(
{
name: PLUGIN_NAME,
stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE,
},
(assets) => {
let windowProviderSource =
// @ts-expect-error this exist
// eslint-disable-next-line no-underscore-dangle
assets[WINDOW_PROVIDER_FILENAME]._children[0]._value

// need to encode so it can be used as a string
// in non optimised builds the source is a multi line string > `` needs to be used
// but ${ needs to be escaped separatly otherwise it breaks the ``
windowProviderSource = encodeURI(windowProviderSource).replaceAll(
"${",
"\\${"
)
windowProviderSource = `\`${windowProviderSource}\``
const providerBridgeSource =
// @ts-expect-error this exist
// eslint-disable-next-line no-underscore-dangle
assets[PROVIDER_BRIDGE_FILENAME]._children[0]._value

// @ts-expect-error this exist
// eslint-disable-next-line no-underscore-dangle,no-param-reassign
assets[PROVIDER_BRIDGE_FILENAME]._children[0]._value =
providerBridgeSource.replace(
// eslint-disable-next-line no-useless-escape
`\"@@@WINDOW_PROVIDER@@@\"`,
windowProviderSource
)

// eslint-disable-next-line no-param-reassign
delete assets[WINDOW_PROVIDER_FILENAME]
// eslint-disable-next-line no-param-reassign
delete assets[`${WINDOW_PROVIDER_FILENAME}.map`]
}
)
}
)
}
}
18 changes: 10 additions & 8 deletions provider-bridge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,23 @@ export function connectProviderBridge(): void {

export async function injectTallyWindowProvider(): Promise<void> {
try {
const windowProviderSourceResponse = await fetch(
browser.runtime.getURL("window-provider.js")
)
const windowProviderSource = await windowProviderSourceResponse.text()
// This will be replaced by the InjectWindowProvider webpack plugin
const windowProviderSource = "@@@WINDOW_PROVIDER@@@"

const container = document.head || document.documentElement
const scriptTag = document.createElement("script")
// this makes the script loading blocking which is good for us
// bc we want to load before anybody has a chance to temper w/ the window obj
scriptTag.setAttribute("async", "false")
// TODO: put env flag here so only dev env has sourcemap
scriptTag.textContent = windowProviderSource.replace(
"window-provider.js.map",
browser.runtime.getURL("window-provider.js.map")

// need to decode the encodes string so it can be used as a source code
// in non optimised builds the source is a multi line string > `` was used
// but ${ needs to be escaped separatly otherwise it breaks the ``
scriptTag.textContent = decodeURI(windowProviderSource).replaceAll(
"\\${",
"${"
)

// TODO: fill in the provider state for window-provider
container.insertBefore(scriptTag, container.children[0])
} catch (e) {
Expand Down
2 changes: 2 additions & 0 deletions webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import LiveReloadPlugin from "webpack-livereload-plugin"
import CopyPlugin, { ObjectPattern } from "copy-webpack-plugin"
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"
import WebExtensionArchivePlugin from "./build-utils/web-extension-archive-webpack-plugin"
import InjectWindowProvider from "./build-utils/inject-window-provider"

const supportedBrowsers = ["brave", "chrome", "edge", "firefox", "opera"]

Expand Down Expand Up @@ -58,6 +59,7 @@ const baseConfig: Configuration = {
},
},
plugins: [
new InjectWindowProvider(),
new Dotenv({
defaults: true,
systemvars: true,
Expand Down

0 comments on commit 6e686bb

Please sign in to comment.