Skip to content

feat: add Lynx web platform support - #22

Open
Huxpro wants to merge 4 commits into
mainfrom
Huxpro/lynx-web-integration
Open

feat: add Lynx web platform support#22
Huxpro wants to merge 4 commits into
mainfrom
Huxpro/lynx-web-integration

Conversation

@Huxpro

@Huxpro Huxpro commented Mar 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add multi-environment rspeedy build config (web + lynx environments) so Sparkling apps can produce browser-compatible bundles alongside native ones
  • Create sparkling-web-shell package — minimal rsbuild web host that renders Lynx bundles via <lynx-view> custom element with @lynx-js/web-core and @lynx-js/web-elements
  • Add web method bridge (sparkling-method/web-registry) that dispatches pipe calls to browser-based handlers when NativeModules is unavailable
  • Implement web handlers for navigation (History API), storage (localStorage), and media (<input type="file">, fetch + blob download)
  • Add CLI support: run:web command, --platform web flag for dev/build/autolink
  • Add "Enable web platform?" prompt to create-sparkling-app
  • Add web platform documentation (guide, method implementations, limitations)

Test plan

  • Run cd packages/playground && pnpm build — verify dist/ has *.lynx.bundle and dist/web/ has web bundles
  • Run pnpm dev:web — verify playground renders at http://localhost:4200/
  • Test ?page=second, ?page=card-view, ?page=media-test query params
  • Verify native asset dirs (android/.../assets, ios/LynxResources) contain no web/ subdirectory
  • Verify storage methods work in browser (localStorage)
  • Verify navigation between pages works in browser
  • Run sparkling-app-cli run:web from playground to test CLI path
  • Run existing native builds to confirm no regressions

Huxpro added 4 commits March 4, 2026 22:26
Add multi-environment build config (web + lynx) to rspeedy so the
playground and template can produce browser-compatible bundles alongside
native ones. Web bundles output to dist/web/ and are served by a new
sparkling-web-shell package that renders them via <lynx-view>.

- Create packages/sparkling-web-shell with @lynx-js/web-core 0.19.8
  and @lynx-js/web-elements 0.11.3
- Add environments config to playground lynx.config.ts with separate
  distPath for web output
- Filter web/ dir from native asset copies
- Add build:web and dev:web scripts to playground
- Update template app.config.ts with matching environments config
…olink)

Add web platform support to sparkling-app-cli:
- New `run:web` command: autolink → build web → start web shell in browser
- `--platform` flag on `build` and `dev` commands (web/native/all)
- Web-aware `autolink`: generates `.sparkling/web-autolink.ts` with
  `import 'pkg/web'` for modules declaring web support
- `copy-assets` excludes `web/` subdirectory from native copies
- `doctor --platform web` checks for @lynx-js/web-core and web shell
- Updated types: `web` in PlatformConfig, MethodModuleConfig, AppConfig.paths
…entations

Add a web dispatch layer to sparkling-method so pipe calls route to
browser-native handlers when running in a web environment. Each method
package now exports a ./web subpath that registers handlers at import time.

- sparkling-method: web-registry.ts (registerWebMethod, isWebEnvironment),
  WebMethodHandler type, web intercept in LynxPipe.call() before NativeModules check
- sparkling-navigation/web: router.open (History API + CustomEvent), router.close
- sparkling-storage/web: getItem/setItem/removeItem via localStorage with namespacing
- sparkling-media/web: chooseMedia (file input), downloadFile (fetch+blob),
  uploadFile/uploadImage (FormData), saveDataURL (unsupported stub)
…b option

- Add web-registry to sparkling-method for dispatching pipe calls to
  browser-based handlers when NativeModules is unavailable
- Update sparkling-web-shell with onNativeModulesCall bridge and
  spkPipe Worker stub for web-core RPC
- Fix navigation web handler scheme parsing
- Add CLI run:web command and --platform web flag to dev/build/autolink
- Add web platform docs (guide, method implementations, limitations)
- Add "Enable web platform?" prompt to create-sparkling-app
- Add web sidebar entries to website rspress config
- Rebuild playground native bundles
@leeekyrie
leeekyrie marked this pull request as ready for review April 28, 2026 15:24
Huxpro referenced this pull request in Huxpro/sparkling Jul 12, 2026
Companion to the web platform port: the /web method handlers added by
upstream PR #22 shipped with no unit tests, which drops the
sparkling-navigation/storage/media coverage gates below threshold once
those files are collected. Add node jest tests that mock the browser
globals (window.history, localStorage, file input, fetch/FormData) and
exercise every handler branch, restoring the packages above their
coverage thresholds.

Kept separate so it can stack onto the web-support PR.
Huxpro pushed a commit to Huxpro/sparkling that referenced this pull request Jul 12, 2026
…d globalProps

Web-support improvements split out for a stacked PR onto the web platform
work (tiktok#22). The previous shell destroyed and re-created a
single <lynx-view> on every navigation, which cannot represent Sparkling's
native container stack (no state preservation on back, no lifecycle, no
globalProps). Now:

- router.open STACKS a new <lynx-view> (own Worker heap); the previous
  view stays alive hidden underneath — router.close / browser back pops
  it and reveals the previous view with state intact
- each view is injected with globalProps (containerID + queryItems parsed
  from its scheme) mirroring the native SDK's GlobalPropsUtils — required
  by anything that reads lynx.__globalProps on web, incl. sparkling-history
- viewAppeared/viewDisappeared GlobalEvents are sent on stack transitions,
  mirroring the native ViewEventUtils contract
- browser history entries carry the scheme stack in state; popstate
  reconciles the view stack (back pops live views, forward re-creates
  fresh heaps, reload rebuilds — matching native process-restore behavior)
- sparkling-navigation web handlers slim down to validated event dispatch
  (sparkling:navigate / sparkling:close); the shell owns stack + history
  bookkeeping like the native SDK owns the activity stack, and the open
  handler now honors the replace option (previously ignored)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARyWgB3243gQx1exWK61Qb
Huxpro pushed a commit to Huxpro/sparkling that referenced this pull request Jul 12, 2026
Port the Web method layer from tiktok#22 so Sparkling methods can run
in a browser (e.g. Lynx-on-web via @lynx-js/web-core), not just native.

- sparkling-method: a `web-registry` (`registerWebMethod` / `getWebMethodHandler`
  / `isWebEnvironment`), a `WebMethodHandler` type, a `./web-registry` export,
  and a `LynxPipe.call` web-handler dispatch (a no-op on native, where the
  registry is empty).
- sparkling-navigation / sparkling-storage / sparkling-media: `/web` handlers
  (router.open/close, storage get/set/remove, media choose/upload/download)
  behind a `./web` package export.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Si6NyRMutX8GJ5MuQ3BnfU
Huxpro pushed a commit to Huxpro/sparkling that referenced this pull request Jul 12, 2026
…d globalProps

Web-support improvements split out for a stacked PR onto the web platform
work (tiktok#22). The previous shell destroyed and re-created a
single <lynx-view> on every navigation, which cannot represent Sparkling's
native container stack (no state preservation on back, no lifecycle, no
globalProps). Now:

- router.open STACKS a new <lynx-view> (own Worker heap); the previous
  view stays alive hidden underneath — router.close / browser back pops
  it and reveals the previous view with state intact
- each view is injected with globalProps (containerID + queryItems parsed
  from its scheme) mirroring the native SDK's GlobalPropsUtils — required
  by anything that reads lynx.__globalProps on web, incl. sparkling-history
- viewAppeared/viewDisappeared GlobalEvents are sent on stack transitions,
  mirroring the native ViewEventUtils contract
- browser history entries carry the scheme stack in state; popstate
  reconciles the view stack (back pops live views, forward re-creates
  fresh heaps, reload rebuilds — matching native process-restore behavior)
- sparkling-navigation web handlers slim down to validated event dispatch
  (sparkling:navigate / sparkling:close); the shell owns stack + history
  bookkeeping like the native SDK owns the activity stack, and the open
  handler now honors the replace option (previously ignored)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARyWgB3243gQx1exWK61Qb
Huxpro pushed a commit to Huxpro/sparkling that referenced this pull request Jul 26, 2026
…queryItems

On native containers, scheme query params reach the opened page via
lynx.__globalProps.queryItems, and each container gets a containerID.
The web router.open handler dropped everything except the page name, so
pages like the nav-chain playground demo always saw depth=1.

- router.open (web): carry all non-reserved scheme params in the browser URL
- web shell: build globalProps { queryItems, containerID, containerInitTime,
  platform } per lynx-view, mirroring the native contract

Standalone web-support bugfix; can be extracted as a stacked PR onto the
web platform PR (tiktok#22).
Huxpro pushed a commit to Huxpro/sparkling that referenced this pull request Jul 26, 2026
Native router.open already supports options.replace (swap current page
instead of pushing). The web handler always did history.pushState, so
router.replace()/redirect()-style cross-page navigation left the previous
page on the stack (and could loop). Use history.replaceState when
options.replace (or a top-level replace flag) is set.

Standalone web-support bugfix; stacked-PR candidate onto tiktok#22.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant