Skip to content

Commit

Permalink
extension: switch to rollup for building instead of webpack
Browse files Browse the repository at this point in the history
NOTE: this will break chrome extension until we implement full manifest v3 support

rollup switch is mainly because

- rollup has a much better builtin ES6 module support (in webpack it's STILL experimental!)
- minimal transformation to the source code, even possible to read without source maps

some additional changes

- somewhat more consistent import handling and bundling, less hacks with
- add build script changes from grasp
  • Loading branch information
karlicoss committed May 28, 2024
1 parent d2e4697 commit 45d6499
Show file tree
Hide file tree
Showing 31 changed files with 4,196 additions and 5,577 deletions.
File renamed without changes.
9 changes: 5 additions & 4 deletions extension/build
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,26 @@ def main() -> None:
if args.release:
assert args.lint # TODO not sure..

def firefox_release_args():
def firefox_publish_args():
from firefox_dev_secrets import API_KEY, API_SECRET
return [
'--artifacts-dir', str(artifacts_dir),
'--api-key' , API_KEY,
'--api-secret' , API_SECRET,
'--id' , IDS[target],
# seems like webext sign requires addon id to be in manifest now
]

if args.publish is not None:
assert args.lint
assert args.release
if 'firefox' in target:
check_call([
npm, 'run', 'release:amo',
npm, 'run', 'web-ext',
'--',
'sign', '--use-submission-api',
'--channel', args.publish,
'--source-dir', str(ext_dir),
*firefox_release_args(),
*firefox_publish_args(),
])
elif target == 'chrome':
assert args.publish == 'listed' # no notion of unlisted on chrome store?
Expand Down
9 changes: 4 additions & 5 deletions extension/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
// @ts-check
import globals from 'globals'
import eslint from '@eslint/js'
import tseslint from 'typescript-eslint'

const globals = require('globals')
const eslint = require('@eslint/js')
const tseslint = require('typescript-eslint')


module.exports = tseslint.config(
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended, // TODO recommendedTypeChecked??
{
Expand Down
243 changes: 243 additions & 0 deletions extension/generate_manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
// due to firefox + chrome and manifest v2 + v3 combination, 95% of the manifest is JS generated anyway
// so with this we're just generaing it fully dynamically

import assert from 'assert'

import pkg from './package.json' with { type: "json" }

const T = {
CHROME : 'chrome',
FIREFOX: 'firefox',
}


// ugh. declarative formats are shit.
export function generateManifest({
target, // str
version, // str
release, // bool
publish, // bool
ext_id // str
} = {}) {
assert(target)
assert(version)
assert(release !== null)
assert(ext_id)

const v3 = version == '3'

// Firefox wouldn't let you rebind its default shortcuts most of which use Shift
// On the other hand, Chrome wouldn't let you use Alt
const modifier = target === T.CHROME ? 'Shift' : 'Alt'

const action_name = v3 ? 'action' : 'browser_action'

const commands = {
"mark_visited": {
"description": "Mark/unmark visited links on the current page",
"suggested_key": {
"default": `Ctrl+${modifier}+V`,
"mac": `Command+${modifier}+V`,
},
},
// right, 'S' interferes with OS hotkey?
// need all of that discoverable from menu anyway
// also dots and browser action too
"search": {
"description": "Open search page",
"suggested_key": {
"default": `Ctrl+${modifier}+H`,
"mac": `Command+${modifier}+H`,
},
},
}

commands[`_execute_${action_name}`] = {
"description": "Activate sidebar",
"suggested_key": {
/* fucking hell, ubuntu is hijacking Ctrl-Shift-E... not sure what to do :(
* https://superuser.com/questions/358749/how-to-disable-ctrlshiftu-in-ubuntu-linux/1392682
*/
"default": `Ctrl+${modifier}+E`,
"mac": `Command+${modifier}+E`,
},
}


const action = {
"default_icon": "images/ic_not_visited_48.png",
"default_title": "Show promnesia sidebar",
}


const endpoints = (domain) => [
// TODO not sure if need to include api subpages?? seems like connect-src doesn't like /* in path component..
"http://" + domain + "/",
"https://" + domain + "/",
]


// prepare for manifest v3
const host_permissions = [
// broad permissions (*) are necessary for webNavigation to work
// otherwise we get "Cannot access contents of the page. Extension manifest must request permission to access the respective host."
'file:///*',
...endpoints('*'),
/* also note that if we have host permissions, we don't need tabs/activeTab permission to inject css/code
* this is necessary to call insertCss and executeScript
* note that just activeTab isn't enough because things aren't necessarily happening after user interaction like action
* e.g. sidebar/icon state is updating after webNavigation callback
*/
]
// FIXME not sure if need these considering it needs broad host permissions anyway?
const optional_host_permissions = endpoints('*')


// TODO make permissions literate
const permissions = [
// for keeping extension settings
"storage",

// receiving page status updates so extension kicks in on page loading
"webNavigation",

// uses context menu actions
"contextMenus",

// todo could be optional?
"notifications",

// used as one of the sources
// todo could be optional?
"bookmarks", // NOTE: isn't available on mobile

// to use local browsing history
// todo could be optional?
"history", // NOTE: isn't available on mobile
]


const optional_permissions = []

if (target === T.FIREFOX || v3) {
// chrome v2 doesn't support scripting api
// FIXME need to actually start using it
permissions.push("scripting")
}


const content_security_policy = [
"script-src 'self'", // this must be specified when overriding, otherwise it complains
/// also this works, but it seems that default-src somehow shadows style-src???
// "default-src 'self'",
// "style-src 'unsafe-inline'", // FFS, otherwise <style> directives on extension's pages not working??
///

// also need to override it to eclude 'upgrade-insecure-requests' in manifest v3?
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy#upgrade_insecure_network_requests_in_manifest_v3
// NOTE: could be connect-src http: https: to allow all?
// but we're specifically allowing endpoints that have /capture in them
"connect-src " + endpoints('*:*').join(' '),
].join('; ')


const background = {}
if (v3) {
if (target === T.CHROME) {
// webext lint will warn about this since it's not supported in firefox yet
background['service_worker'] = 'background.js'

// this isn't supported in chrome manifest v3 (chrome warns about unsupported field)
// but without it webext lint fails
background['scripts'] = ['background.js']
} else {
background['scripts'] = ['background.js']
}
} else {
background['scripts'] = ['background.js']
background['persistent'] = false
}
// hmm seems like it works in firefox v2 too, but NOT in chrome v2??
background['type'] = 'module'

const _resources = [
"sidebar.css", // injected in the sidebar
"*.js.map", // debugging symbols
]

const web_accessible_resources = v3 ? [{resources: _resources, matches: [ '*://*/*']}] : _resources

const manifest = {
name: pkg.name + (release ? '' : ' [dev]'),
version: pkg.version,
description: pkg.description,
permissions: permissions,
commands: commands, // NOTE: this doesn't have any effect on mobile
optional_permissions: optional_permissions,
manifest_version: v3 ? 3 : 2,
background: background,
icons: {
"48": "images/ic_not_visited_48.png",
},
options_ui: {
page: 'options_page.html',
open_in_tab: true,
},
web_accessible_resources: web_accessible_resources,
}
manifest[action_name] = action

if (target === T.FIREFOX) {
// NOTE: chrome v3 works without content_security_policy??
// but in firefox it refuses to make a request even when we allow hostname permission??
manifest.content_security_policy = (v3 ? {extension_pages: content_security_policy} : content_security_policy)
}

// this is only needed during testing
if (!publish) {
manifest.content_scripts = [{"matches": ["<all_urls>"], "js": ["selenium_bridge.js"]}]
}

// NOTE: this is only for mobile Firefox, we dynamically enable it in background page
// NOTE: chrome doesn't allow both page_action and browser_action in manifest
// https://stackoverflow.com/questions/7888915/why-i-cannot-use-two-or-more-browser-action-page-action-or-app-together
// for Firefox, it will also be deprecated in manifest v3 at some point? keeping for now just in case
// https://extensionworkshop.com/documentation/develop/manifest-v3-migration-guide/
if (target !== T.CHROME) {
manifest.page_action = {
default_icon: {
"48": "images/ic_visited_48.png"
},
default_title: "Promnesia",
}
}

if (v3) {
if (target === T.FIREFOX) {
// firefox doesn't support optional_host_permissions yet
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1766026
// and https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions#host_permissions
// note that these will still have to be granted by user (unlike in chrome)
manifest.host_permissions = host_permissions
manifest.optional_permissions.push(...optional_host_permissions)
} else {
manifest.host_permissions = host_permissions
manifest.optional_host_permissions = optional_host_permissions
}
} else {
manifest.permissions.push(...host_permissions)
manifest.optional_permissions.push(...optional_host_permissions)
}

if (target === T.FIREFOX || v3) {
// for firefox, this is required during publishing?
// this isn't really required in chrome, but without it, webext lint fails for chrome addon
const gecko_id = target === T.FIREFOX ? ext_id : '{00000000-0000-0000-0000-000000000000}'
manifest['browser_specific_settings'] = {
'gecko': {
'id': gecko_id,
},
}
}
return manifest
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* NOTE: I switched to rollup now, but keeping webpack config just for future reference
*/
const webpack = require('webpack'),
path = require('path'),
{CleanWebpackPlugin} = require('clean-webpack-plugin'),
Expand Down
Loading

0 comments on commit 45d6499

Please sign in to comment.