Skip to content
Open
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
14 changes: 7 additions & 7 deletions docs/en/apis/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@

APIs for Lynx bundles running inside Sparkling containers.

| API | Description |
| --- | --- |
| [GlobalProps](/apis/global-props/Interface.GlobalProps) | Runtime globals injected by the native SDK (`lynx.__globalProps`) |
| [Scheme](/apis/scheme) | The unified `hybrid://...` URL format for opening pages/containers |
| [Navigation](/apis/sparkling-methods/sparkling-navigation) | Router helpers for opening/closing pages from Lynx/JS |
| [Storage](/apis/sparkling-methods/sparkling-storage) | Key-value storage helpers for Lynx/JS |
| [Media](/apis/sparkling-methods/sparkling-media) | Media helpers for choosing, uploading, downloading, and saving files |
| API | Description | Web |
| --- | --- | --- |
| [GlobalProps](/apis/global-props/Interface.GlobalProps) | Runtime globals injected by the native SDK (`lynx.__globalProps`) | - |
| [Scheme](/apis/scheme) | The unified `hybrid://...` URL format for opening pages/containers | - |
| [Navigation](/apis/sparkling-methods/sparkling-navigation) | Router helpers for opening/closing pages from Lynx/JS | Yes |
| [Storage](/apis/sparkling-methods/sparkling-storage) | Key-value storage helpers for Lynx/JS | Yes |
| [Media](/apis/sparkling-methods/sparkling-media) | Media helpers for choosing, uploading, downloading, and saving files | Yes |

## Sparkling SDK

Expand Down
30 changes: 28 additions & 2 deletions docs/en/guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ npx sparkling build
| Option | Description |
| --- | --- |
| `--config <path>` | Path to `app.config.ts` (default: `app.config.ts`) |
| `--platform <platform>` | Target platform: `android`, `ios`, `web`, or `all` (default: `all`) |
| `--copy` | Copy built assets to Android and iOS native shells |
| `--skip-copy` | Skip copying assets (default) |

By default, asset copying is skipped for faster iteration during development. Use `--copy` when you need the bundles inside the native projects (e.g. for a release build).

When `--platform web` is specified, only web bundles (`*.web.bundle`) are produced. This is faster than building all environments.

### `sparkling dev`

Start the Rspeedy dev server for hot-reload development. Instead of rebuilding and copying bundles manually, the dev server serves bundles over HTTP so changes are reflected instantly.
Expand All @@ -41,6 +44,7 @@ npx sparkling dev
| Option | Description |
| --- | --- |
| `--config <path>` | Path to `app.config.ts` (default: `app.config.ts`) |
| `--platform <platform>` | Target platform: `web`, `native`, or `all` (default: `all`) |
| `--port <number>` | Dev server port (default: `app.config.ts -> dev.server.port`, fallback `5969`) |
| `--host <host>` | Dev server host (default: `app.config.ts -> dev.server.host`, then Rspeedy default) |

Expand Down Expand Up @@ -81,12 +85,13 @@ npx sparkling autolink

| Option | Description |
| --- | --- |
| `--platform <platform>` | Platform to autolink: `android`, `ios`, or `all` (default: `all`) |
| `--platform <platform>` | Platform to autolink: `android`, `ios`, `web`, or `all` (default: `all`) |

**What it does:**

- **Android** — Links Sparkling method Gradle projects and generates `SparklingAutolink.kt`. Debug-tool packages are linked as `debugImplementation`.
- **iOS** — Links Sparkling method pods and generates `SparklingAutolink.swift`. Debug-tool packages are linked in the debug target.
- **Web** — Reads `web` entries from each `module.config.json` and generates a `web-autolink.ts` file that imports all `*/web` method handlers.

### `sparkling run:android`

Expand Down Expand Up @@ -140,6 +145,24 @@ This command will:

You can also set the `SPARKLING_IOS_SIMULATOR` environment variable to specify a default simulator.

### `sparkling run:web`

Build web bundles and launch a browser preview.

```bash
npx sparkling run:web
```

This command will:

1. Build web bundles (`*.web.bundle`)
2. Start the `sparkling-web-shell` dev server
3. Open the app in your default browser at `http://localhost:3000`

Use `?page=<name>` query parameters to navigate to different entry points (e.g. `http://localhost:3000?page=second`).

For more details, see the [Web Platform Guide](/guide/web-platform).

### `sparkling doctor`

Verify that your development environment is properly set up.
Expand Down Expand Up @@ -196,6 +219,9 @@ npx sparkling run:android
# 5. Run on iOS
npx sparkling run:ios

# 6. Build bundles for release
# 6. Preview in browser
npx sparkling run:web

# 7. Build bundles for release
npx sparkling build --copy
```
11 changes: 11 additions & 0 deletions docs/en/guide/get-started/create-custom-method.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,17 @@ npx sparkling autolink

</Steps>

## Add web support (optional)

You can add a web implementation so your method works in the browser. See the full guide at [Web Method Implementations](/guide/web-method-implementations).

In brief:

1. Create `src/web/index.ts` with `registerWebMethod()` calls
2. Add `"./web"` subpath export to `package.json`
3. Add `"web"` to `platforms` in `module.config.json`
4. Run `npx sparkling autolink`

## Best practices

- **Naming convention**: package name should follow `sparkling-<module>` format.
Expand Down
8 changes: 6 additions & 2 deletions docs/en/guide/get-started/create-new-app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ npm create sparkling-app@latest my-app
cd my-app
```

### Run native targets
### Run on any platform

```bash
# Android
npm run run:android

# iOS
npm run run:ios

# Web (browser preview)
npm run run:web
```

### Add Sparkling methods as needed
Expand All @@ -48,6 +51,7 @@ npx sparkling build

- A Lynx app project (based on the default template)
- Android and iOS native shells already wired for Sparkling
- Web platform support for browser previews (enabled by default)
- A working JS ↔ native pipe method example (router)
- Developer workflow commands (build / autolink / run)

Expand All @@ -56,7 +60,7 @@ Key folders/files created by the default template:
- `src/`: Lynx/React entry points and assets
- `android/`, `ios/`: native shells wired to Sparkling SDK
- `app.config.ts`: build + routing config consumed by `sparkling-app-cli`
- `package.json`: scripts (`dev`, `build`, `run:android`, `run:ios`)
- `package.json`: scripts (`dev`, `build`, `run:android`, `run:ios`, `run:web`)

### Prerequisites

Expand Down
62 changes: 62 additions & 0 deletions docs/en/guide/web-limitations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Web Limitations

The web platform provides a convenient development and preview environment, but has differences from the native Android/iOS platforms. This page documents known limitations.

## Rendering

- **DOM-based rendering**: `@lynx-js/web-core` renders Lynx components as custom HTML elements in the DOM, rather than using a native view hierarchy. CSS behavior follows browser standards, which may differ from Lynx's native layout engine in edge cases.
- **Performance**: For complex UIs with many elements or animations, native rendering will generally be faster. The web platform is best suited for development previews, not performance-critical production use.

## Native Bridge

- **`NativeModules` is unavailable**: On web, the Lynx `NativeModules` global does not exist. All method calls must go through the [web handler registry](/guide/web-method-implementations).
- **Unregistered methods**: Methods without a web handler return error code `-3` (module not registered). Check which methods have web handlers in the [built-in methods table](/guide/web-method-implementations#built-in-web-methods).

## Storage

- **Not encrypted**: `localStorage` is not encrypted, unlike native secure storage options. Do not store sensitive data (tokens, credentials) via `storage.*` methods on web in production.
- **Size limit**: `localStorage` has a ~5 MB per-origin limit in most browsers. Native storage does not have this restriction.
- **Synchronous**: `localStorage` operations are synchronous and block the main thread. For large datasets, this can cause jank.

## Media

- **Camera access**: `media.chooseMedia` with a camera source requires HTTPS. On `http://localhost` during development, camera access may be allowed by the browser, but in production, HTTPS is required.
- **File downloads**: `media.downloadFile` uses `fetch()` and is subject to CORS restrictions. The target URL must include appropriate CORS headers, or the download will fail.
- **File type filtering**: Browser `<input type="file">` accept filters are hints — users can override them and select any file type.

## Network

- **CORS**: All `fetch()` calls from the browser are subject to Cross-Origin Resource Sharing (CORS) policies. APIs that work from native (which has no CORS) may fail from web without server-side CORS headers.
- **Cookies**: Cookie handling differs between browser and native HTTP clients. Session management may behave differently on web.

## Device APIs

The following native capabilities are not available on web unless the browser provides equivalent APIs with user permission:

- Geolocation (available via browser Geolocation API, requires HTTPS)
- Push notifications (available via browser Push API, requires service worker)
- Biometric authentication (not available)
- App-level deep linking (not applicable in browser context)
- Background processing (limited to service workers)

## Feature Detection

Write platform-aware code using error handling:

```ts
import { callAsync } from 'sparkling-method';

try {
const result = await callAsync('nativeOnly.feature', params);
// Use native result
} catch (e) {
if (e.code === -2 || e.code === -3) {
// Not available on this platform
// Show alternative UI or skip the feature
}
}
```

Error codes:
- `-2`: `NativeModules` not available (running on web without a handler)
- `-3`: Module not registered (no web handler for this method)
147 changes: 147 additions & 0 deletions docs/en/guide/web-method-implementations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Web Method Implementations

Sparkling method SDKs (navigation, storage, media) communicate with the native layer via `NativeModules` on Android/iOS. On web, `NativeModules` is unavailable — instead, a **web handler registry** dispatches method calls to browser-native implementations.

## How It Works

```
App code → LynxPipe.call('router.open', params)
sparkling-method detects web environment
Web handler registry lookup by method name
Browser-native implementation (History API, localStorage, etc.)
```

When `LynxPipe.call()` runs on the web:

1. It checks if `NativeModules` is available — on web, it isn't.
2. Before returning an error, it looks up the method name in the **web handler registry**.
3. If a handler is registered, it's invoked with the same params and callback.
4. If no handler is found, it returns error code `-3` (module not registered).

## Built-in Web Methods

### Navigation (`sparkling-navigation`)

| Method | Web Implementation | Notes |
|--------|-------------------|-------|
| `router.open` | Parses the `hybrid://` scheme, extracts the bundle name, uses the History API and fires a `CustomEvent` to swap the `<lynx-view>` URL | Full scheme parameter support |
| `router.close` | `window.history.back()` | |

### Storage (`sparkling-storage`)

| Method | Web Implementation | Notes |
|--------|-------------------|-------|
| `storage.getItem` | `localStorage.getItem()` | 5 MB per-origin limit |
| `storage.setItem` | `localStorage.setItem()` | |
| `storage.removeItem` | `localStorage.removeItem()` | |

### Media (`sparkling-media`)

| Method | Web Implementation | Notes |
|--------|-------------------|-------|
| `media.chooseMedia` | `<input type="file">` with accept filters | Camera source requires HTTPS |
| `media.downloadFile` | `fetch()` + `URL.createObjectURL()` + download link | Subject to CORS restrictions |

## Creating a Web Handler for a Custom Method

If you've created a custom method SDK (see [Create a Custom Method](/guide/get-started/create-custom-method)), you can add web support by following these steps:

### 1. Create the web handler

Create `src/web/index.ts` in your method package:

```ts
import { registerWebMethod } from 'sparkling-method';

registerWebMethod('myModule.myAction', (params, callback) => {
// Implement using browser APIs
const result = { /* ... */ };
callback({ code: 0, data: result });
});

registerWebMethod('myModule.anotherAction', (params, callback) => {
// ...
callback({ code: 0, data: {} });
});
```

### 2. Add subpath export

In your method package's `package.json`, add a `./web` export:

```json
{
"exports": {
".": "./dist/index.js",
"./web": "./dist/web/index.js"
}
}
```

### 3. Update module.config.json

Add `"web"` to the `platforms` array:

```json
{
"name": "my-method",
"platforms": ["android", "ios", "web"],
"web": {
"entryPoint": "./src/web/index.ts",
"subpath": "./web"
}
}
```

### 4. Run autolink

```bash
pnpm autolink
```

The CLI discovers the `web` platform entry and generates the appropriate imports so your web handler is loaded automatically.

## Testing Web Handlers

Web handlers are plain functions — you can test them in isolation:

```ts
import { getWebMethodHandler } from 'sparkling-method';

// After importing your web handler module
import 'my-method/web';

test('myModule.myAction returns expected data', (done) => {
const handler = getWebMethodHandler('myModule.myAction');
handler({ input: 'test' }, (response) => {
expect(response.code).toBe(0);
expect(response.data).toEqual({ /* expected */ });
done();
});
});
```

## Error Handling

If a method is called on web without a registered handler, `LynxPipe` returns:

```json
{ "code": -3, "message": "Module not registered" }
```

You can use this to implement graceful degradation:

```ts
import { callAsync } from 'sparkling-method';

try {
const result = await callAsync('myModule.doThing', params);
} catch (e) {
if (e.code === -3) {
// Method not available on this platform — show fallback UI
}
}
```
Loading