Merge branch 'master' into only-collect-rsx-macro

This commit is contained in:
Evan Almloff 2023-09-02 18:14:04 -05:00
commit 4e1bc13933
27 changed files with 417 additions and 508 deletions

View file

@ -42,6 +42,7 @@ members = [
# Full project examples # Full project examples
"examples/tailwind", "examples/tailwind",
"examples/PWA-example", "examples/PWA-example",
"examples/query_segments_demo",
# Playwright tests # Playwright tests
"playwright-tests/liveview", "playwright-tests/liveview",
"playwright-tests/web", "playwright-tests/web",

View file

@ -0,0 +1,12 @@
[package]
name = "query_segments_demo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dioxus = { path = "../../packages/dioxus", version = "*" }
dioxus-router = { path = "../../packages/router", version = "*" }
dioxus-web = { path = "../../packages/web", version = "*" }
form_urlencoded = "1.2.0"

View file

@ -0,0 +1,73 @@
#![allow(non_snake_case, unused)]
//! Example: Url query segments usage
//! ------------------------------------
//!
//! This example shows how to access and use multiple query segments present in an url on the web.
//!
//! Run `dx serve` and navigate to `http://localhost:8080/blog?name=John&surname=Doe`
use std::fmt::Display;
use dioxus::prelude::*;
use dioxus_router::prelude::*;
// ANCHOR: route
#[derive(Routable, Clone)]
#[rustfmt::skip]
enum Route {
// segments that start with ?: are query segments
#[route("/blog?:query_params")]
BlogPost {
// You must include query segments in child variants
query_params: BlogQuerySegments,
},
}
#[derive(Debug, Clone, PartialEq)]
struct BlogQuerySegments {
name: String,
surname: String,
}
/// The display impl needs to display the query in a way that can be parsed:
impl Display for BlogQuerySegments {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "name={}&surname={}", self.name, self.surname)
}
}
/// The query segment is anything that implements https://docs.rs/dioxus-router/latest/dioxus_router/routable/trait.FromQuery.html. You can implement that trait for a struct if you want to parse multiple query parameters.
impl FromQuery for BlogQuerySegments {
fn from_query(query: &str) -> Self {
let mut name = None;
let mut surname = None;
let pairs = form_urlencoded::parse(query.as_bytes());
pairs.for_each(|(key, value)| {
if key == "name" {
name = Some(value.clone().into());
}
if key == "surname" {
surname = Some(value.clone().into());
}
});
Self {
name: name.unwrap(),
surname: surname.unwrap(),
}
}
}
#[inline_props]
fn BlogPost(cx: Scope, query_params: BlogQuerySegments) -> Element {
render! {
div{"This is your blogpost with a query segment:"}
div{format!("{:?}", query_params)}
}
}
fn App(cx: Scope) -> Element {
render! { Router::<Route>{} }
}
fn main() {
dioxus_web::launch(App);
}

View file

@ -1,29 +1,31 @@
[application] [application]
# dioxus project name # App name
name = "dioxus-cli" name = "project_name"
# default platfrom # The Dioxus platform to default to
# you can also use `dx serve/build --platform XXX` to use other platform default_platform = "web"
# value: web | desktop
default_platform = "desktop"
# Web `build` & `serve` dist path # `build` & `serve` output path
out_dir = "dist" out_dir = "dist"
# resource (static) file folder # The static resource path
asset_dir = "public" asset_dir = "public"
[web.app] [web.app]
# HTML title tag content # HTML title tag content
title = "dioxus | ⛺" title = "project_name"
[web.watcher] [web.watcher]
watch_path = ["src"] # When watcher is triggered, regenerate the `index.html`
reload_html = true
# include `assets` in web platform # Which files or dirs will be monitored
watch_path = ["src", "public"]
# Include style or script assets
[web.resource] [web.resource]
# CSS style file # CSS style file
@ -34,12 +36,13 @@ script = []
[web.resource.dev] [web.resource.dev]
# Javascript code file # Same as [web.resource], but for development servers
# serve: [dev-server] only
# CSS style file
style = []
# JavaScript files
script = [] script = []
[application.tools] [[web.proxy]]
backend = "http://localhost:8000/api/"
# use binaryen.wasm-opt for output Wasm file
# binaryen just will trigger in `web` platform
binaryen = { wasm_opt = true }

View file

@ -1,43 +1,69 @@
<div align="center"> <div style="text-align: center">
<h1>📦✨ Dioxus CLI </h1> <h1>📦✨ Dioxus CLI</h1>
<p><strong>Tooling to supercharge Dioxus projects</strong></p> <p><strong>Tooling to supercharge Dioxus projects</strong></p>
</div> </div>
**dioxus-cli** (inspired by wasm-pack and webpack) is a tool for getting Dioxus projects up and running.
It handles all build, bundling, development and publishing to simplify web development.
The **dioxus-cli** (inspired by wasm-pack and webpack) is a tool for getting Dioxus projects up and running.
It handles all building, bundling, development and publishing to simplify development.
## Installation ## Installation
### Install stable version ### Install the stable version (recommended)
``` ```
cargo install dioxus-cli cargo install dioxus-cli
``` ```
### Install from git repository
### Install the latest development build through git
To get the latest bug fixes and features, you can install the development version from git.
However, this is not fully tested.
That means you're probably going to have more bugs despite having the latest bug fixes.
``` ```
cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli
``` ```
This will download the CLI from the master branch,
and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
### Install from local folder ### Install from local folder
``` ```
cargo install --path . --debug cargo install --path . --debug
``` ```
## Get started
## Get Started Use `dx create project-name` to initialize a new Dioxus project.
Use `dx create project-name` to initialize a new Dioxus project. <br>
It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template) repository. It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template) repository.
<br>
Alternatively, you can specify the template path: Alternatively, you can specify the template path:
``` ```
dx create hello --template gh:dioxuslabs/dioxus-template dx create hello --template gh:dioxuslabs/dioxus-template
``` ```
## Dioxus Config File Run `dx --help` for a list of all the available commands.
Furthermore, you can run `dx <command> --help` to get help with a specific command.
Dioxus CLI will use `Dioxus.toml` file to Identify some project info and switch some cli feature. ## Dioxus config file
You can get more configure information from [Dioxus CLI Document](https://dioxuslabs.com/cli/configure.html). You can use the `Dioxus.toml` file for further configuration.
Some fields are mandatory, but the CLI tool will tell you which ones are missing.
You can create a `Dioxus.toml` with all fields already set using `dx config init project-name`,
or you can use this bare-bones template (only mandatory fields) to get started:
```toml
[application]
name = "project-name"
# Currently supported platforms: web, desktop
default_platform = "web"
[web.app]
title = "Hello"
[web.watcher]
[web.resource.dev]
```
The full anatomy of `Dioxus.toml` is shown on the [Dioxus website](https://dioxuslabs.com/learn/0.4/CLI/configure).

View file

@ -3,4 +3,4 @@ authors = ["YuKun Liu"]
language = "en" language = "en"
multilingual = false multilingual = false
src = "src" src = "src"
title = "Dioxus Cli" title = "Dioxus CLI"

View file

@ -2,17 +2,12 @@
- [Introduction](./introduction.md) - [Introduction](./introduction.md)
- [Installation](./installation.md) - [Installation](./installation.md)
- [Create a Project](./creating.md) - [Create a project](./creating.md)
- [Configure Project](./configure.md) - [Configure a project](./configure.md)
- [Commands](./cmd/README.md) - [Plugin development](./plugin/README.md)
- [Build](./cmd/build.md) - [API.Log](plugin/interface/log.md)
- [Serve](./cmd/serve.md) - [API.Command](plugin/interface/command.md)
- [Clean](./cmd/clean.md) - [API.OS](plugin/interface/os.md)
- [Translate](./cmd/translate.md) - [API.Directories](plugin/interface/dirs.md)
- [Plugin Development](./plugin/README.md) - [API.Network](plugin/interface/network.md)
- [API.Log](./plugin/interface/log.md) - [API.Path](plugin/interface/path.md)
- [API.Command](./plugin/interface/command.md)
- [API.OS](./plugin/interface/os.md)
- [API.Directories](./plugin/interface/dirs.md)
- [API.Network](./plugin/interface/network.md)
- [API.Path](./plugin/interface/path.md)

View file

@ -1,30 +0,0 @@
# Commands
In this chapter we will introduce all `dioxus-cli` commands.
> You can also use `dx --help` to get cli help info.
```
Build, Bundle & Ship Dioxus Apps
Usage: dx [OPTIONS] <COMMAND>
Commands:
build Build the Rust WASM app and all of its assets
translate Translate some source file into Dioxus code
serve Build, watch & serve the Rust WASM app and all of its assets
create Init a new project for Dioxus
clean Clean output artifacts
bundle Bundle the Rust desktop app and all of its assets
version Print the version of this extension
fmt Format some rsx
check Check the Rust files in the project for issues
config Dioxus config file controls
help Print this message or the help of the given subcommand(s)
Options:
-v Enable verbose logging
--bin <BIN> Specify bin target
-h, --help Print help
-V, --version Print version
```

View file

@ -1,56 +0,0 @@
# Build
The `dx build` command can help you `pack & build` a dioxus project.
```
dioxus-build
Build the Rust WASM app and all of its assets
USAGE:
dx build [OPTIONS]
OPTIONS:
--example <EXAMPLE> [default: ""]
--platform <PLATFORM> [default: "default_platform"]
--release [default: false]
--bin [default: None]
```
You can use this command to build a project:
```
dx build --release
```
## Target platform
Use the `platform` option to choose your target platform:
```
# for desktop project
dx build --platform desktop
```
`platform` currently only supports `desktop` & `web`.
```
# for web project
dx build --platform web
```
## Specify workspace bin
You can add the `--bin` option to select which crate you want Dioxus to build:
```
dx build --bin app
```
## Build Example
You can use the `example` option to select a example to build:
```
# build the `test` example
dx build --exmaple test
```

View file

@ -1,27 +0,0 @@
# Clean
`dx clean` will clear the build artifacts (the out_dir and the cargo cache)
```
dioxus-clean
Clean build artifacts
USAGE:
dx clean [OPTIONS]
OPTIONS:
--bin [default: None]
```
# Example
```
dx clean
```
# Specify workspace bin
You can add the `--bin` option to select which crate you want Dioxus to clean artifacts from:
```
dx clean --bin app
```

View file

@ -1,70 +0,0 @@
# Serve
The `dx serve` can start a dev server with hot-reloading
```
dioxus-serve
Build, watch & serve the Rust WASM app and all of its assets
USAGE:
dx serve [OPTIONS]
OPTIONS:
--example <EXAMPLE> [default: ""]
--platform <PLATFORM> [default: "default_platform"]
--release [default: false]
--hot-reload [default: false]
--bin [default: None]
```
You can use this command to build project and start a dev server:
```
dx serve
```
## Serve Example
You can use the `example` option to serve a example:
```
# serve the `test` example
dx serve --exmaple test
```
## Specify workspace bin
You can add the `--bin` option to select which crate you want Dioxus to build and serve:
```
dx serve --bin app
```
## Open Browser
You can add the `--open` option to open system default browser when server startup:
```
dx serve --open
```
## RSX Hot Reloading
You can add the `--hot-reload` flag to enable [rsx hot reloading](https://dioxuslabs.com/docs/0.3/guide/en/getting_started/hot_reload.html). This will allow you to reload some rsx changes without a full recompile:
```
dx serve --open
```
## Cross Origin Policy
You can add the `cross-origin-policy` option to change cross-origin header to:
```
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
```
```
dx serve --corss-origin-policy
```

View file

@ -1,68 +0,0 @@
# Translate
`dx translate` can translate some `html` file into a Dioxus compoent
```
dioxus-translate
Translate some source file into a Dioxus component
USAGE:
dx translate [OPTIONS] [OUTPUT]
ARGS:
<OUTPUT> Output file, defaults to stdout if not present
OPTIONS:
-c, --component Activate debug mode
-f, --file <FILE> Input file
```
## Translate HTML to stdout
You can use the `file` option to set path to the `html` file to translate:
```
dx transtale --file ./index.html
```
## Output rsx to a file
You can pass a file to the traslate command to set the path to write the output of the command to:
```
dx translate --file ./index.html component.rsx
```
## Output rsx to a file
Setting the `component` option will create a compoent from the HTML:
```
dx translate --file ./index.html --component
```
## Example
This HTML:
```html
<div>
<h1> Hello World </h1>
<a href="https://dioxuslabs.com/">Link</a>
</div>
```
Translates into this Dioxus component:
```rust
fn component(cx: Scope) -> Element {
cx.render(rsx! {
div {
h1 { "Hello World" },
a {
href: "https://dioxuslabs.com/",
"Link"
}
}
})
}
```

View file

@ -1,166 +1,155 @@
# Configure Project # Configure Project
This chapter will teach you how to configure the CLI with the `Dioxus.toml` file.
There's an [example](#config-example) which has comments to describe individual keys.
You can copy that or view this documentation for a more complete learning experience.
This chapter will introduce you to how to configure the CLI with your `Dioxus.toml` file "🔒" indicates a mandatory item. Some headers are mandatory, but none of the keys inside them are. It might look weird, but it's normal. Simply don't include any keys.
Be aware that if the config file is present in the folder, some fields must be filled out, or the CLI tool will abort. The mandatory [table headers](https://toml.io/en/v1.0.0#table) and keys will have a '✍' sign beside it.
## Structure ## Structure
The CLI uses a `Dioxus.toml` file in the root of your crate to define some configuration for your `dioxus` project. Each header has it's TOML form directly under it.
### Application ### Application 🔒
General application confiration: ```toml
```
[application] [application]
# configuration
``` ```
1. ***name*** ✍ - project name & title
2. ***default_platform*** ✍ - which platform target for this project.
Application-wide configuration. Applies to both web and desktop.
1. **name** 🔒 - Project name & title.
```toml
name = "my_project"
``` ```
name = "my-project"
``` 2. **default_platform** 🔒 - The platform this project targets
2. ***default_platform*** - The platform this project targets ```toml
```ß # Currently supported platforms: web, desktop
# current supported platforms: web, desktop
# default: web
default_platform = "web" default_platform = "web"
``` ```
if you change this to `desktop`, the `dx build` will default building a desktop app
3. ***out_dir*** - The directory to place the build artifacts from `dx build` or `dx service` into. This is also where the `assets` directory will be copied to 3. **out_dir** - The directory to place the build artifacts from `dx build` or `dx serve` into. This is also where the `assets` directory will be copied into.
``` ```toml
out_dir = "dist" out_dir = "dist"
``` ```
4. ***asset_dir*** - The directory with your static assets. The CLI will automatically copy these assets into the ***out_dir*** after a build/serve.
``` 4. **asset_dir** - The directory with your static assets. The CLI will automatically copy these assets into the **out_dir** after a build/serve.
```toml
asset_dir = "public" asset_dir = "public"
``` ```
5. ***sub_package*** - The sub package in the workspace to build by default
``` 5. **sub_package** - The sub package in the workspace to build by default.
```toml
sub_package = "my-crate" sub_package = "my-crate"
``` ```
### Web.App ### Web.App 🔒
Configeration specific to web applications: ```toml
```
[web.app] [web.app]
# configuration
``` ```
1. ***title*** - The title of the web page Web-specific configuration.
```
1. **title** - The title of the web page.
```toml
# HTML title tag content # HTML title tag content
title = "dioxus app | ⛺" title = "project_name"
```
2. ***base_path*** - The base path to build the appliation for serving at. This can be useful when serving your application in a subdirectory under a domain. For example when building a site to be served on github pages.
``` ```
2. **base_path** - The base path to build the application for serving at. This can be useful when serving your application in a subdirectory under a domain. For example when building a site to be served on GitHub Pages.
```toml
# The application will be served at domain.com/my_application/, so we need to modify the base_path to the path where the application will be served # The application will be served at domain.com/my_application/, so we need to modify the base_path to the path where the application will be served
base_path = "my_application" base_path = "my_application"
``` ```
### Web.Watcher ✍ ### Web.Watcher ✍
Configeration related to the development server: ```toml
```
[web.watcher] [web.watcher]
# configuration
``` ```
1. ***reload_html*** - If this is true, the cli will rebuild the index.html file every time the application is rebuilt Development server configuration.
```
1. **reload_html** - If this is true, the cli will rebuild the index.html file every time the application is rebuilt
```toml
reload_html = true reload_html = true
``` ```
2. ***watch_path*** - The files & directories to moniter for changes
``` 2. **watch_path** - The files & directories to monitor for changes
```toml
watch_path = ["src", "public"] watch_path = ["src", "public"]
``` ```
3. ***index_on_404*** - If enabled, Dioxus CLI will serve the root page when a route is not found. *This is needed when serving an application that uses the router*
``` 3. **index_on_404** - If enabled, Dioxus will serve the root page when a route is not found.
*This is needed when serving an application that uses the router*.
However, when serving your app using something else than Dioxus (e.g. GitHub Pages), you will have to check how to configure it on that platform.
In GitHub Pages, you can make a copy of `index.html` named `404.html` in the same directory.
```toml
index_on_404 = true index_on_404 = true
``` ```
### Web.Resource ✍ ### Web.Resource 🔒
Configeration related to static resources your application uses: ```toml
```
[web.resource] [web.resource]
# configuration
``` ```
1. ***style*** - The styles (`.css` files) to include in your application Static resource configuration.
```
1. **style** - CSS files to include in your application.
```toml
style = [ style = [
# include from public_dir. # Include from public_dir.
"./assets/style.css", "./assets/style.css",
# or some asset from online cdn. # Or some asset from online cdn.
"https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css" "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
] ]
``` ```
2. ***script*** - The additional scripts (`.js` files) to include in your application
``` 2. **script** - JavaScript files to include in your application.
style = [ ```toml
# include from public_dir. script = [
"./assets/index.js", # Include from asset_dir.
# or some asset from online cdn. "./public/index.js",
# Or from an online CDN.
"https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js" "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
] ]
``` ```
### Web.Resource.Dev ### Web.Resource.Dev 🔒
Configeration related to static resources your application uses in development: ```toml
```
[web.resource.dev] [web.resource.dev]
# configuration
``` ```
1. ***style*** - The styles (`.css` files) to include in your application This is the same as [`[web.resource]`](#webresource-), but it only works in development servers.
``` For example, if you want to include a file in a `dx serve` server, but not a `dx serve --release` server, put it here.
style = [
# include from public_dir.
"./assets/style.css",
# or some asset from online cdn.
"https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
]
```
2. ***script*** - The additional scripts (`.js` files) to include in your application
```
style = [
# include from public_dir.
"./assets/index.js",
# or some asset from online cdn.
"https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
]
```
### Web.Proxy ### Web.Proxy
Configeration related to any proxies your application requires durring development. Proxies will forward requests to a new service ```toml
```
[[web.proxy]] [[web.proxy]]
# configuration
``` ```
1. ***backend*** - The URL to the server to proxy. The CLI will forward any requests under the backend relative route to the backend instead of returning 404 Configuration related to any proxies your application requires during development. Proxies will forward requests to a new service.
```
1. **backend** - The URL to the server to proxy. The CLI will forward any requests under the backend relative route to the backend instead of returning 404
```toml
backend = "http://localhost:8000/api/" backend = "http://localhost:8000/api/"
``` ```
This will cause any requests made to the dev server with prefix /api/ to be redirected to the backend server at http://localhost:8000. The path and query parameters will be passed on as-is (path rewriting is not currently supported). This will cause any requests made to the dev server with prefix /api/ to be redirected to the backend server at http://localhost:8000. The path and query parameters will be passed on as-is (path rewriting is currently not supported).
## Config example ## Config example
This includes all fields, mandatory or not.
```toml ```toml
[application] [application]
# App (Project) Name # App name
name = "{{project-name}}" name = "project_name"
# The Dioxus platform to default to # The Dioxus platform to default to
default_platform = "web" default_platform = "web"
@ -168,23 +157,23 @@ default_platform = "web"
# `build` & `serve` output path # `build` & `serve` output path
out_dir = "dist" out_dir = "dist"
# the static resource path # The static resource path
asset_dir = "public" asset_dir = "public"
[web.app] [web.app]
# HTML title tag content # HTML title tag content
title = "dioxus | ⛺" title = "project_name"
[web.watcher] [web.watcher]
# when watcher is triggered, regenerate the `index.html` # When watcher is triggered, regenerate the `index.html`
reload_html = true reload_html = true
# which files or dirs will be monitored # Which files or dirs will be monitored
watch_path = ["src", "public"] watch_path = ["src", "public"]
# include `assets` in web platform # Include style or script assets
[web.resource] [web.resource]
# CSS style file # CSS style file
@ -195,12 +184,12 @@ script = []
[web.resource.dev] [web.resource.dev]
# serve: [dev-server] only # Same as [web.resource], but for development servers
# CSS style file # CSS style file
style = [] style = []
# Javascript code file # JavaScript files
script = [] script = []
[[web.proxy]] [[web.proxy]]

View file

@ -1,39 +1,37 @@
# Create a Project # Create a Project
Once you have the Dioxus CLI tool installed, you can use it to create dioxus project. Once you have the Dioxus CLI installed, you can use it to create your own project!
## Initializing a default project ## Initializing a default project
First, run the `dx create` command to create a new project ready to be used with Dioxus and the Dioxus CLI: First, run the `dx create` command to create a new project:
``` ```
dx create hello-dioxus dx create hello-dioxus
``` ```
> It will clone a default template from github template: [DioxusLabs/dioxus-template](https://github.com/DioxusLabs/dioxus-template) > It will clone this [template](https://github.com/DioxusLabs/dioxus-template).
> This default template is use for `web` platform application. > This default template is used for `web` platform application.
> >
> You can choose to create your project from a different template by passing the `template` argument: > You can choose to create your project from a different template by passing the `template` argument:
> ``` > ```
> dx init hello-dioxus --template=gh:dioxuslabs/dioxus-template > dx init hello-dioxus --template=gh:dioxuslabs/dioxus-template
> ``` > ```
Next, move the current directory into your new project: Next, navigate into your new project:
``` ```
cd hello-dioxus cd hello-dioxus
``` ```
> Make sure `wasm32 target` is installed before running the Web project. > Make sure the WASM target is installed before running the projects.
> You can install the wasm target for rust using rustup: > You can install the WASM target for rust using rustup:
> ``` > ```
> rustup target add wasm32-unknown-unknown > rustup target add wasm32-unknown-unknown
> ``` > ```
Finally, create serve your project with the Dioxus CLI: Finally, serve your project:
``` ```
dx serve dx serve
``` ```
By default, the CLI serve your site at: [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/) By default, the CLI serves your website at [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/).

View file

@ -1,22 +1,23 @@
# Installation # Installation
Choose any one of the methods below to install the Dioxus CLI: ## Install the latest development build through git
## Install from latest git version To get the latest bug fixes and features, you can install the development version from git.
To get the most up to date bug fixes and features of the Dioxus CLI, you can install the development version from git.
``` ```
cargo install --git https://github.com/Dioxuslabs/cli cargo install --git https://github.com/Dioxuslabs/cli
``` ```
This will automatically download `Dioxus-CLI` source from github master branch, This will download `Dioxus-CLI` source from GitHub master branch,
and install it in Cargo's global binary directory (`~/.cargo/bin/` by default). and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
## Install from `crates.io` version ## Install stable through `crates.io`
The published version of the Dioxus CLI is updated less often, but should be more stable than the git version of the Dioxus CLI. The published version of the Dioxus CLI is updated less often, but is more stable than the git version.
``` ```
cargo install dioxus-cli cargo install dioxus-cli
``` ```
Run `dx --help` for a list of all the available commands.
Furthermore, you can run `dx <COMMAND> --help` to get help with a specific command.

View file

@ -1,21 +1,18 @@
# Introduction # Introduction
📦✨ **Dioxus-Cli** is a tool to help get dioxus projects off the ground. The 📦✨ **Dioxus CLI** is a tool to help get Dioxus projects off the ground.
![dioxus-logo](https://dioxuslabs.com/guide/images/dioxuslogo_full.png)
It includes `dev server`, `hot reload` and some `quick command` to help you use dioxus.
## Features ## Features
* Build and pack a Dioxus project
* `html` to `rsx` conversion tool
* Hot Reload for `web` platform
* Create a Dioxus project from `git` repo
* And more!
<!-- Checkmarks don't render on the website, so I've just made a normal list. You can uncomment this if the website rendering is fixed.
- [x] `html` to `rsx` conversion tool - [x] `html` to `rsx` conversion tool
- [x] hot reload for `web` platform - [x] Hot Reload for `web` platform
- [x] create dioxus project from `git` repo - [x] Create a Dioxus project from `git` repo
- [x] build & pack dioxus project - [x] Build & pack Dioxus project
- [ ] autoformat dioxus `rsx` code - [ ] Automatically format Dioxus `rsx` code
-->
## Contributors
Contributors to this guide:
- [mrxiaozhuox](https://github.com/mrxiaozhuox)

View file

@ -1,24 +1,85 @@
# CLI Plugin Development # CLI Plugin development
> For Cli 0.2.0 we will add `plugin-develop` support. **IMPORTANT: Ignore this documentation. Plugins are yet to be released and chances are it won't work for you. This is just what plugins *could* look like.**
Before the 0.2.0 we use `dx tool` to use & install some plugin, but we think that is not good for extend cli program, some people want tailwind support, some people want sass support, we can't add all this thing in to the cli source code and we don't have time to maintain a lot of tools that user request, so maybe user make plugin by themself is a good choice. In the past we used `dx tool` to use and install tools, but it was a flawed system.
Tools were hard-coded by us, but people want more tools than we could code, so this plugin system was made to let
anyone develop plugins and use them in Dioxus projects.
### Why Lua ? Plugin resources:
* [Source code](https://github.com/DioxusLabs/dioxus/tree/master/packages/cli/src/plugin)
* [Unofficial Dioxus plugin community](https://github.com/DioxusPluginCommunity). Contains certain plugins you can use right now.
We choose `Lua: 5.4` to be the plugin develop language, because cli plugin is not complex, just like a workflow, and user & developer can write some easy code for their plugin. We have **vendored** lua in cli program, and user don't need install lua runtime in their computer, and the lua parser & runtime doesn't take up much disk memory. ### Why Lua?
### Event Management We chose Lua `5.4` to be the plugin developing language,
because it's extremely lightweight, embeddable and easy to learn.
We installed Lua into the CLI, so you don't need to do it yourself.
The plugin library have pre-define some important event you can control: Lua resources:
* [Official website](https://www.lua.org/). You can basically find everything here.
* [Awesome Lua](https://github.com/LewisJEllis/awesome-lua). Additional resources (such as Lua plugins for your favorite IDE), and other *awesome* tools!
- `build.on_start`
- `build.on_finished`
- `serve.on_start`
- `serve.on_rebuild`
- `serve.on_shutdown`
### Plugin Template ## Creating a plugin
A plugin is just an `init.lua` file.
You can include other files using `dofile(path)`.
You need to have a plugin and a manager instance, which you can get using `require`:
```lua
local plugin = require("plugin")
local manager = require("manager")
```
You need to set some `manager` fields and then initialize the plugin:
```lua
manager.name = "My first plugin"
manager.repository = "https://github.com/john-doe/my-first-plugin" -- The repository URL.
manager.author = "John Doe <john.doe@example.com>"
manager.version = "0.1.0"
plugin.init(manager)
```
You also need to return the `manager`, which basically represents your plugin:
```lua
-- Your code here.
-- End of file.
manager.serve.interval = 1000
return manager
```
And you're ready to go. Now, go and have a look at the stuff below and the API documentation.
### Plugin info
You will encounter this type in the events below. The keys are as follows:
* `name: string` - The name of the plugin.
* `repository: string` - The plugin repository URL.
* `author: string` - The author of the plugin.
* `version: string` - The plugin version.
### Event management
The plugin library has certain events that you can subscribe to.
* `manager.on_init` - Triggers the first time the plugin is loaded.
* `manager.build.on_start(info)` - Triggers before the build process. E.g., before `dx build`.
* `manager.build.on_finish(info)` - Triggers after the build process. E.g., after `dx build`.
* `manager.serve.on_start(info)` - Triggers before the serving process. E.g., before `dx serve`.
* `manager.serve.on_rebuild_start(info)` - Triggers before the server rebuilds the web with hot reload.
* `manager.serve.on_rebuild_end(info)` - Triggers after the server rebuilds the web with hot reload.
* `manager.serve.on_shutdown` - Triggers when the server is shutdown. E.g., when the `dx serve` process is terminated.
To subscribe to an event, you simply need to assign it to a function:
```lua
manager.build.on_start = function (info)
log.info("[plugin] Build starting: " .. info.name)
end
```
### Plugin template
```lua ```lua
package.path = library_dir .. "/?.lua" package.path = library_dir .. "/?.lua"

View file

@ -1,15 +1,15 @@
# Command Functions # Command Functions
> you can use command functions to execute some code & script You can use command functions to execute code and scripts.
Type Define: Type definition:
``` ```
Stdio: "Inherit" | "Piped" | "Null" Stdio: "Inherit" | "Piped" | "Null"
``` ```
### `exec(commands: [string], stdout: Stdio, stderr: Stdio)` ### `exec(commands: [string], stdout: Stdio, stderr: Stdio)`
you can use this function to run some command on the current system. You can use this function to run some commands on the current system.
```lua ```lua
local cmd = plugin.command local cmd = plugin.command
@ -18,4 +18,4 @@ manager.test = function ()
cmd.exec({"git", "clone", "https://github.com/DioxusLabs/cli-plugin-library"}) cmd.exec({"git", "clone", "https://github.com/DioxusLabs/cli-plugin-library"})
end end
``` ```
> Warning: This function don't have exception catch. > Warning: This function doesn't catch exceptions.

View file

@ -1,33 +1,28 @@
# Dirs Functions # Dirs Functions
> you can use Dirs functions to get some directory path Dirs functions are for getting various directory paths. Not to be confused with `plugin.path`.
### `plugin_dir() -> string`
### plugin_dir() -> string Get the plugin's root directory path.
You can get current plugin **root** directory path
```lua ```lua
local path = plugin.dirs.plugin_dir() local path = plugin.dirs.plugin_dir()
-- example: ~/Development/DioxusCli/plugin/test-plugin/ -- example: ~/Development/DioxusCli/plugin/test-plugin/
``` ```
### bin_dir() -> string ### `bin_dir() -> string`
You can get plugin **bin** direcotry path Get the plugin's binary directory path. Put binary files like `tailwind-cli` or `sass-cli` in this directory.
Sometime you need install some binary file like `tailwind-cli` & `sass-cli` to help your plugin work, then you should put binary file in this directory.
```lua ```lua
local path = plugin.dirs.bin_dir() local path = plugin.dirs.bin_dir()
-- example: ~/Development/DioxusCli/plugin/test-plugin/bin/ -- example: ~/Development/DioxusCli/plugin/test-plugin/bin/
``` ```
### temp_dir() -> string ### `temp_dir() -> string`
You can get plugin **temp** direcotry path Get the plugin's temporary directory path. Put any temporary files here.
Just put some temporary file in this directory.
```lua ```lua
local path = plugin.dirs.bin_dir() local path = plugin.dirs.bin_dir()

View file

@ -1,46 +1,46 @@
# Log Functions # Log Functions
> You can use log function to print some useful log info You can use log functions to print various logging information.
### Trace(info: string) ### `trace(info: string)`
Print trace log info Print trace log info.
```lua ```lua
local log = plugin.log local log = plugin.log
log.trace("trace information") log.trace("trace information")
``` ```
### Debug(info: string) ### `debug(info: string)`
Print debug log info Print debug log info.
```lua ```lua
local log = plugin.log local log = plugin.log
log.debug("debug information") log.debug("debug information")
``` ```
### Info(info: string) ### `info(info: string)`
Print info log info Print info log info.
```lua ```lua
local log = plugin.log local log = plugin.log
log.info("info information") log.info("info information")
``` ```
### Warn(info: string) ### `warn(info: string)`
Print warning log info Print warning log info.
```lua ```lua
local log = plugin.log local log = plugin.log
log.warn("warn information") log.warn("warn information")
``` ```
### Error(info: string) ### `error(info: string)`
Print error log info Print error log info.
```lua ```lua
local log = plugin.log local log = plugin.log

View file

@ -1,12 +1,13 @@
# Network Functions # Network Functions
> you can use Network functions to download & read some data from internet You can use Network functions to download & read some data from the internet.
### download_file(url: string, path: string) -> boolean ### `download_file(url: string, path: string) -> boolean`
This function can help you download some file from url, and it will return a *boolean* value to check the download status. (true: success | false: fail) Downloads a file from the specified URL,
and returns a `boolean` that represents the download status (true: success, false: failure).
You need pass a target url and a local path (where you want to save this file) You need to pass a target URL and a local path (where you want to save this file).
```lua ```lua
-- this file will download to plugin temp directory -- this file will download to plugin temp directory
@ -19,9 +20,11 @@ if status != true then
end end
``` ```
### clone_repo(url: string, path: string) -> boolean ### `clone_repo(url: string, path: string) -> boolean`
This function can help you use `git clone` command (this system must have been installed git) Clone a repository from the given URL into the given path.
Returns a `boolean` that represents the clone status (true: success, false: failure).
The system executing this function must have git installed.
```lua ```lua
local status = plugin.network.clone_repo( local status = plugin.network.clone_repo(

View file

@ -1,10 +1,10 @@
# OS Functions # OS Functions
> you can use OS functions to get some system information OS functions are for getting system information.
### current_platform() -> string ("windows" | "macos" | "linux") ### `current_platform() -> string ("windows" | "macos" | "linux")`
This function can help you get system & platform type: Get the current OS platform.
```lua ```lua
local platform = plugin.os.current_platform() local platform = plugin.os.current_platform()

View file

@ -1,10 +1,13 @@
# Path Functions # Path Functions
> you can use path functions to operate valid path string You can use path functions to perform operations on valid path strings.
### join(path: string, extra: string) -> string ### `join(path: string, extra: string) -> string`
This function can help you extend a path, you can extend any path, dirname or filename. <!-- TODO: Add specifics.
From the example given, it seems like it just creates a subdirectory path.
What would it do when "extending" file paths? -->
Extend a path; you can extend both directory and file paths.
```lua ```lua
local current_path = "~/hello/dioxus" local current_path = "~/hello/dioxus"
@ -12,9 +15,9 @@ local new_path = plugin.path.join(current_path, "world")
-- new_path = "~/hello/dioxus/world" -- new_path = "~/hello/dioxus/world"
``` ```
### parent(path: string) -> string ### `parent(path: string) -> string`
This function will return `path` parent-path string, back to the parent. Return the parent path of the specified path. The parent path is always a directory.
```lua ```lua
local current_path = "~/hello/dioxus" local current_path = "~/hello/dioxus"
@ -22,14 +25,14 @@ local new_path = plugin.path.parent(current_path)
-- new_path = "~/hello/" -- new_path = "~/hello/"
``` ```
### exists(path: string) -> boolean ### `exists(path: string) -> boolean`
This function can check some path (dir & file) is exists. Check if the specified path exists, as either a file or a directory.
### is_file(path: string) -> boolean ### `is_file(path: string) -> boolean`
This function can check some path is a exist file. Check if the specified path is a file.
### is_dir(path: string) -> boolean ### `is_dir(path: string) -> boolean`
This function can check some path is a exist dir. Check if the specified path is a directory.

View file

@ -1,4 +1,4 @@
/// Creats a callback that will be run before the component is removed. This can be used to clean up side effects from the component (created with use_effect) /// Creates a callback that will be run before the component is removed. This can be used to clean up side effects from the component (created with use_effect)
/// ///
/// Example: /// Example:
/// ```rust /// ```rust

View file

@ -2,7 +2,7 @@ use std::{
any::Any, any::Any,
collections::HashSet, collections::HashSet,
rc::Rc, rc::Rc,
sync::{Arc, RwLock, RwLockWriteGuard}, sync::{Arc, RwLock},
}; };
use dioxus::prelude::*; use dioxus::prelude::*;
@ -36,7 +36,7 @@ struct MutableRouterState {
/// A collection of router data that manages all routing functionality. /// A collection of router data that manages all routing functionality.
#[derive(Clone)] #[derive(Clone)]
pub struct RouterContext { pub struct RouterContext {
state: Arc<RwLock<MutableRouterState>>, state: Rc<RefCell<MutableRouterState>>,
subscribers: Arc<RwLock<HashSet<ScopeId>>>, subscribers: Arc<RwLock<HashSet<ScopeId>>>,
subscriber_update: Arc<dyn Fn(ScopeId)>, subscriber_update: Arc<dyn Fn(ScopeId)>,
@ -56,7 +56,7 @@ impl RouterContext {
R: Clone, R: Clone,
<R as std::str::FromStr>::Err: std::fmt::Display, <R as std::str::FromStr>::Err: std::fmt::Display,
{ {
let state = Arc::new(RwLock::new(MutableRouterState { let state = Rc::new(RefCell::new(MutableRouterState {
prefix: Default::default(), prefix: Default::default(),
history: cfg.take_history(), history: cfg.take_history(),
unresolved_error: None, unresolved_error: None,
@ -105,7 +105,7 @@ impl RouterContext {
// set the updater // set the updater
{ {
let mut state = myself.state.write().unwrap(); let mut state = myself.state.borrow_mut();
state.history.updater(Arc::new(move || { state.history.updater(Arc::new(move || {
for &id in subscribers.read().unwrap().iter() { for &id in subscribers.read().unwrap().iter() {
(mark_dirty)(id); (mark_dirty)(id);
@ -117,20 +117,20 @@ impl RouterContext {
} }
pub(crate) fn route_from_str(&self, route: &str) -> Result<Rc<dyn Any>, String> { pub(crate) fn route_from_str(&self, route: &str) -> Result<Rc<dyn Any>, String> {
let state = self.state.read().unwrap(); let state = self.state.borrow();
state.history.parse_route(route) state.history.parse_route(route)
} }
/// Check whether there is a previous page to navigate back to. /// Check whether there is a previous page to navigate back to.
#[must_use] #[must_use]
pub fn can_go_back(&self) -> bool { pub fn can_go_back(&self) -> bool {
self.state.read().unwrap().history.can_go_back() self.state.borrow().history.can_go_back()
} }
/// Check whether there is a future page to navigate forward to. /// Check whether there is a future page to navigate forward to.
#[must_use] #[must_use]
pub fn can_go_forward(&self) -> bool { pub fn can_go_forward(&self) -> bool {
self.state.read().unwrap().history.can_go_forward() self.state.borrow().history.can_go_forward()
} }
/// Go back to the previous location. /// Go back to the previous location.
@ -138,7 +138,7 @@ impl RouterContext {
/// Will fail silently if there is no previous location to go to. /// Will fail silently if there is no previous location to go to.
pub fn go_back(&self) { pub fn go_back(&self) {
{ {
self.state.write().unwrap().history.go_back(); self.state.borrow_mut().history.go_back();
} }
self.change_route(); self.change_route();
@ -149,7 +149,7 @@ impl RouterContext {
/// Will fail silently if there is no next location to go to. /// Will fail silently if there is no next location to go to.
pub fn go_forward(&self) { pub fn go_forward(&self) {
{ {
self.state.write().unwrap().history.go_forward(); self.state.borrow_mut().history.go_forward();
} }
self.change_route(); self.change_route();
@ -206,8 +206,7 @@ impl RouterContext {
/// The route that is currently active. /// The route that is currently active.
pub fn current<R: Routable>(&self) -> R { pub fn current<R: Routable>(&self) -> R {
self.state self.state
.read() .borrow()
.unwrap()
.history .history
.current_route() .current_route()
.downcast::<R>() .downcast::<R>()
@ -218,7 +217,7 @@ impl RouterContext {
/// The route that is currently active. /// The route that is currently active.
pub fn current_route_string(&self) -> String { pub fn current_route_string(&self) -> String {
self.any_route_to_string(&*self.state.read().unwrap().history.current_route()) self.any_route_to_string(&*self.state.borrow().history.current_route())
} }
pub(crate) fn any_route_to_string(&self, route: &dyn Any) -> String { pub(crate) fn any_route_to_string(&self, route: &dyn Any) -> String {
@ -243,7 +242,7 @@ impl RouterContext {
/// The prefix that is currently active. /// The prefix that is currently active.
pub fn prefix(&self) -> Option<String> { pub fn prefix(&self) -> Option<String> {
self.state.read().unwrap().prefix.clone() self.state.borrow().prefix.clone()
} }
fn external(&self, external: String) -> Option<ExternalNavigationFailure> { fn external(&self, external: String) -> Option<ExternalNavigationFailure> {
@ -261,8 +260,8 @@ impl RouterContext {
} }
} }
fn state_mut(&self) -> RwLockWriteGuard<MutableRouterState> { fn state_mut(&self) -> RefMut<MutableRouterState> {
self.state.write().unwrap() self.state.borrow_mut()
} }
/// Manually subscribe to the current route /// Manually subscribe to the current route
@ -283,15 +282,14 @@ impl RouterContext {
/// Clear any unresolved errors /// Clear any unresolved errors
pub fn clear_error(&self) { pub fn clear_error(&self) {
self.state.write().unwrap().unresolved_error = None; self.state.borrow_mut().unresolved_error = None;
self.update_subscribers(); self.update_subscribers();
} }
pub(crate) fn render_error<'a>(&self, cx: Scope<'a>) -> Element<'a> { pub(crate) fn render_error<'a>(&self, cx: Scope<'a>) -> Element<'a> {
self.state self.state
.read() .borrow()
.unwrap()
.unresolved_error .unresolved_error
.as_ref() .as_ref()
.and_then(|_| (self.failure_external_navigation)(cx)) .and_then(|_| (self.failure_external_navigation)(cx))

View file

@ -22,7 +22,11 @@ impl<E: std::fmt::Display> std::fmt::Display for RouteParseError<E> {
} }
} }
/// Something that can be created from a query string /// Something that can be created from a query string.
///
/// This trait needs to be implemented if you want to turn a query string into a struct.
///
/// A working example can be found in the `examples` folder in the root package under `query_segments_demo`
pub trait FromQuery { pub trait FromQuery {
/// Create an instance of `Self` from a query string /// Create an instance of `Self` from a query string
fn from_query(query: &str) -> Self; fn from_query(query: &str) -> Self;

View file

@ -392,6 +392,7 @@ fn read_input_to_data(target: Element) -> Rc<FormData> {
.dyn_ref() .dyn_ref()
.and_then(|input: &web_sys::HtmlInputElement| { .and_then(|input: &web_sys::HtmlInputElement| {
input.files().and_then(|files| { input.files().and_then(|files| {
#[allow(clippy::arc_with_non_send_sync)]
crate::file_engine::WebFileEngine::new(files) crate::file_engine::WebFileEngine::new(files)
.map(|f| std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>) .map(|f| std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>)
}) })