Files
obsidian-vault/work/projects/vscode-migration/vscode-migration.md
T

82 lines
8.8 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VSCode/Cursor Builds & Debugging (macOS)
Status: **IN PROGRESS** · updated 2026-10-01
**Asana:** [Migration to fully VSCode-supported builds&debugging](https://app.asana.com/1/137249556945/project/1203301625297703/task/1209808486380252)
**Repo:** `~/DuckDuckGo/apple-browsers.git` (bare + worktrees)
**Findings:** [[projects/vscode-migration/findings]]
## Goal
Build, run and debug the macOS app from VSCode/Cursor: make most of the app
SPM-compatible, so `swift build` + SourceKit-LSP work, and configure
`.vscode` (tasks, launch).
## Status
| Step | Status |
|---|---|
| Move non-Swift code to local packages | ✅ Jun 2025 |
| Missing imports, unused files cleanup | ✅ Jun 2025 |
| Initial VSCode config | ✅ Jun 2025 (stale: `sweetpad` worktree) |
| Unify WebKit private methods (Sparkle/AppStore) | ✅ Feb 2026 |
| Drop `#if SPARKLE/APPSTORE` | ✅ Mar 2026 — DMG and App Store targets now compile the same 1398 files |
| Drop dead target flags (`SANDBOX_TEST_TOOL`, `ALPHA`, `NETWORK_EXTENSION` in shared files) | ✅ [#6983](https://github.com/duckduckgo/apple-browsers/pull/6983) |
| Replace sandbox-test-tool with App Store UI tests (`AppStoreSandboxUITests`, CI leg along full DMG runs) | ✅ [#6980](https://github.com/duckduckgo/apple-browsers/pull/6980) |
| Split app files shared with helper targets | 🔄 A+B in review ([#7029](https://github.com/duckduckgo/apple-browsers/pull/7029)), C ready — see [Target split stages](#target-split-stages) |
| Drop storyboards | 🔄 3 left on main: `Feedback`, `NavigationBar`, `PasswordManager` (`drop-sb-*` worktrees) |
| Core Data models in code | ❌ **Cancelled** 2026-10-01 — Xcode 27 builds these in SPM |
| Asset catalogs for `swift build` | ❌ **Cancelled** 2026-10-01 — Xcode 27 builds these in SPM |
| swift-build fork (Provisional Inputs) | ⏸ not started; may be unnecessary |
| Remote debugging (VMs, old hardware) | ⏸ not started |
| AI instructions, GitHub MCP subtasks | ⏸ not started |
## Open items after the cancellation
- [x] Closed PR [#6976](https://github.com/duckduckgo/apple-browsers/pull/6976) (AssetCatalogPlugin) and the Core Data PR; their worktrees are removed.
- [ ] Check what Xcode 27 actually does for `swift build` (native) and SourceKit-LSP: asset symbols, `.car`, `.momd`, storyboards? Earlier finding on Xcode 26: only `--build-system swiftbuild` handles assets, native doesn't. See [[projects/vscode-migration/findings#Asset catalogs]].
- [ ] Re-check whether storyboards still need dropping with Xcode 27.
## Plan (next steps)
1. **Extract files shared with helper targets into packages** — in progress, see [Target split stages](#target-split-stages). Started from 38 app files also compiled into VPN / PIR agent / NetP extensions. Dead flags are gone (#6983); unused memberships trimmed and stages A+B moved (#7029). The old draft `netp-dependencies` is superseded.
2. **Decide on strings & resources in the package** (tech design): 1964 `NSLocalizedString` without `bundle:` (→ `Bundle.main`), ~60 resource files, 8 `Bundle.main.url(…)`. `bundleIdentifier`/`appGroup` via `Bundle.main` can stay.
3. **App code as a library package** + thin app target (`AppMain`, Info.plist, entitlements, embed phases for login items / extensions).
4. **VSCode tasks with cached helper targets**: gate script hashes each extension's inputs (git-based, not mtime) and skips `xcodebuild` when unchanged; assemble step copies prebuilt extensions and signs. Only pays off once the app itself builds with `swift build`. See [[projects/vscode-migration/findings#Extensions in VSCode tasks]].
5. Convert ~57 string-name image lookups (`NSImage(named:)`, `Image("…")`) to asset symbols — they break once code moves to `Bundle.module`.
## Target split stages
Goal: no file in `macOS/DuckDuckGo/` is compiled into a helper target (VPN agent, PIR agent, NetP extensions), so the app directory can become one SPM target. `InputFilesChecker` tracks the remaining files in `temporarilyAllowedMisplacedFiles` (one block per stage); a stale entry fails the build, so each stage PR must remove its block.
| Stage | Files | Used by | Home | New deps / project changes | Size & blockers | PR |
|---|---|---|---|---|---|---|
| A | `ApplicationBuildType`, `BuildFlags`, `DuckDuckGoUserAgent` | app + all 6 helpers | `AppKitExtensions` | none (all targets already link it) | 46 imports | [#7029](https://github.com/duckduckgo/apple-browsers/pull/7029) |
| B | `DBPFeatureFlagger`, `DataBrokerAuthenticationManagerBuilder`, `DataBrokerProtectionSettings+Environment`, `WebViewUserAgentProvider`, `SafariVersionReader`, `WebKitVersionProvider` | app + PIR agent | `DataBrokerProtection-macOS` | none (`Subscription` comes transitively, like elsewhere in the package) | 5 imports | [#7029](https://github.com/duckduckgo/apple-browsers/pull/7029) |
| C | `NetworkProtectionPixelEvent` (569 loc) | app, VPN agent, 3 extensions | `NetworkProtectionMac` → `VPNPixels` (new library product) | `VPNPixels` += `VPN`, `Configuration`; BSK package dep; product linked to 7 targets | 9 imports. Ready, uncommitted (`move-vpn-pixel-event`) | own PR, on top of #7029 |
| D | `SubscriptionPixel`, `SubscriptionPixelHandler`, `SubscriptionEnvironment+Default`, `WideEventFeatureFlagAdapter`, `SubscriptionFunnelOrigin` (836 loc) | app, VPN agent, PIR agent, 3 extensions | new local package (no existing one is linked by all consumers) | `Subscription`, `PixelKit`, `Networking`, `PrivacyConfig`, `WideEvent`, `AppKitExtensions`; product linked to ~8 targets | used in ~134 files — biggest diff | own PR (new package, Subscription reviewers) |
| E1 | TipKit ×4, `VPNIPCResources`, `VPNOperationErrorRecorder`, `NetworkProtectionVPNCountryLabelsModel`, `VPNSettings+Environment` (~470 loc) | app + VPN agent | `NetworkProtectionMac` (IPC / UI, or a small `TipKitSupport` target) | `Subscription` for `VPNSettings+Environment` | moderate, no strings | combine with G |
| G | 10 helper-only sources living in `DuckDuckGo/` (`Bundle+VPN`, `NetworkProtectionOptionKeyExtension`, `NetworkProtectionControllerErrorStore`, `NetworkProtectionTunnelController`, `MacPacketTunnelProvider`, `MacTransparentProxyProvider`, `NetworkProtectionNotificationsPresenterFactory`, `VPNFailureRecoveryPixel`, `Bundle+NetworkProtectionExtensions`, `SubscriptionManager+StandardConfiguration`) | helpers only, never the app | helper-owned folders | `git mv` + pbxproj group paths only | small, noisy pbxproj | combine with E1 |
| E2 | `UserText+NetworkProtection+Shared`, `DefaultVPNLocationFormatter` | app + VPN agent | `NetworkProtectionUI` (has `Localizable.xcstrings`) | strings → `Bundle.module` with translations; app and VPN agent each have their own `UserText` | blocked on the strings/resources decision | combine with H |
| H | 4 app icons, `macos-config.json`, 7 VPN Lottie JSONs, 2 NetP `.xcstrings` | app + helpers | package resources or per-target copies | resource bundles / `Bundle.module` | same decision as E2 and the app-package tech design | with E2 |
| F | `UserDefaultsWrapper` (415 loc) + `UserDefaults+NetworkProtectionShared` | app, VPN agent, all extensions; ~51 app files | don't move — deprecated in favour of `KeyedStoring` | follows the KeyedStoring migration | blocked on that migration (owner/timeline TBD) | after the migration |
| X (optional) | `NETP_SYSTEM_EXTENSION` in `MacPacketTunnelProvider`, `MacTransparentProxyProvider`, `NetworkProtectionNotificationsPresenterFactory` | extensions only | runtime check `Bundle.main.bundleURL.pathExtension == "systemextension"` | removes the last `FEATURE_FLAGS` from xcconfigs | changes keychain service / defaults selection — needs VPN team review | optional, separate |
Order: C → D → E1+G → strings/resources tech design → E2+H → F after KeyedStoring. X any time if the VPN team agrees.
## Worktrees
| Worktree | Branch | What |
|---|---|---|
| `trim-target-memberships` | `alex/trim-target-memberships` | Stages A+B + membership trim, PR #7029 |
| `move-vpn-pixel-event` | `alex/move-vpn-pixel-event` | Stage C, uncommitted, on top of #7029 |
| `drop-sb-feedback`, `drop-sb-navigationbar`, `drop-sb-passwordmanager` | `alex/drop-*-storyboard` | Remaining storyboards |
| `coredata-spm-hacks-cleanup` | `alex/coredata-spm-hacks-cleanup` | no commits ahead of main yet |
| `netp-dependencies` | `alex/align-netp-dependencies` | Old draft: move files by target (superseded by the stages above) |
| `vscode`, `vscode2` | `alex/fix-imports-cleanup`, `alex/vscode2` | Old: SwiftGenPlugin draft (uncommitted), root `Package.swift` |
| `sweetpad` | `alex/cursor-fix-build` | Old `.vscode` (SweetPad) config |
Gone: `spm-asset-symbols-plugin`, `coredata-code-models*`, `drop-sb-bookmarksbar*` (BookmarksBar storyboard + xib are on main), `appstore-sandbox-ui-tests` (#6980), `drop-dead-target-flags` (#6983), `split-shared-target-files`.
Demo project for the (cancelled) asset approach: `~/Developer/SPMAssetSymbolsDemo` (`./verify.sh`).