Skip to content

Commit

Permalink
Add non-standard cross-browser fields support
Browse files Browse the repository at this point in the history
  • Loading branch information
cezaraugusto committed Jun 28, 2024
1 parent b0391db commit dc1bda6
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
17 changes: 17 additions & 0 deletions packages/manifest-compat-plugin/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {type Compiler} from 'webpack'
import {type ManifestCompatInterface} from './types'
import handleSchemaErrors from './handleSchemaErrors'
import handleRuntimeErrors from './handleRuntimeErrors'
import HandleBrowserSpecificFields from './plugins/HandleBrowserSpecificFields'
import {type ManifestBase} from './manifest-types'

export default class ManifestCompatPlugin {
Expand All @@ -13,6 +14,22 @@ export default class ManifestCompatPlugin {
}

apply(compiler: Compiler) {
// TODO: This should be split into multiple plugins
// - HandleMissingFields - When users are missing a required field in their manifest file.
// - HandleDeprecatedFields - When users use a manifest field that has been deprecated in their manifest file version.
// - HandleV2ToV3Changes - When users use a manifest field that has changed from v2 to v3 e.g. `web_accessible_resources`.
// - HandleFieldTypeMistakes - When users use a field with the wrong type, e.g. a string instead of an array.

// - HandleBrowserSpecificFields - When users use non-compilant, browser-specific fields e.g. `chrome:`, `firefox:`.
new HandleBrowserSpecificFields({
manifestPath: this.options.manifestPath,
browser: this.options.browser || 'chrome'
}).apply(compiler)

// - HandleBrowserCompatErrors - When users use a field that is not compatible with the browser they are targeting.
// - HandleManifestVersionErrors - When users use a field that is not compatible with the browser they are targeting.

// TODO: Refactor this
compiler.hooks.afterCompile.tapAsync(
'CompatPlugin (module)',
(compilation, done) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {type Compiler, sources} from 'webpack'
import {ManifestBase} from '../manifest-types'

interface Options {
manifestPath: string
browser: string
exclude?: string[]
}

export default class HandleBrowserSpecificFields {
private readonly manifestPath: string
private browser: string
private chromiumBasedBrowsers = ['chrome', 'edge', 'opera', 'brave']

constructor(options: Options) {
this.manifestPath = options.manifestPath
this.browser = options.browser
}

private processManifest(manifest: any): any {
const result: any = {}

for (const key in manifest) {
if (manifest.hasOwnProperty(key)) {
if (
typeof manifest[key] === 'object' &&
!Array.isArray(manifest[key])
) {
result[key] = this.processManifest(manifest[key])
} else if (
key.startsWith(`${this.browser}:`) ||
(key.startsWith('chromium:') &&
this.chromiumBasedBrowsers.includes(this.browser))
) {
result[key.replace(`${this.browser}:`, '').replace('chromium:', '')] =
manifest[key]
} else if (!key.includes(':')) {
result[key] = manifest[key]
}
}
}

return result
}

apply(compiler: Compiler) {
compiler.hooks.emit.tapAsync(
'HandleBrowserSpecificFields',
(compilation, done) => {
if (compilation.errors.length > 0) return

const manifestSource = compilation
.getAsset('manifest.json')
?.source.source()
const manifest: ManifestBase = JSON.parse(
(manifestSource || '').toString()
)
const overrides = this.processManifest(manifest)

const patchedManifest: ManifestBase = {
...manifest,
...JSON.parse(overrides)
}

const source = JSON.stringify(patchedManifest, null, 2)
const rawSource = new sources.RawSource(source)

compilation.updateAsset('manifest.json', rawSource)

done()
}
)
}
}

0 comments on commit dc1bda6

Please sign in to comment.