Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions .github/ISSUE_TEMPLATE/safari-beta-bug.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Safari beta bug report
description: Report a bug from the macOS Safari TestFlight beta or local Safari beta validation flow.
title: "[Safari beta] "
body:
- type: markdown
attributes:
value: |
Please include the diagnostics report from `debug.html` whenever possible. Copy or download it from the extension first, then paste it below.

- type: input
id: macos_version
attributes:
label: macOS version
placeholder: "e.g. macOS 26.2"
validations:
required: true

- type: input
id: safari_version
attributes:
label: Safari version
placeholder: "e.g. Safari 18.4"
validations:
required: true

- type: input
id: res_version
attributes:
label: RES version or build
placeholder: "e.g. 5.24.8 beta / TestFlight build 3"
validations:
required: true

- type: dropdown
id: install_source
attributes:
label: Install source
options:
- TestFlight
- Local Xcode build
- Other
validations:
required: true

- type: dropdown
id: reddit_surface
attributes:
label: Where did the issue happen?
options:
- Old Reddit
- New Reddit
- Both
- Not tied to a Reddit page
validations:
required: true

- type: textarea
id: page_url
attributes:
label: Affected page or extension view
description: Paste the page URL or say `options.html`, `debug.html`, or another extension page.
placeholder: "https://old.reddit.com/r/test"
validations:
required: true

- type: textarea
id: repro_steps
attributes:
label: Reproduction steps
description: List the exact steps needed to reproduce the issue.
placeholder: |
1. Open ...
2. Click ...
3. Observe ...
validations:
required: true

- type: textarea
id: expected_behavior
attributes:
label: Expected behavior
placeholder: "What should have happened?"
validations:
required: true

- type: textarea
id: actual_behavior
attributes:
label: Actual behavior
placeholder: "What happened instead?"
validations:
required: true

- type: textarea
id: diagnostics_report
attributes:
label: Diagnostics report from debug.html
description: Paste the copied report, or explain why you could not capture one.
render: text
validations:
required: true

- type: textarea
id: additional_context
attributes:
label: Additional context
description: Screenshots, Xcode console output, permission prompts, or other extensions that may be relevant.
6 changes: 6 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<!-- e.g. "fixes #1234", see https://github.com/blog/1506-closing-issues-via-pull-requests -->
Relevant issue:
Tested in browser:

If this PR touches `lib/environment/`, browser manifests, or build target logic, complete this before marking it review-ready:

- [ ] Chrome smoke: injects on old Reddit, settings persist, toolbar style toggle works, `showImages` works, downloads remain managed, history-dependent behavior still works
- [ ] Firefox smoke: injects on old Reddit, settings persist, toolbar style toggle works, `showImages` works, downloads remain managed, history-dependent behavior still works, Firefox-specific auth/storage behavior still matches expectations
- [ ] Safari smoke (if applicable): use the Safari checklist in `CONTRIBUTING.md`
24 changes: 24 additions & 0 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,34 @@ jobs:
dist/zip/edge.zip
dist/zip/firefox.zip
dist/zip/opera.zip
dist/zip/safari.zip
prerelease: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

safari_validation:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: yarn install --frozen-lockfile

- run: yarn test
- run: yarn eslint
- run: yarn safari:validate
- run: tar -C dist -czf dist/zip/safari-xcode.tar.gz safari-xcode

- uses: actions/upload-artifact@v4
with:
name: safari-validation-artifacts
path: |
dist/zip/safari.zip
dist/zip/safari-xcode.tar.gz
if-no-files-found: error
retention-days: 7

windows:
runs-on: windows-latest
steps:
Expand Down
48 changes: 47 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ To load the extension into your browser, see [Loading RES into your browser](#lo

**`yarn build [--browsers <browsers>]`** will clean `dist/`, then build RES (release mode). Each build output will be compressed to a .zip file in `dist/zip/`.

`<browsers>` is a comma-separated list of browsers to target, e.g. `chrome,firefox`. `all` will build all targets. By default, `chrome` will be targeted.
`<browsers>` is a comma-separated list of browsers to target, e.g. `chrome,firefox,safari`. `all` will build all targets. By default, `chrome` will be targeted.

Safari builds emit a WebExtension bundle in `dist/safari/` and `dist/zip/safari.zip`. Packaging that bundle for distribution still requires Xcode on macOS.
For the broad public beta/TestFlight rollout, use [`docs/safari-public-beta.md`](docs/safari-public-beta.md) as the source of truth.

#### Lint and test commands

Expand Down Expand Up @@ -69,11 +72,53 @@ The default host and port (`localhost` and `4444`) should work for most local in
1. Click `Load Temporary Add-on` and select `/dist/firefox/manifest.json` (not the `/firefox` folder).
1. Any time you make changes, you must go back to the `about:debugging` page and `Reload` the extension.

##### Safari (macOS)

1. Install Xcode and its command line tools on macOS.
1. If the converter fails with `A required plugin failed to load`, run `xcodebuild -runFirstLaunch` once.
1. Run `yarn safari:validate` to build `dist/safari`, convert it into `dist/safari-xcode/`, patch the generated Xcode bundle identifiers, and verify that the app target can be built locally without signing.
1. If you need to sign the app locally with your own Apple team, rebuild with a unique base bundle ID first, for example `RES_SAFARI_BUNDLE_IDENTIFIER=com.<yourname>.redditenhancementsuitesafari yarn safari:validate`. The extension bundle ID is derived automatically as `<base>.extension`.
1. Open `/dist/safari-xcode/Reddit Enhancement Suite Safari/Reddit Enhancement Suite Safari.xcodeproj` in Xcode, run the containing app locally to enable the extension in Safari, and use Xcode for reload/debug cycles.
1. Public distribution goes through Apple's Safari Web Extension packaging flow and App Store Connect rather than the browser store automation used for Chrome and Firefox.
1. Broad public Safari testing should use TestFlight rather than GitHub artifacts; see [`docs/safari-public-beta.md`](docs/safari-public-beta.md).

Safari smoke checklist after the containing app is installed:

- Extension enables and injects on old Reddit.
- Options page opens and settings/translations load.
- Toolbar action still toggles subreddit CSS.
- `showImages` expands media and optional host-permission prompts still work.
- Download actions open the asset for manual save.
- History-dependent UI is absent or intentionally inert, without console errors.
- File backup/restore works.
- Cloud backup works for manual auth only, or the provider is intentionally hidden if manual auth fails.
- Private browsing does not crash the extension.
- If the options page is blank or the toolbar click does nothing, open `debug.html` inside the extension bundle to inspect persisted Safari runtime diagnostics and clear them between attempts.
- If you need to file a Safari bug, use the copy/download actions on `debug.html` and submit the report through the GitHub Safari beta issue template.

Known Safari gaps in the current port:

- No extension-managed browsing history; history-dependent filters and showImages history writes are disabled.
- No controlled extension downloads; Safari falls back to opening the asset in a new tab for manual save.
- Automatic cloud backups remain disabled until Safari background redirect auth is validated manually.
- Safari runtime diagnostics are enabled by default and stored in extension local storage until the port stabilizes.

#### Cross-browser regression smoke

If a change touches `lib/environment/`, browser manifests, or build target logic, do not mark the PR review-ready until this short smoke pass has been completed on the PR branch:

- Chrome on old Reddit: RES injects, settings save/reload, toolbar style toggle works on a styled subreddit, `showImages` expands media, downloads remain managed, and history-based behavior still works.
- Firefox on old Reddit: same smoke pass, plus Firefox-specific auth/storage behavior still matches expected pre-Safari behavior.
- Safari: keep the existing Safari smoke checklist above.

Chrome is the representative Chromium runtime for these checks. Edge and Opera only need build validation unless Chrome shows a regression.

## Project structure

#### Top level files and folders

- `.github/`: Github templates
- `docs/`: release and rollout documentation
- `browser/`: extension API files common to all browsers
- `build/`: files handling automated browser deployments
- `changelog/`: release changelogs
Expand All @@ -93,6 +138,7 @@ The default host and port (`localhost` and `4444`) should work for most local in
- `lib/vendor/`: RES vendor libraries (old libs not on npm)
- `lib/**/__tests__`: unit tests
- `locales`: RES i18n translations
- `safari/`: Safari-specific RES files
- `tests/`: integration tests
- `package.json`: package info, dependencies
- `build.js`: build script
Expand Down
17 changes: 15 additions & 2 deletions build.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ const targets = {
manifest: './chrome/manifest.json',
noSourcemap: true,
},
safari: {
browserName: 'safari',
browserMinVersion: '18.4',
manifest: './safari/manifest.json',
noSourcemap: true,
},
firefox: {
browserName: 'firefox',
browserMinVersion: '115.0',
Expand Down Expand Up @@ -70,22 +76,26 @@ const updatedURL /*: string */ = isBeta ?
`https://redditenhancementsuite.com/releases/beta/#v${version}` :
`https://redditenhancementsuite.com/releases/#v${version}`;
const homepageURL /*: string */ = packageInfo.homepage;
const repositoryURL /*: string */ = `https://github.com/${packageInfo.repository.username}/${packageInfo.repository.repository}`;
const safariBetaIssueURL /*: string */ = `${repositoryURL}/issues/new?template=safari-beta-bug.yml`;
// used for invalidating caches on each build (executed at build time)
// production builds uses version number to keep the build reproducible
const buildToken = isProduction ? version : devBuildToken;

async function buildForBrowser(targetName, { manifest, noSourceMap, browserName, browserMinVersion, browserMobileMinVersion }) {
async function buildForBrowser(targetName, { manifest, noSourcemap, browserName, browserMinVersion, browserMobileMinVersion }) {
const context = {
entryPoints: {
'foreground.entry': './lib/foreground.entry.js',
'background.entry': './lib/background.entry.js',
'debug.entry': './lib/debug/debug.entry.js',
'diagnosticsLink.entry': './lib/options/diagnosticsLink.entry.js',
'options.entry': './lib/options/options.entry.js',
'prompt.entry': './lib/environment/background/permissions/prompt.entry.js',
manifest,
options: './lib/options/options.scss',
res: './lib/css/res.scss',
},
sourcemap: !isProduction || !noSourceMap,
sourcemap: !isProduction || !noSourcemap,
outdir: `./dist/${targetName}/`,
bundle: true,
format: 'iife',
Expand Down Expand Up @@ -113,6 +123,8 @@ async function buildForBrowser(targetName, { manifest, noSourceMap, browserName,
'process.env.isMajor': `"${isMajor.toString()}"`,
'process.env.updatedURL': `"${updatedURL}"`,
'process.env.homepageURL': `"${homepageURL}"`,
'process.env.repositoryURL': `"${repositoryURL}"`,
'process.env.safariBetaIssueURL': `"${safariBetaIssueURL}"`,
},
plugins: [
{
Expand All @@ -138,6 +150,7 @@ async function buildForBrowser(targetName, { manifest, noSourceMap, browserName,
{ from: ['./images/css-on.png'], to: ['./'] },
{ from: ['./images/icon128.png'], to: ['./'] },
{ from: ['./images/icon48.png'], to: ['./'] },
{ from: ['./lib/debug/debug.html'], to: ['./'] },
{ from: ['./lib/environment/background/permissions/prompt.html'], to: ['./'] },
{ from: ['./lib/options/options.html'], to: ['./'] },
{ from: ['./node_modules/dashjs/dist/dash.mediaplayer.min.js'], to: ['./'] },
Expand Down
Loading