Skip to content
Merged
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
13 changes: 1 addition & 12 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ Always reference these instructions first and fallback to search or bash command

**BUG INVESTIGATION**: When investigating whether a bug was already resolved in a previous version, always prioritize searching through `docs/source/about/changelog.rst` first before using Git history. Only search through Git history when no relevant changelog entries are found.

**CODE RETRIEVAL**: Always prioritize using Serena tools (e.g., `mcp_oraios_serena_find_symbol`, `mcp_oraios_serena_search_for_pattern`) for code retrieval and analysis over standard file reading or searching tools.

## Working Effectively

### Bootstrap, Build, and Test the Repository
Expand Down Expand Up @@ -56,7 +54,6 @@ pip install flask sanic tornado
- `hatch test --cover` -- run tests with coverage reporting (used in CI)
- `hatch test -k test_name` -- run specific tests
- `hatch test tests/test_config.py` -- run specific test files
- Note: Some tests require Playwright browser automation and may fail in headless environments

**Run Python Linting and Formatting:**

Expand All @@ -70,7 +67,7 @@ pip install flask sanic tornado

- `hatch run javascript:check` -- Lint and type-check JavaScript (10 seconds). NEVER CANCEL. Set timeout to 30+ minutes.
- `hatch run javascript:fix` -- Format JavaScript code
- `hatch run javascript:test` -- Run JavaScript tests (note: may fail in headless environments due to DOM dependencies)
- `hatch run javascript:test` -- Run JavaScript tests

**Interactive Development Shell:**

Expand Down Expand Up @@ -325,13 +322,6 @@ Follow this step-by-step process for effective development:
- Network timeouts during pip install are common in CI environments
- Missing dependencies error: Install ASGI dependencies with `pip install orjson asgiref asgi-tools servestatic`

### Test Issues:

- Playwright tests may fail in headless environments -- this is expected
- Tests requiring browser DOM should be marked appropriately
- Use `hatch test -k "not playwright"` to skip browser-dependent tests
- JavaScript tests may fail with "window is not defined" in Node.js environment -- this is expected

### Import Issues:

- ReactPy must be installed or src/ must be in Python path
Expand Down Expand Up @@ -397,7 +387,6 @@ Always ensure your changes pass local validation before pushing, as the CI pipel
- **All builds and tests run quickly** - if something takes more than 60 seconds, investigate the issue
- **Hatch environments provide full isolation** - no need to manage virtual environments manually
- **JavaScript packages are bundled into Python** - the build process combines JS and Python into a single distribution
- **Browser automation tests may fail in headless environments** - this is expected behavior for Playwright tests
- **Documentation updates are required** when making changes to Python source code
- **Always update this file** when making changes to the development workflow, build process, or repository structure
- **All tests must always pass** - failures are never expected or allowed in a healthy development environment
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# --- Build Artifacts ---
src/reactpy/static/index.js*
src/reactpy/static/*.js*
src/reactpy/static/morphdom/
src/reactpy/static/pyscript/

Expand Down
1 change: 0 additions & 1 deletion .serena/.gitignore

This file was deleted.

8 changes: 0 additions & 8 deletions .serena/memories/code_style.md

This file was deleted.

12 changes: 0 additions & 12 deletions .serena/memories/development_workflow.md

This file was deleted.

16 changes: 0 additions & 16 deletions .serena/memories/project_overview.md

This file was deleted.

17 changes: 0 additions & 17 deletions .serena/memories/suggested_commands.md

This file was deleted.

84 changes: 0 additions & 84 deletions .serena/project.yml

This file was deleted.

26 changes: 16 additions & 10 deletions docs/source/about/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ Unreleased
- :pull:`1269` - Added ``reactpy.pyscript_component`` that can be used to embed ReactPy components into your existing application.
- :pull:`1264` - Added ``reactpy.use_async_effect`` hook.
- :pull:`1281` - Added ``reactpy.Vdom`` primitive interface for creating VDOM dictionaries.
- :pull:`1307` - Added ``reactpy.web.reactjs_component_from_file`` to import ReactJS components from a file.
- :pull:`1307` - Added ``reactpy.web.reactjs_component_from_url`` to import ReactJS components from a URL.
- :pull:`1307` - Added ``reactpy.web.reactjs_component_from_string`` to import ReactJS components from a string.
- :pull:`1307` - Added ``reactpy.reactjs.component_from_file`` to import ReactJS components from a file.
- :pull:`1307` - Added ``reactpy.reactjs.component_from_url`` to import ReactJS components from a URL.
- :pull:`1307` - Added ``reactpy.reactjs.component_from_string`` to import ReactJS components from a string.
- :pull:`1314` - Added ``reactpy.reactjs.component_from_npm`` to import ReactJS components from NPM.
- :pull:`1314` - Added ``reactpy.h`` as a shorthand alias for ``reactpy.html``.

**Changed**

- :pull:`1314` - The ``key`` attribute is now stored within ``attributes`` in the VDOM spec.
- :pull:`1251` - Substitute client-side usage of ``react`` with ``preact``.
- :pull:`1239` - Script elements no longer support behaving like effects. They now strictly behave like plain HTML scripts.
- :pull:`1255` - The ``reactpy.html`` module has been modified to allow for auto-creation of any HTML nodes. For example, you can create a ``<data-table>`` element by calling ``html.data_table()``.
Expand All @@ -59,14 +62,15 @@ Unreleased
- :pull:`1281` - ``reactpy.core.vdom._EllipsisRepr`` has been moved to ``reactpy.types.EllipsisRepr``.
- :pull:`1281` - ``reactpy.types.VdomDictConstructor`` has been renamed to ``reactpy.types.VdomConstructor``.
- :pull:`1312` - ``REACTPY_ASYNC_RENDERING`` can now de-duplicate and cascade renders where necessary.
- :pull:`1312` - ``REACTPY_ASYNC_RENDERING`` is now defaulted to ``True`` for up to 40x performance improvements.
- :pull:`1312` - ``REACTPY_ASYNC_RENDERING`` is now defaulted to ``True`` for up to 40x performance improvements in environments with high concurrency.

**Deprecated**

-:pull:`1307` - ``reactpy.web.export`` is deprecated. Use ``reactpy.web.reactjs_component_from_*`` instead.
-:pull:`1307` - ``reactpy.web.module_from_file`` is deprecated. Use ``reactpy.web.reactjs_component_from_file`` instead.
-:pull:`1307` - ``reactpy.web.module_from_url`` is deprecated. Use ``reactpy.web.reactjs_component_from_url`` instead.
-:pull:`1307` - ``reactpy.web.module_from_string`` is deprecated. Use ``reactpy.web.reactjs_component_from_string`` instead.
-:pull:`1307` - ``reactpy.web.export`` is deprecated. Use ``reactpy.reactjs.component_from_*`` instead.
-:pull:`1307` - ``reactpy.web.module_from_file`` is deprecated. Use ``reactpy.reactjs.component_from_file`` instead.
-:pull:`1307` - ``reactpy.web.module_from_url`` is deprecated. Use ``reactpy.reactjs.component_from_url`` instead.
-:pull:`1307` - ``reactpy.web.module_from_string`` is deprecated. Use ``reactpy.reactjs.component_from_string`` instead.
-:pull:`1314` - ``reactpy.web.*`` is deprecated. Use ``reactpy.reactjs.*`` instead.

**Removed**

Expand All @@ -78,8 +82,8 @@ Unreleased
- :pull:`1311` - Removed deprecated exception type ``reactpy.core.serve.Stop``.
- :pull:`1311` - Removed deprecated component ``reactpy.widgets.hotswap``.
- :pull:`1255` - Removed ``reactpy.sample`` module.
- :pull:`1255` - Removed ``reactpy.svg`` module. Contents previously within ``reactpy.svg.*`` can now be accessed via ``html.svg.*``.
- :pull:`1255` - Removed ``reactpy.html._`` function. Use ``html.fragment`` instead.
- :pull:`1255` - Removed ``reactpy.svg`` module. Contents previously within ``reactpy.svg.*`` can now be accessed via ``reactpy.html.svg.*``.
- :pull:`1255` - Removed ``reactpy.html._`` function. Use ``reactpy.html(...)`` or ``reactpy.html.fragment(...)`` instead.
- :pull:`1113` - Removed ``reactpy.run``. See the documentation for the new method to run ReactPy applications.
- :pull:`1113` - Removed ``reactpy.backend.*``. See the documentation for the new method to run ReactPy applications.
- :pull:`1113` - Removed ``reactpy.core.types`` module. Use ``reactpy.types`` instead.
Expand All @@ -92,12 +96,14 @@ Unreleased
- :pull:`1312` - Removed ``reactpy.types.LayoutType``. Use ``reactpy.types.BaseLayout`` instead.
- :pull:`1312` - Removed ``reactpy.types.ContextProviderType``. Use ``reactpy.types.ContextProvider`` instead.
- :pull:`1312` - Removed ``reactpy.core.hooks._ContextProvider``. Use ``reactpy.types.ContextProvider`` instead.
- :pull:`1314` - Removed ``reactpy.web.utils``. Use ``reactpy.reactjs.utils`` instead.

**Fixed**

- :pull:`1239` - Fixed a bug where script elements would not render to the DOM as plain text.
- :pull:`1271` - Fixed a bug where the ``key`` property provided within server-side ReactPy code was failing to propagate to the front-end JavaScript components.
- :pull:`1254` - Fixed a bug where ``RuntimeError("Hook stack is in an invalid state")`` errors could be generated when using a webserver that reuses threads.
- :pull:`1314` - Allow for ReactPy and ReactJS components to be arbitrarily inserted onto the page with any possible hierarchy.


v1.1.0
Expand Down
23 changes: 12 additions & 11 deletions src/build_scripts/clean_js_dir.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,30 @@

# Get the path to the JS source directory
js_src_dir = pathlib.Path(__file__).parent.parent / "js"

# Get the paths to all `dist` folders in the JS source directory
dist_dirs = glob.glob(str(js_src_dir / "**/dist"), recursive=True)

# Get the paths to all `node_modules` folders in the JS source directory
node_modules_dirs = glob.glob(str(js_src_dir / "**/node_modules"), recursive=True)

# Get the paths to all `tsconfig.tsbuildinfo` files in the JS source directory
tsconfig_tsbuildinfo_files = glob.glob(
str(js_src_dir / "**/tsconfig.tsbuildinfo"), recursive=True
)
static_output_dir = pathlib.Path(__file__).parent.parent / "reactpy" / "static"

# Delete all `dist` folders
dist_dirs = glob.glob(str(js_src_dir / "**/dist"), recursive=True)
for dist_dir in dist_dirs:
with contextlib.suppress(FileNotFoundError):
shutil.rmtree(dist_dir)

# Delete all `node_modules` folders
node_modules_dirs = glob.glob(str(js_src_dir / "**/node_modules"), recursive=True)
for node_modules_dir in node_modules_dirs:
with contextlib.suppress(FileNotFoundError):
shutil.rmtree(node_modules_dir)

# Delete all `tsconfig.tsbuildinfo` files
tsconfig_tsbuildinfo_files = glob.glob(
str(js_src_dir / "**/tsconfig.tsbuildinfo"), recursive=True
)
for tsconfig_tsbuildinfo_file in tsconfig_tsbuildinfo_files:
with contextlib.suppress(FileNotFoundError):
os.remove(tsconfig_tsbuildinfo_file)

# Delete all `index-*.js` files
index_js_files = glob.glob(str(static_output_dir / "index-*.js*"))
for index_js_file in index_js_files:
with contextlib.suppress(FileNotFoundError):
os.remove(index_js_file)
2 changes: 1 addition & 1 deletion src/js/packages/@reactpy/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"license": "MIT",
"name": "@reactpy/app",
"scripts": {
"build": "bun build \"src/index.ts\" --outdir=\"../../../../reactpy/static/\" --minify --sourcemap=\"linked\"",
"build": "bun build \"src/index.ts\" \"src/react.ts\" \"src/react-dom.ts\" \"src/react-jsx-runtime.ts\" --outdir=\"../../../../reactpy/static/\" --minify --sourcemap=\"linked\" --splitting",
"checkTypes": "tsc --noEmit"
}
}
9 changes: 9 additions & 0 deletions src/js/packages/@reactpy/app/src/react-dom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import ReactDOM from "preact/compat";

// @ts-ignore
export * from "preact/compat";

// @ts-ignore
export * from "preact/compat/client";

export default ReactDOM;
1 change: 1 addition & 0 deletions src/js/packages/@reactpy/app/src/react-jsx-runtime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "preact/jsx-runtime";
6 changes: 6 additions & 0 deletions src/js/packages/@reactpy/app/src/react.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from "preact/compat";

// @ts-ignore
export * from "preact/compat";

export default React;
3 changes: 2 additions & 1 deletion src/js/packages/@reactpy/app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"compilerOptions": {
"composite": true,
"outDir": "dist",
"rootDir": "src"
"rootDir": "src",
"esModuleInterop": true
},
"extends": "../../../tsconfig.json",
"include": ["src"],
Expand Down
2 changes: 1 addition & 1 deletion src/js/packages/@reactpy/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@
"checkTypes": "tsc --noEmit"
},
"type": "module",
"version": "1.0.2"
"version": "1.0.3"
}
6 changes: 3 additions & 3 deletions src/js/packages/@reactpy/client/src/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function StandardElement({ model }: { model: ReactPyVdom }) {
model.tagName === "" ? Fragment : model.tagName,
createAttributes(model, client),
...createChildren(model, (child) => {
return <Element model={child} key={child.key} />;
return <Element model={child} key={child.attributes?.key} />;
}),
);
}
Expand Down Expand Up @@ -100,7 +100,7 @@ function UserInputElement({ model }: { model: ReactPyVdom }): JSX.Element {
// overwrite
{ ...props, value },
...createChildren(model, (child) => (
<Element model={child} key={child.key} />
<Element model={child} key={child.attributes?.key} />
)),
);
}
Expand Down Expand Up @@ -135,7 +135,7 @@ function ScriptElement({ model }: { model: ReactPyVdom }) {
return () => {
ref.current?.removeChild(scriptElement);
};
}, [model.key]);
}, [model.attributes?.key]);

return <div ref={ref} />;
}
Expand Down
1 change: 1 addition & 0 deletions src/js/packages/@reactpy/client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export * from "./vdom";
export * from "./websocket";
export { default as React } from "preact/compat";
export { default as ReactDOM } from "preact/compat";
export { jsx, jsxs, Fragment } from "preact/jsx-runtime";
export * as preact from "preact";
Loading
Loading