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
37 changes: 21 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,42 +56,47 @@ mkdir my_app_name
cd my_app_name
```

### 2. Set up a virtual environment
### 2. Install uv

Create and activate virtual environment
Reflex recommends [uv](https://docs.astral.sh/uv/) for managing your project environment and dependencies.
See the [uv installation docs](https://docs.astral.sh/uv/getting-started/installation/) for your platform.

```bash
# On Windows:
python -m venv .venv
.venv\Scripts\activate
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# On macOS/Linux:
python3 -m venv .venv
source .venv/bin/activate
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```

### 3. Install Reflex
### 3. Initialize the Python project

Reflex is available as a pip package (Requires Python 3.10+):
```bash
uv init
```

### 4. Add Reflex

Reflex requires Python 3.10+:

```bash
pip install reflex
uv add reflex
```

### 4. Initialize the project
### 5. Initialize the project

This command initializes a template app in your new directory:

```bash
reflex init
uv run reflex init
```

### 5. Run the app
### 6. Run the app

You can run this app in development mode:

```bash
reflex run
uv run reflex run
```

You should see your app running at http://localhost:3000.
Expand All @@ -100,7 +105,7 @@ Now you can modify the source code in `my_app_name/my_app_name.py`. Reflex has f

### Troubleshooting

If you installed Reflex without a virtual environment and the `reflex` command is not found, you can run commands using: `python3 -m reflex init` and `python3 -m reflex run`
If the `reflex` command is not on your PATH, run it through uv instead: `uv run reflex init` and `uv run reflex run`

## 🫧 Example App

Expand Down
2 changes: 1 addition & 1 deletion reflex/docs/advanced_onboarding/code_structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ example-big-app/
│ ├─ state.py
│ ├─ template.py
├─ uploaded_files/
├─ requirements.txt
├─ pyproject.toml
├─ rxconfig.py
```

Expand Down
8 changes: 4 additions & 4 deletions reflex/docs/advanced_onboarding/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Reflex apps can be configured using a configuration file, environment variables,

## Configuration File

Running `reflex init` will create an `rxconfig.py` file in your root directory.
Running `uv run reflex init` will create an `rxconfig.py` file in your root directory.
You can pass keyword arguments to the `Config` class to configure your app.

For example:
Expand All @@ -31,15 +31,15 @@ You can override the configuration file by setting environment variables.
For example, to override the `frontend_port` setting, you can set the `FRONTEND_PORT` environment variable.

```bash
FRONTEND_PORT=3001 reflex run
FRONTEND_PORT=3001 uv run reflex run
```

## Command Line Arguments

Finally, you can override the configuration file and environment variables by passing command line arguments to `reflex run`.
Finally, you can override the configuration file and environment variables by passing command line arguments to `uv run reflex run`.

```bash
reflex run --frontend-port 3001
uv run reflex run --frontend-port 3001
```

See the [CLI reference](/docs/api-reference/cli) for all the arguments available.
Expand Down
4 changes: 2 additions & 2 deletions reflex/docs/advanced_onboarding/how-reflex-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ rx.box(height="1em")

We wanted Reflex apps to look and feel like a traditional web app to the end user, while still being easy to build and maintain for the developer. To do this, we built on top of mature and popular web technologies.

When you `reflex run` your app, Reflex compiles the frontend down to a single-page [Next.js](https://nextjs.org) app and serves it on a port (by default `3000`) that you can access in your browser.
When you run `uv run reflex run`, Reflex compiles the frontend down to a single-page [Next.js](https://nextjs.org) app and serves it on a port (by default `3000`) that you can access in your browser.

The frontend's job is to reflect the app's state, and send events to the backend when the user interacts with the UI. No actual logic is run on the frontend.

Expand Down Expand Up @@ -128,7 +128,7 @@ Beyond this, Reflex components can be styled using the full power of CSS. We lev

Now let's look at how we added interactivity to our apps.

In Reflex only the frontend compiles to Javascript and runs on the user's browser, while all the state and logic stays in Python and is run on the server. When you `reflex run`, we start a FastAPI server (by default on port `8000`) that the frontend connects to through a websocket.
In Reflex only the frontend compiles to Javascript and runs on the user's browser, while all the state and logic stays in Python and is run on the server. When you run `uv run reflex run`, we start a FastAPI server (by default on port `8000`) that the frontend connects to through a websocket.

All the state and logic are defined within a `State` class.

Expand Down
4 changes: 2 additions & 2 deletions reflex/docs/getting_started/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ This page gives an introduction to the most common concepts that you will use to
- Create pages and navigate between them
```

[Install](/docs/getting_started/installation) `reflex` using pip.
[Install](/docs/getting_started/installation) `reflex` with uv before continuing.

```bash
pip install reflex
uv add reflex
```

Import the `reflex` library to get started.
Expand Down
4 changes: 2 additions & 2 deletions reflex/docs/getting_started/dashboard_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,9 @@ Don't worry if you don't understand the code above, in this tutorial we are goin

## Setup for the tutorial

Check out the [installation docs](/docs/getting_started/installation) to get Reflex set up on your machine. Follow these to create a folder called `dashboard_tutorial`, which you will `cd` into and `pip install reflex`.
Check out the [installation docs](/docs/getting_started/installation) to get Reflex set up on your machine. Follow these to create a folder called `dashboard_tutorial`, which you will `cd` into, then run `uv init` and `uv add reflex`.

We will choose template `0` when we run `reflex init` to get the blank template. Finally run `reflex run` to start the app and confirm everything is set up correctly.
We will choose template `0` when we run `uv run reflex init` to get the blank template. Finally run `uv run reflex run` to start the app and confirm everything is set up correctly.

## Overview

Expand Down
25 changes: 21 additions & 4 deletions reflex/docs/getting_started/project-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,36 @@ Let's create a new app called `{app_name}`
```bash
mkdir {app_name}
cd {app_name}
reflex init
uv init
uv add reflex
uv run reflex init
```

This will create a directory structure like this:

```bash
{app_name}
├── .venv
├── .web
├── assets
├── {app_name}
│ ├── __init__.py
│ └── {app_name}.py
└── rxconfig.py
├── .gitignore
├── .python-version
├── pyproject.toml
├── rxconfig.py
└── uv.lock
```

`uv init` may also create helper files such as `README.md`, `main.py`, and Git metadata. The tree above focuses on the main files you will interact with while building a Reflex app.

Let's go over each of these directories and files.

## .venv

`uv add reflex` creates a local virtual environment in `.venv` by default. This keeps your app dependencies isolated from the rest of your system Python.

## .web

This is where the compiled Javascript files will be stored. You will never need to touch this directory, but it can be useful for debugging.
Expand All @@ -45,14 +58,18 @@ For example, if you save an image to `assets/image.png` you can display it from
rx.image(src="https://web.reflex-assets.dev/other/image.png")
```

j

## Main Project

Initializing your project creates a directory with the same name as your app. This is where you will write your app's logic.

Reflex generates a default app within the `{app_name}/{app_name}.py` file. You can modify this file to customize your app.

## Python Project Files

`pyproject.toml` defines your Python project metadata and dependencies. `uv add reflex` records the Reflex dependency there before you initialize the app.

`uv.lock` stores the fully resolved dependency set for reproducible installs. Commit it to version control so everyone working on the app gets the same Python package versions.

## Configuration

The `rxconfig.py` file can be used to configure your app. By default it looks something like this:
Expand Down
24 changes: 13 additions & 11 deletions reflex/reflex.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,22 @@ def _init(
# Initialize the .gitignore.
frontend_skeleton.initialize_gitignore()

# Initialize the requirements.txt.
needs_user_manual_update = frontend_skeleton.initialize_requirements_txt()

template_msg = f" using the {template} template" if template else ""
# Finish initializing the app.
console.success(
f"Initialized {app_name}{template_msg}."
+ (
f" Make sure to add {constants.RequirementsTxt.DEFAULTS_STUB + constants.Reflex.VERSION} to your requirements.txt or pyproject.toml file."
if needs_user_manual_update
else ""
)
if Path(constants.PyprojectToml.FILE).exists():
needs_user_manual_update = False
next_steps = " Run `uv run reflex run` to start the app."
else:
needs_user_manual_update = frontend_skeleton.initialize_requirements_txt()
next_steps = " Install dependencies from `requirements.txt` with `uv pip install -r requirements.txt` (or your preferred installer) before running `uv run reflex run`."
manual_update = (
f" Make sure to add `{constants.RequirementsTxt.DEFAULTS_STUB + constants.Reflex.VERSION}` to your requirements.txt file."
if needs_user_manual_update
else ""
)

# Finish initializing the app.
console.success(f"Initialized {app_name}{template_msg}.{manual_update}{next_steps}")


@cli.command()
@loglevel_option
Expand Down
114 changes: 85 additions & 29 deletions reflex/utils/frontend_skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import json
import random
import re
from pathlib import Path

from reflex_base import constants
Expand Down Expand Up @@ -42,44 +41,101 @@ def initialize_gitignore(
gitignore_file.write_text("\n".join(files_to_ignore) + "\n")


def initialize_requirements_txt() -> bool:
def _read_dependency_file(file_path: Path) -> tuple[str | None, str | None]:
"""Read a dependency file with a forgiving encoding strategy.

Args:
file_path: The file to read.

Returns:
A tuple of file content and the encoding used to read it.
"""
try:
return file_path.read_text(), None
except UnicodeDecodeError:
pass
except Exception as e:
console.error(f"Failed to read {file_path} due to {e}.")
raise SystemExit(1) from None

try:
return file_path.read_text(encoding="utf-8"), "utf-8"
except UnicodeDecodeError:
return None, None
except Exception as e:
console.error(f"Failed to read {file_path} due to {e}.")
raise SystemExit(1) from None


def _has_reflex_requirement_line(requirements_text: str) -> bool:
"""Check whether requirements.txt already contains reflex.

Returns:
Whether reflex is already present in the requirements text.
"""
return any(
_is_reflex_dependency_spec(line) for line in requirements_text.splitlines()
)


def _is_reflex_dependency_spec(requirement: str) -> bool:
"""Check whether a dependency specification refers to the reflex package.

Args:
requirement: The dependency specification to check.

Returns:
Whether the specification refers to the reflex package.
"""
requirement = requirement.strip()
if not requirement.lower().startswith("reflex"):
return False

suffix = requirement[len("reflex") :]
if suffix.startswith("["):
extras_end = suffix.find("]")
if extras_end == -1:
return False
suffix = suffix[extras_end + 1 :]

return not suffix or suffix.lstrip().startswith((
"==",
"!=",
">=",
"<=",
"~=",
">",
"<",
";",
"@",
))


def initialize_requirements_txt(
requirements_file_path: Path = Path(constants.RequirementsTxt.FILE),
pyproject_file_path: Path = Path(constants.PyprojectToml.FILE),
) -> bool:
"""Initialize the requirements.txt file.
If absent and no pyproject.toml file exists, generate one for the user.
If the requirements.txt does not have reflex as dependency,
generate a requirement pinning current version and append to
the requirements.txt file.

If a project already uses pyproject.toml, leave dependency management to the
package manager. Otherwise ensure requirements.txt pins the current Reflex
version for legacy workflows.

Returns:
True if the user has to update the requirements.txt file.

Raises:
SystemExit: If the requirements.txt file cannot be read or written to.
"""
requirements_file_path = Path(constants.RequirementsTxt.FILE)
if (
not requirements_file_path.exists()
and Path(constants.PyprojectToml.FILE).exists()
):
return True
if not requirements_file_path.exists() and pyproject_file_path.exists():
return False

requirements_file_path.touch(exist_ok=True)

for encoding in [None, "utf-8"]:
try:
content = requirements_file_path.read_text(encoding)
break
except UnicodeDecodeError:
continue
except Exception as e:
console.error(f"Failed to read {requirements_file_path} due to {e}.")
raise SystemExit(1) from None
else:
content, encoding = _read_dependency_file(requirements_file_path)
if content is None:
return True

for line in content.splitlines():
if re.match(r"^reflex[^a-zA-Z0-9]", line):
console.debug(f"{requirements_file_path} already has reflex as dependency.")
return False
if _has_reflex_requirement_line(content):
console.debug(f"{requirements_file_path} already has reflex as dependency.")
return False

console.debug(
f"Appending {constants.RequirementsTxt.DEFAULTS_STUB} to {requirements_file_path}"
Expand Down
Loading
Loading