Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5176301116 |
90
Makefile
90
Makefile
@@ -22,16 +22,19 @@
|
|||||||
# Makefile for logsdu - build the extension for Firefox and Chrome.
|
# Makefile for logsdu - build the extension for Firefox and Chrome.
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# make # typecheck and bundle for Firefox into build/
|
# make # everything: build and package both browsers
|
||||||
# make chrome # same, but with Chrome's manifest, into build/
|
# make firefox # build Firefox only -> build/firefox/
|
||||||
|
# make chrome # build Chrome only -> build/chrome/
|
||||||
# make test # run the unit tests
|
# make test # run the unit tests
|
||||||
# make smoke # check the background bundle works as a service worker
|
# make smoke # check the background bundle works as a service worker
|
||||||
# make xpi # package the Firefox build -> dist/logsdu-<version>.xpi
|
# make xpi # package Firefox -> dist/logsdu-<version>-firefox.xpi
|
||||||
# make crx # package the Chrome build -> dist/logsdu-<version>-chrome.zip
|
# make crx # package Chrome -> dist/logsdu-<version>-chrome.zip
|
||||||
# make packages # both of the above
|
# make packages # both of the above (same as plain "make")
|
||||||
# make clean # remove build/ and dist/
|
# make clean # remove build/, dist/ and stray packages
|
||||||
|
# make distclean # clean, plus node_modules/
|
||||||
#
|
#
|
||||||
# build/ holds the unpacked extension and is regenerated from scratch; dist/
|
# build/<target>/ holds the unpacked extension for one browser; the two targets
|
||||||
|
# never share a directory, so neither can be left stale by the other. dist/
|
||||||
# holds the packages meant to be published, and is kept out of build/ so that
|
# holds the packages meant to be published, and is kept out of build/ so that
|
||||||
# packaging never tries to include its own output.
|
# packaging never tries to include its own output.
|
||||||
#
|
#
|
||||||
@@ -40,22 +43,33 @@
|
|||||||
#
|
#
|
||||||
# Load the unpacked build while developing:
|
# Load the unpacked build while developing:
|
||||||
# Firefox about:debugging -> This Firefox -> Load Temporary Add-on ->
|
# Firefox about:debugging -> This Firefox -> Load Temporary Add-on ->
|
||||||
# build/manifest.json (dropped when Firefox restarts)
|
# build/firefox/manifest.json (dropped when Firefox restarts)
|
||||||
# Chrome chrome://extensions -> Developer mode -> Load unpacked -> build/
|
# Chrome chrome://extensions -> Developer mode -> Load unpacked ->
|
||||||
|
# build/chrome/
|
||||||
#
|
#
|
||||||
# Publishing:
|
# Publishing:
|
||||||
# Firefox upload dist/*.xpi at addons.mozilla.org
|
# Firefox upload dist/*-firefox.xpi at addons.mozilla.org
|
||||||
# Chrome upload dist/*-chrome.zip at chrome.google.com/webstore/devconsole
|
# Chrome upload dist/*-chrome.zip at chrome.google.com/webstore/devconsole
|
||||||
|
#
|
||||||
|
# Every package filename names its browser. The two are not interchangeable --
|
||||||
|
# they differ in the manifest's background key -- and uploading the wrong one
|
||||||
|
# fails in ways that are not obvious from the error.
|
||||||
|
|
||||||
EXT_ID := logsdu
|
EXT_ID := logsdu
|
||||||
VERSION := $(shell node -p "require('./package.json').version")
|
VERSION := $(shell node -p "require('./package.json').version")
|
||||||
|
FIREFOX_DIR := build/firefox
|
||||||
|
CHROME_DIR := build/chrome
|
||||||
DIST := dist
|
DIST := dist
|
||||||
XPI := $(DIST)/$(EXT_ID)-$(VERSION).xpi
|
XPI := $(DIST)/$(EXT_ID)-$(VERSION)-firefox.xpi
|
||||||
CRX := $(DIST)/$(EXT_ID)-$(VERSION)-chrome.zip
|
CRX := $(DIST)/$(EXT_ID)-$(VERSION)-chrome.zip
|
||||||
|
|
||||||
.PHONY: all build chrome test smoke xpi crx packages clean check-deps
|
.PHONY: all firefox chrome typecheck test smoke xpi crx packages clean \
|
||||||
|
distclean check-deps
|
||||||
|
|
||||||
all: build
|
# The default does the lot: build both browsers and package both. Packaging is
|
||||||
|
# only a zip of a directory that was going to be built anyway, so making it the
|
||||||
|
# default costs nothing and means dist/ is never quietly out of date with src/.
|
||||||
|
all: packages
|
||||||
|
|
||||||
# Unit tests for the pure logic: the input formatters and the decision that
|
# Unit tests for the pure logic: the input formatters and the decision that
|
||||||
# says whether a page load may press "Entrar". Run straight through Node's
|
# says whether a page load may press "Entrar". Run straight through Node's
|
||||||
@@ -64,30 +78,40 @@ test:
|
|||||||
node --test "src/**/*.test.ts"
|
node --test "src/**/*.test.ts"
|
||||||
|
|
||||||
# Runs the built background bundle in a service-worker-shaped sandbox, which
|
# Runs the built background bundle in a service-worker-shaped sandbox, which
|
||||||
# is where a Chrome-only breakage would otherwise hide until runtime.
|
# is where a Chrome-only breakage would otherwise hide until runtime. The
|
||||||
smoke: build
|
# bundle is identical for both targets, so checking one covers both.
|
||||||
node tools/sw-smoke.mjs
|
smoke: chrome
|
||||||
|
node tools/sw-smoke.mjs $(CHROME_DIR)/background.js
|
||||||
|
|
||||||
# Call the local toolchain directly, so this works regardless of how pnpm is
|
# Typecheck once. Both build targets depend on it rather than each running tsc,
|
||||||
|
# which halves the work when building both.
|
||||||
|
#
|
||||||
|
# Calls the local toolchain directly, so this works regardless of how pnpm is
|
||||||
# provided (corepack vs standalone). Run "corepack pnpm install" first.
|
# provided (corepack vs standalone). Run "corepack pnpm install" first.
|
||||||
build: check-deps
|
typecheck: check-deps
|
||||||
node_modules/.bin/tsc -noEmit -skipLibCheck
|
node_modules/.bin/tsc -noEmit -skipLibCheck
|
||||||
|
|
||||||
|
firefox: typecheck
|
||||||
node esbuild.config.mjs production
|
node esbuild.config.mjs production
|
||||||
|
@echo "Firefox build: $(CURDIR)/$(FIREFOX_DIR)"
|
||||||
|
|
||||||
# The same sources with Chrome's manifest. Firefox and Chrome disagree on the
|
# The same sources with Chrome's manifest. Firefox and Chrome disagree on the
|
||||||
# background key and on the gecko block, so the manifest is generated per
|
# background key and on the gecko block, so the manifest is generated per
|
||||||
# target rather than forked.
|
# target rather than forked.
|
||||||
chrome: check-deps
|
chrome: typecheck
|
||||||
node_modules/.bin/tsc -noEmit -skipLibCheck
|
|
||||||
TARGET=chrome node esbuild.config.mjs production
|
TARGET=chrome node esbuild.config.mjs production
|
||||||
@echo "Chrome build in build/ -- chrome://extensions -> Developer mode -> Load unpacked."
|
@echo
|
||||||
|
@echo "Chrome build: $(CURDIR)/$(CHROME_DIR)"
|
||||||
|
@echo "Load it with chrome://extensions -> Developer mode -> Load unpacked."
|
||||||
|
@echo "Select the folder itself; Chrome wants the directory holding manifest.json."
|
||||||
|
@echo
|
||||||
|
|
||||||
# An .xpi is just a zip of the extension directory, with the manifest at the
|
# An .xpi is just a zip of the extension directory, with the manifest at the
|
||||||
# top level rather than inside a wrapper folder.
|
# top level rather than inside a wrapper folder.
|
||||||
xpi: build
|
xpi: firefox
|
||||||
@mkdir -p $(DIST)
|
@mkdir -p $(DIST)
|
||||||
rm -f $(XPI)
|
rm -f $(XPI)
|
||||||
cd build && zip -qr ../$(XPI) .
|
cd $(FIREFOX_DIR) && zip -qr $(CURDIR)/$(XPI) .
|
||||||
@echo
|
@echo
|
||||||
@echo "Built: $(CURDIR)/$(XPI)"
|
@echo "Built: $(CURDIR)/$(XPI)"
|
||||||
@echo
|
@echo
|
||||||
@@ -108,18 +132,30 @@ xpi: build
|
|||||||
crx: chrome
|
crx: chrome
|
||||||
@mkdir -p $(DIST)
|
@mkdir -p $(DIST)
|
||||||
rm -f $(CRX)
|
rm -f $(CRX)
|
||||||
cd build && zip -qr ../$(CRX) .
|
cd $(CHROME_DIR) && zip -qr $(CURDIR)/$(CRX) .
|
||||||
@echo
|
@echo
|
||||||
@echo "Built: $(CURDIR)/$(CRX)"
|
@echo "Built: $(CURDIR)/$(CRX)"
|
||||||
@echo "Upload it at chrome.google.com/webstore/devconsole"
|
@echo "Upload it at chrome.google.com/webstore/devconsole"
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
# Both packages. The Firefox build runs last so build/ is left in the state
|
# Both packages. Order no longer matters: each target has its own directory.
|
||||||
# the development instructions assume.
|
packages: xpi crx
|
||||||
packages: crx xpi
|
|
||||||
|
|
||||||
|
# Removes everything the build produces, including packages from earlier
|
||||||
|
# versions, whose filenames carry their own version number and so are never
|
||||||
|
# overwritten by a later build. dist/ is tracked in git, so a clean shows the
|
||||||
|
# packages as deleted until the next "make packages" puts them back.
|
||||||
clean:
|
clean:
|
||||||
rm -rf build $(DIST)
|
rm -rf build $(DIST)
|
||||||
|
rm -f $(EXT_ID)-*.xpi $(EXT_ID)-*.zip
|
||||||
|
find . -name '*.map' -not -path './node_modules/*' -delete
|
||||||
|
@echo "Removed build/, $(DIST)/ and any stray packages."
|
||||||
|
|
||||||
|
# Everything clean removes, plus the installed dependencies. Recover with
|
||||||
|
# "corepack pnpm install" -- never with npm, see the note in README.md.
|
||||||
|
distclean: clean
|
||||||
|
rm -rf node_modules
|
||||||
|
@echo "Removed node_modules/. Run: corepack pnpm install"
|
||||||
|
|
||||||
# Fail with a useful message rather than a confusing "tsc: not found".
|
# Fail with a useful message rather than a confusing "tsc: not found".
|
||||||
check-deps:
|
check-deps:
|
||||||
|
|||||||
32
README.md
32
README.md
@@ -19,7 +19,7 @@ Once it is published, from addons.mozilla.org. Until then, build it yourself:
|
|||||||
|
|
||||||
```
|
```
|
||||||
corepack pnpm install # first time, or after a dependency change
|
corepack pnpm install # first time, or after a dependency change
|
||||||
make xpi # typecheck, bundle, and package dist/logsdu-<version>.xpi
|
make xpi # bundle and package dist/logsdu-<version>-firefox.xpi
|
||||||
```
|
```
|
||||||
|
|
||||||
`make xpi` prints the full path of the file and how to install it. The package
|
`make xpi` prints the full path of the file and how to install it. The package
|
||||||
@@ -119,12 +119,12 @@ check.
|
|||||||
## Chrome
|
## Chrome
|
||||||
|
|
||||||
```
|
```
|
||||||
make chrome # unpacked Chrome build in build/
|
make chrome # unpacked Chrome build in build/chrome/
|
||||||
make crx # package it as dist/logsdu-<version>-chrome.zip
|
make crx # package it as dist/logsdu-<version>-chrome.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
Load `build/` via `chrome://extensions` -> Developer mode -> **Load unpacked**,
|
Load `build/chrome/` via `chrome://extensions` -> Developer mode -> **Load
|
||||||
or upload the zip at
|
unpacked** (select the folder itself), or upload the zip at
|
||||||
[the Web Store dashboard](https://chrome.google.com/webstore/devconsole).
|
[the Web Store dashboard](https://chrome.google.com/webstore/devconsole).
|
||||||
|
|
||||||
One codebase, two manifests. Chrome MV3 requires a background *service worker*
|
One codebase, two manifests. Chrome MV3 requires a background *service worker*
|
||||||
@@ -156,21 +156,29 @@ script instead.
|
|||||||
|
|
||||||
```
|
```
|
||||||
corepack pnpm install
|
corepack pnpm install
|
||||||
|
make # everything: build and package both browsers
|
||||||
|
make firefox # build Firefox only -> build/firefox/
|
||||||
|
make chrome # build Chrome only -> build/chrome/
|
||||||
make test # unit tests
|
make test # unit tests
|
||||||
make smoke # background bundle under a service worker
|
make smoke # background bundle under a service worker
|
||||||
make # typecheck and bundle into build/
|
corepack pnpm run dev # rebuild Firefox on change
|
||||||
make packages # both publishable packages into dist/
|
make clean # remove build/, dist/ and stray packages
|
||||||
corepack pnpm run dev # rebuild on change
|
make distclean # clean, plus node_modules/
|
||||||
make clean
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`build/` is the unpacked extension and is regenerated from scratch every time.
|
A bare `make` typechecks once, bundles for both browsers into `build/`, and
|
||||||
`dist/` holds the packages meant to be published, and is kept separate so that
|
packages both into `dist/`. Packaging is only a zip of a directory that was
|
||||||
packaging never tries to include its own output.
|
going to be built anyway, so it costs nothing and keeps `dist/` from drifting
|
||||||
|
out of step with the sources.
|
||||||
|
|
||||||
|
Each browser gets its own directory under `build/`, so the two can coexist and
|
||||||
|
neither is ever left stale by the other. `dist/` holds the packages meant to be
|
||||||
|
published, and is kept out of `build/` so that packaging never tries to include
|
||||||
|
its own output.
|
||||||
|
|
||||||
While iterating, load the unpacked directory rather than reinstalling an `.xpi`
|
While iterating, load the unpacked directory rather than reinstalling an `.xpi`
|
||||||
each time: `about:debugging` -> **This Firefox** -> **Load Temporary Add-on** ->
|
each time: `about:debugging` -> **This Firefox** -> **Load Temporary Add-on** ->
|
||||||
`build/manifest.json`, then press **Reload** there after each rebuild. That copy
|
`build/firefox/manifest.json`, then press **Reload** there after each rebuild. That copy
|
||||||
disappears on restart, which is the point -- it is for development, not daily
|
disappears on restart, which is the point -- it is for development, not daily
|
||||||
use.
|
use.
|
||||||
|
|
||||||
|
|||||||
BIN
dist/logsdu-0.3.0-chrome.zip
vendored
BIN
dist/logsdu-0.3.0-chrome.zip
vendored
Binary file not shown.
BIN
dist/logsdu-0.3.0.xpi
vendored
BIN
dist/logsdu-0.3.0.xpi
vendored
Binary file not shown.
@@ -35,12 +35,17 @@ const banner = `/*
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const prod = process.argv[2] === 'production';
|
const prod = process.argv[2] === 'production';
|
||||||
const outdir = 'build';
|
|
||||||
|
|
||||||
// Target browser. Firefox and Chrome disagree on exactly one manifest key, so
|
// Target browser. Firefox and Chrome disagree on exactly one manifest key, so
|
||||||
// the manifest is written per target rather than duplicated in the tree.
|
// the manifest is written per target rather than duplicated in the tree.
|
||||||
const target = process.env.TARGET === 'chrome' ? 'chrome' : 'firefox';
|
const target = process.env.TARGET === 'chrome' ? 'chrome' : 'firefox';
|
||||||
|
|
||||||
|
// Each target gets its own directory. They used to share one, and the result
|
||||||
|
// was that whichever build ran last silently won: loading the other browser's
|
||||||
|
// output then failed with a confusing manifest error. Separate directories
|
||||||
|
// mean both can exist at once and neither can be stale by accident.
|
||||||
|
const outdir = `build/${target}`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the manifest for the target browser.
|
* Write the manifest for the target browser.
|
||||||
*
|
*
|
||||||
@@ -60,8 +65,9 @@ async function writeManifest() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything that is not TypeScript is copied verbatim into build/, so that
|
// Everything that is not TypeScript is copied verbatim into the output, so
|
||||||
// the directory can be handed straight to about:debugging.
|
// that the directory can be handed straight to about:debugging or to Chrome's
|
||||||
|
// "Load unpacked".
|
||||||
async function copyStatic() {
|
async function copyStatic() {
|
||||||
await mkdir(outdir, { recursive: true });
|
await mkdir(outdir, { recursive: true });
|
||||||
for (const name of await readdir('src')) {
|
for (const name of await readdir('src')) {
|
||||||
@@ -76,7 +82,7 @@ async function copyStatic() {
|
|||||||
await copyStatic();
|
await copyStatic();
|
||||||
|
|
||||||
// In watch mode the static files must follow every rebuild, otherwise editing
|
// In watch mode the static files must follow every rebuild, otherwise editing
|
||||||
// manifest.json or a .html file silently changes nothing in build/.
|
// manifest.json or a .html file silently changes nothing in the output.
|
||||||
const staticPlugin = {
|
const staticPlugin = {
|
||||||
name: 'copy-static',
|
name: 'copy-static',
|
||||||
setup(build) {
|
setup(build) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "logsdu",
|
"name": "logsdu",
|
||||||
"version": "0.3.0",
|
"version": "0.3.1",
|
||||||
"description": "Browser extension that fills and submits a three-field academic portal login.",
|
"description": "Browser extension that fills and submits a three-field academic portal login.",
|
||||||
"author": "Ruben Carlo Benante <rcb@beco.cc>",
|
"author": "Ruben Carlo Benante <rcb@beco.cc>",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "logsdu",
|
"name": "logsdu",
|
||||||
"version": "0.3.0",
|
"version": "0.3.1",
|
||||||
"description": "Saves and fills logins that password managers cannot: registration number, date of birth and document number.",
|
"description": "Saves and fills logins that password managers cannot: registration number, date of birth and document number.",
|
||||||
"author": "Ruben Carlo Benante (Dr. Beco)",
|
"author": "Ruben Carlo Benante (Dr. Beco)",
|
||||||
"homepage_url": "https://code.beco.cc/beco/logsdu",
|
"homepage_url": "https://code.beco.cc/beco/logsdu",
|
||||||
|
|||||||
@@ -29,14 +29,15 @@
|
|||||||
//
|
//
|
||||||
// This evaluates the built bundle in a worker-shaped sandbox with a stubbed
|
// This evaluates the built bundle in a worker-shaped sandbox with a stubbed
|
||||||
// extension API, and asserts that it registers exactly one content script, for
|
// extension API, and asserts that it registers exactly one content script, for
|
||||||
// exactly the configured origin. Run it against build/ after a build:
|
// exactly the configured origin.
|
||||||
//
|
//
|
||||||
// make smoke
|
// make smoke
|
||||||
|
// node tools/sw-smoke.mjs [path/to/background.js]
|
||||||
|
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import vm from 'node:vm';
|
import vm from 'node:vm';
|
||||||
|
|
||||||
const BUNDLE = 'build/background.js';
|
const BUNDLE = process.argv[2] ?? 'build/chrome/background.js';
|
||||||
const CONFIGURED_ORIGIN = 'https://portal.example.br';
|
const CONFIGURED_ORIGIN = 'https://portal.example.br';
|
||||||
|
|
||||||
const permissionChecks = [];
|
const permissionChecks = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user