Skip to content
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2170ece
- clean
PupilTong Mar 9, 2026
ef62fba
+ build ok
PupilTong Mar 10, 2026
bc61c42
web-core-wasm -> web-core
PupilTong Mar 10, 2026
5039e14
+ initial test clean
PupilTong Mar 10, 2026
ad819db
feat: support __QuerySelector and __InvokeUIMethod
PupilTong Mar 10, 2026
5342856
fix: support legacy json template for lazy usage
PupilTong Mar 10, 2026
fcf5baa
feat: Make `systemInfo` instance-specific and configurable via a new …
PupilTong Mar 10, 2026
b16215d
fix: type selector for legacy json template
PupilTong Mar 10, 2026
bbd8ac2
fix: legacy root selector
PupilTong Mar 10, 2026
d3b1b51
fix: support @keyframe in legacy json template
PupilTong Mar 10, 2026
fa68712
refactor: Adjust module loading paths, promote `wasm-feature-detect` …
PupilTong Mar 11, 2026
f5754fc
fix: Add nonce attribute to the iframe srcdoc script for CSP compliance.
PupilTong Mar 11, 2026
d767345
feat: Implement and test dynamic list item removal and insertion in R…
PupilTong Mar 12, 2026
9d5ac5d
fix: scoped css support for json legacy bundle
PupilTong Mar 12, 2026
e001c05
+ fix
PupilTong Mar 12, 2026
553dbf9
+ CSR OK!
PupilTong Mar 12, 2026
c5928b2
+ partial fix
PupilTong Mar 16, 2026
4731cbe
+ fix header
PupilTong Mar 16, 2026
86c00ba
+ implement FP support
PupilTong Mar 17, 2026
05c84fa
chore: Initialize `SERVER_IN_SHADOW_CSS` with a const expression.
PupilTong Mar 17, 2026
eb4d334
+ dedupe
PupilTong Mar 17, 2026
06cf03e
fix
PupilTong Mar 18, 2026
bcccb2c
+ fix
PupilTong Mar 18, 2026
a4cacc1
+ changeset
PupilTong Mar 18, 2026
d1bc22c
+ dedupe
PupilTong Mar 18, 2026
e519ece
+ rerender for SSR from the start over
PupilTong Mar 18, 2026
293c0b4
feat: Add server-side DOM manipulation APIs for element insertion, re…
PupilTong Mar 19, 2026
0fc8a5d
+ fix
PupilTong Mar 19, 2026
8491ed9
+ fix
PupilTong Mar 19, 2026
5f6ea34
+ fix
PupilTong Mar 19, 2026
24530c8
+ fix repl
PupilTong Mar 20, 2026
a3f8f37
+ fix changeset
PupilTong Mar 24, 2026
2767588
Merge branch 'main' into p/hw/replace-web-core
Huxpro Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
64 changes: 64 additions & 0 deletions .changeset/bitter-emus-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
"@lynx-js/web-core": minor
---
Comment thread
coderabbitai[bot] marked this conversation as resolved.

**This is a breaking change**

## Architectural Upgrade: `web-core-wasm` replaces `web-core`

This release marks a major architectural upgrade for the web platform. The experimental, WASM-powered engine formerly known as `web-core-wasm` has been fully stabilized and merged into the main branch, completely replacing the previous pure JS/TS based `web-core` implementation. This consolidation massively improves execution performance and aligns the API boundaries of the Web platform directly with other native Lynx implementations.
Comment thread
PupilTong marked this conversation as resolved.

### 🎉 Added Features

- **Core API Enhancements**: Successfully exposed and supported `__QuerySelector` and `__InvokeUIMethod` methods.
- **Security & CSP Compliance**: Added a `nonce` attribute to the iframe's `srcdoc` script execution, strengthening Content Security Policy (CSP) compliance.
- **`<lynx-view>` Parameter Enhancements**:
- Added the `browser-config` attribute and property to `<lynx-view>`. Development environments can now supply a `BrowserConfig` object (e.g., configuring `pixelRatio`, `pixelWidth`, `pixelHeight`) allowing the `systemInfo` payload to be dynamically configured at the instance level.

### 🔄 Changed Features

- **Legacy JSON Backwards Compatibility**: Delivered comprehensive fixes and optimizations to deeply support legacy JSON output templates:
- Added support for lazy loading execution mode (`lazy usage`).
- Implemented the correct decoding and handling of `@keyframe` animation rules.
- Rectified rule scoping matching including scoped CSS, root selectors, and type selectors.
- **Ecosystem Migration**: Updated testing and ecosystem applications (such as `web-explorer` and `shell-project`) to migrate away from obsolete fragmented dependencies. The new WASM architecture seamlessly integrates Element APIs and CSS directly inside the core client module, requiring a much simpler initialization footprint.

**Before (Legacy `web-core` + `web-elements`):**
```typescript
// Required multiple imports to assemble the environment
import '@lynx-js/web-core/client';
import type { LynxViewElement as LynxView } from '@lynx-js/web-core';

// Had to manually import separate elements and their CSS
import '@lynx-js/web-elements/index.css';
import '@lynx-js/web-elements/all';

const lynxView = document.createElement('lynx-view') as LynxView;
// ...
```

**After (New `web-core` unified architecture):**
```typescript
// The new engine natively registers Web Components and injects fundamental CSS
import '@lynx-js/web-core/client';
import type { LynxViewElement as LynxView } from '@lynx-js/web-core/client';

const lynxView = document.createElement('lynx-view') as LynxView;
// ...
```
_(Applications can now drop `@lynx-js/web-elements` entirely from their `package.json` dependencies)._
- **Dependency & Boot Sequence Improvements**: Re-architected module loading pathways. Promoted `wasm-feature-detect` directly to a core dependency, and hardened the web worker count initialization assertions.
- **Initialization Optimizations**: Converted `SERVER_IN_SHADOW_CSS` initialization bounds to use compilation-time constant expressions for better optimization.

### 🗑️ Deleted Features & Structural Deprecations

- **`<lynx-view>` Parameter Removals**:
- Removed the `thread-strategy` property and attribute. Historically, this permitted consumers to toggle between `'multi-thread'` and `'all-on-ui'` modes depending on how they wanted the background logic to be executed. The WASM-driven architecture enforces a consolidated concurrency model, deprecating this `<lynx-view>` attribute entirely.
- Removed the `overrideLynxTagToHTMLTagMap` property/attribute. HTML tag overriding mechanism has been deprecated in the new engine.
- Removed the `customTemplateLoader` property handler from `<lynx-view>`.
- Removed the `inject-head-links` property and attribute (`injectHeadLinks`), which previously was used to automatically inject `<link rel="stylesheet">` tags from the document head into the `lynx-view` shadow root.
- **Fragmented Packages Removal**: The new cohesive WASM architecture native to `@lynx-js/web-core` handles cross-thread communication, worker boundaries, and rendering loops uniformly. Consequently, multiple obsolete packages have been completely removed from the workspace:
- `@lynx-js/web-mainthread-apis`
- `@lynx-js/web-worker-runtime`
- `@lynx-js/web-core-server`
- `@lynx-js/web-core-wasm-e2e` (transitioned into standard test suites)
6 changes: 1 addition & 5 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@
"fixed": [
[
"@lynx-js/web-core",
"@lynx-js/web-core-server",
"@lynx-js/web-constants",
"@lynx-js/web-mainthread-apis",
"@lynx-js/web-worker-rpc",
"@lynx-js/web-worker-runtime",
"@lynx-js/web-rsbuild-server-middleware"
],
[
Expand Down Expand Up @@ -42,7 +38,7 @@
"ignore": [
"@lynx-js/web-tests",
"@lynx-js/example-react",
"@lynx-js/web-core-wasm-e2e"
"@lynx-js/web-core-e2e"
],
"changedFilePatterns": [
"src/**"
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ jobs:
export PLAYWRIGHT_JUNIT_OUTPUT_NAME=test-report.junit.xml
pnpm --filter @lynx-js/web-tests run test --reporter='github,dot,junit,html' --shard=${{ matrix.shard }}/3
pnpm --filter @lynx-js/web-tests run coverage:ci
web-core-wasm-e2e:
web-core-e2e:
needs: build
uses: ./.github/workflows/workflow-test.yml
secrets:
Expand All @@ -144,15 +144,15 @@ jobs:
runs-on: lynx-custom-container
is-web: true
web-report-name: "playwright-${{ matrix.render }}-shard${{ matrix.shard }}"
web-report-path: "packages/web-platform/web-core-wasm-e2e/playwright-report"
web-report-path: "packages/web-platform/web-core-e2e/playwright-report"
codecov-flags: "e2e"
run: |
if [ "${{ matrix.render }}" = "SSR" ]; then
export ENABLE_SSR=true
fi
export NODE_OPTIONS="--max-old-space-size=32768"
export PLAYWRIGHT_JUNIT_OUTPUT_NAME=test-report.junit.xml
pnpm --filter @lynx-js/web-core-wasm-e2e run test --reporter='github,dot,junit,html' --shard=${{ matrix.shard }}/2
pnpm --filter @lynx-js/web-core-e2e run test --reporter='github,dot,junit,html' --shard=${{ matrix.shard }}/2
test-api:
needs: build
uses: ./.github/workflows/workflow-test.yml
Expand Down Expand Up @@ -354,7 +354,7 @@ jobs:
- test-type
- test-typos
- test-vitest
- web-core-wasm-e2e
- web-core-e2e
- website
if: always()
runs-on: ubuntu-latest
Expand Down
1 change: 0 additions & 1 deletion .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ extend-exclude = [
"packages/web-platform/web-tests/tests/react.spec.ts-snapshots/*",
"packages/web-platform/web-tests/tests/react.spec.ts",
"packages/web-platform/web-tests/tests/react/basic-element-x-overlay-ng-playground-test/index.jsx",
"packages/web-platform/offscreen-document/src/webworker/OffscreenCSSStyleDeclaration.ts",
]

[default]
Expand Down
5 changes: 2 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ export NODE_OPTIONS="--max-old-space-size=32768"
- `packages/web-platform/` - **Lynx for Web**: Web platform implementation
- `web-core/` - Core web runtime
- `web-elements/` - DOM element implementations
- `web-worker-runtime/` - Web worker support
- `web-tests/` - E2E test suite (Playwright)
- `web-core-e2e` - e2e tests

- `packages/testing-library/` - Testing infrastructure
- `packages/tools/` - Build and development utilities
Expand Down Expand Up @@ -245,7 +244,7 @@ These instructions were generated through comprehensive analysis and testing of
- Includes E2E test suite requiring Playwright
- Many packages have complex interdependencies
- Contains performance-critical rendering code
- See `packages/web-platform/web-core-wasm/AGENTS.md` for specific instructions on `web-core-wasm`.
- See `packages/web-platform/web-core/AGENTS.md` for specific instructions on `web-core`.

Remember: This is a complex, multi-language monorepo. Always allow extra time for builds and tests, and follow the exact command sequences provided.

Expand Down
11 changes: 1 addition & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ members = [
"packages/react/transform/crates/*",
"packages/react/transform/swc-plugin-reactlynx",
"packages/react/transform/swc-plugin-reactlynx-compat",
"packages/web-platform/web-core-wasm",
"packages/web-platform/web-core",
"packages/web-platform/web-elements",
"packages/web-platform/web-mainthread-apis",
]

[workspace.dependencies]
Expand Down
5 changes: 0 additions & 5 deletions packages/repl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,8 @@
"@lynx-js/lynx-core": "0.1.3",
"@lynx-js/type-element-api": "0.0.3",
"@lynx-js/types": "3.7.0",
"@lynx-js/web-constants": "workspace:*",
"@lynx-js/web-core": "workspace:*",
"@lynx-js/web-elements": "workspace:*",
"@lynx-js/web-mainthread-apis": "workspace:*",
"@lynx-js/web-platform-rsbuild-plugin": "workspace:*",
"@lynx-js/web-worker-rpc": "workspace:*",
"@lynx-js/web-worker-runtime": "workspace:*",
"@rsbuild/core": "catalog:rsbuild",
"@rsbuild/plugin-react": "^1.4.5",
"@tailwindcss/postcss": "^4.2.1",
Expand Down
6 changes: 3 additions & 3 deletions packages/repl/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
// LICENSE file in the root directory of this source tree.
import { useCallback, useEffect, useRef, useState } from 'react';

import type { LynxTemplate } from '@lynx-js/web-constants';

import { buildLynxTemplate } from './bundler/template-builder.js';
import { EditorPane } from './components/EditorPane.js';
import type { EditorPaneHandle } from './components/EditorPane.js';
Expand Down Expand Up @@ -89,7 +87,9 @@ export function App() {
initial.sampleIndex,
);
const [timingText, setTimingText] = useState('');
const [template, setTemplate] = useState<LynxTemplate | null>(null);
const [template, setTemplate] = useState<Record<string, unknown> | null>(
null,
);
Comment thread
PupilTong marked this conversation as resolved.
const pendingTimingRef = useRef<
| { css: number | null; assemble: number; t0: number; buildEnd: number }
| null
Expand Down
8 changes: 3 additions & 5 deletions packages/repl/src/bundler/css-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

import * as csstree from 'css-tree';

import type { CSSRule, OneInfo, StyleInfo } from '@lynx-js/web-constants';

// --- Simplified parse (adapted from css-serializer/parse.ts) ---

interface Declaration {
Expand Down Expand Up @@ -260,7 +258,7 @@ function parseCSS(content: string): LynxStyleNode[] {

function genStyleInfo(
cssMap: Record<string, LynxStyleNode[]>,
): StyleInfo {
): unknown {
Comment thread
PupilTong marked this conversation as resolved.
return Object.fromEntries(
Object.entries(cssMap).map(([cssId, nodes]) => {
const contentsAtom: string[] = [];
Expand Down Expand Up @@ -297,7 +295,7 @@ function genStyleInfo(
const selectors = ((ast.children.first as csstree.Rule)
.prelude as csstree.SelectorList).children
.toArray() as csstree.Selector[];
const groupedSelectors: CSSRule['sel'] = [];
const groupedSelectors: unknown[] = [];
for (const selectorList of selectors) {
let plainSelectors: string[] = [];
let pseudoClassSelectors: string[] = [];
Expand Down Expand Up @@ -356,7 +354,7 @@ function genStyleInfo(
});
}
}
const info: OneInfo = {
const info: unknown = {
content: [contentsAtom.join('\n')],
rules,
};
Expand Down
7 changes: 3 additions & 4 deletions packages/repl/src/bundler/template-builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable headers/header-format */
import type { LynxTemplate, StyleInfo } from '@lynx-js/web-constants';

import { processCSS } from './css-processor.js';
import { getConsoleWrapperCode } from '../console/console-wrapper.js';
Expand Down Expand Up @@ -27,7 +26,7 @@ export function buildLynxTemplate(
css: string,
sessionId: string,
): {
template: LynxTemplate;
template: unknown;
timing: { 'css-serializer': number | null; assemble: number };
} {
const mainThreadWithFallback = `${mainThread}
Expand All @@ -43,7 +42,7 @@ if (typeof globalThis.renderPage !== 'function') {
+ getBackgroundLifecycleCode()
+ background;

let styleInfo: StyleInfo = {};
let styleInfo: unknown = {};
let cssSerializerTime: number | null = null;
if (css.trim()) {
const t = performance.now();
Expand All @@ -52,7 +51,7 @@ if (typeof globalThis.renderPage !== 'function') {
}

const assembleStart = performance.now();
const template: LynxTemplate = {
const template: unknown = {
lepusCode: { root: mainThreadCode },
manifest: { '/app-service.js': backgroundCode },
styleInfo,
Expand Down
14 changes: 7 additions & 7 deletions packages/repl/src/components/LynxPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
/* eslint-disable headers/header-format, sort-imports, import/order, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, n/no-unsupported-features/node-builtins, @typescript-eslint/prefer-nullish-coalescing */
import { useRef, useEffect, useState, useCallback } from 'react';
import type { LynxTemplate } from '@lynx-js/web-constants';
import type { LynxView } from '@lynx-js/web-core';

let renderCounter = 0;
import type { LynxViewElement as LynxView } from '@lynx-js/web-core/client';

interface LynxPreviewProps {
template: LynxTemplate | null;
template: Record<string, string | boolean | number> | null;
Comment thread
PupilTong marked this conversation as resolved.
isDark: boolean;
onLoad?: () => void;
}
Expand Down Expand Up @@ -83,8 +80,10 @@ export function LynxPreview({ template, isDark, onLoad }: LynxPreviewProps) {
setError(null);
setIsLoading(true);

lynxView.customTemplateLoader = async () => template;
lynxView.url = `repl://template/v${renderCounter++}`;
const blobUrl = URL.createObjectURL(
new Blob([JSON.stringify(template)], { type: 'application/json' }),
);
lynxView.url = blobUrl;

// lynx-view has no load event. The url setter schedules teardown+boot via
// queueMicrotask, so our Promise microtask (queued after) runs once the
Expand Down Expand Up @@ -112,6 +111,7 @@ export function LynxPreview({ template, isDark, onLoad }: LynxPreviewProps) {
});

return () => {
URL.revokeObjectURL(blobUrl);
observer?.disconnect();
};
}, [template, onLoad]);
Expand Down
2 changes: 1 addition & 1 deletion packages/repl/src/components/PreviewPane.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable headers/header-format, sort-imports, import/order, n/file-extension-in-import */
import { RotateCw } from 'lucide-react';
import type { LynxTemplate } from '@lynx-js/web-constants';
import type { LynxTemplate } from '@lynx-js/web-core/client';
import { LynxPreview } from './LynxPreview';
import { ConsolePanel } from './ConsolePanel';
import {
Expand Down
5 changes: 1 addition & 4 deletions packages/repl/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.

import '@lynx-js/web-core';
import '@lynx-js/web-core/index.css';
import '@lynx-js/web-elements/index.css';
import '@lynx-js/web-elements/all';
import '@lynx-js/web-core/client';

import './globals.css';

Expand Down
Loading
Loading