Merge branch 'DioxusLabs:master' into intigrate-collect-assets
This commit is contained in:
10 files changed
+136
-102
No files matched your search
@@ -44,7 +44,7 @@ jobs:
|
|||||||
# args: --path packages/cli
|
# args: --path packages/cli
|
||||||
- name: Run Playwright tests
|
- name: Run Playwright tests
|
||||||
run: npx playwright test
|
run: npx playwright test
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: playwright-report
|
name: playwright-report
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ So... Dioxus is great, but why won't it work for me?
|
|||||||
## Contributing
|
## Contributing
|
||||||
- Check out the website [section on contributing](https://dioxuslabs.com/learn/0.4/contributing).
|
- Check out the website [section on contributing](https://dioxuslabs.com/learn/0.4/contributing).
|
||||||
- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues).
|
- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues).
|
||||||
- Join the discord and ask questions!
|
- [Join](https://discord.gg/XgGxMSkvUM) the discord and ask questions!
|
||||||
|
|
||||||
|
|
||||||
<a href="https://github.com/dioxuslabs/dioxus/graphs/contributors">
|
<a href="https://github.com/dioxuslabs/dioxus/graphs/contributors">
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ dioxus-html = { workspace = true, features = ["hot-reload-context"] }
|
|||||||
dioxus-core = { workspace = true, features = ["serialize"] }
|
dioxus-core = { workspace = true, features = ["serialize"] }
|
||||||
dioxus-hot-reload = { workspace = true }
|
dioxus-hot-reload = { workspace = true }
|
||||||
interprocess-docfix = { version = "1.2.2" }
|
interprocess-docfix = { version = "1.2.2" }
|
||||||
|
gitignore = "1.0.8"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ It handles building, bundling, development and publishing to simplify developmen
|
|||||||
|
|
||||||
### Install the stable version (recommended)
|
### Install the stable version (recommended)
|
||||||
|
|
||||||
```
|
```shell
|
||||||
cargo install dioxus-cli
|
cargo install dioxus-cli
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ To get the latest bug fixes and features, you can install the development versio
|
|||||||
However, this is not fully tested.
|
However, this is not fully tested.
|
||||||
That means you're probably going to have more bugs despite having the latest bug fixes.
|
That means you're probably going to have more bugs despite having the latest bug fixes.
|
||||||
|
|
||||||
```
|
```shell
|
||||||
cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli
|
cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
|
|||||||
|
|
||||||
### Install from local folder
|
### Install from local folder
|
||||||
|
|
||||||
```
|
```shell
|
||||||
cargo install --path . --debug
|
cargo install --path . --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxu
|
|||||||
|
|
||||||
Alternatively, you can specify the template path:
|
Alternatively, you can specify the template path:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
dx create hello --template gh:dioxuslabs/dioxus-template
|
dx create hello --template gh:dioxuslabs/dioxus-template
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -274,7 +274,6 @@ pub fn build_desktop(
|
|||||||
let mut cmd = subprocess::Exec::cmd("cargo")
|
let mut cmd = subprocess::Exec::cmd("cargo")
|
||||||
.cwd(&config.crate_dir)
|
.cwd(&config.crate_dir)
|
||||||
.arg("build")
|
.arg("build")
|
||||||
.arg("--quiet")
|
|
||||||
.arg("--message-format=json");
|
.arg("--message-format=json");
|
||||||
|
|
||||||
if config.release {
|
if config.release {
|
||||||
@@ -282,6 +281,8 @@ pub fn build_desktop(
|
|||||||
}
|
}
|
||||||
if config.verbose {
|
if config.verbose {
|
||||||
cmd = cmd.arg("--verbose");
|
cmd = cmd.arg("--verbose");
|
||||||
|
} else {
|
||||||
|
cmd = cmd.arg("--quiet");
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.custom_profile.is_some() {
|
if config.custom_profile.is_some() {
|
||||||
|
|||||||
@@ -27,15 +27,17 @@ pub struct Autoformat {
|
|||||||
impl Autoformat {
|
impl Autoformat {
|
||||||
// Todo: autoformat the entire crate
|
// Todo: autoformat the entire crate
|
||||||
pub async fn autoformat(self) -> Result<()> {
|
pub async fn autoformat(self) -> Result<()> {
|
||||||
|
let Autoformat { check, raw, file } = self;
|
||||||
|
|
||||||
// Default to formatting the project
|
// Default to formatting the project
|
||||||
if self.raw.is_none() && self.file.is_none() {
|
if raw.is_none() && file.is_none() {
|
||||||
if let Err(e) = autoformat_project(self.check).await {
|
if let Err(e) = autoformat_project(check).await {
|
||||||
eprintln!("error formatting project: {}", e);
|
eprintln!("error formatting project: {}", e);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(raw) = self.raw {
|
if let Some(raw) = raw {
|
||||||
let indent = indentation_for(".")?;
|
let indent = indentation_for(".")?;
|
||||||
if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0, indent) {
|
if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0, indent) {
|
||||||
println!("{}", inner);
|
println!("{}", inner);
|
||||||
@@ -47,47 +49,90 @@ impl Autoformat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Format single file
|
// Format single file
|
||||||
if let Some(file) = self.file {
|
if let Some(file) = file {
|
||||||
let file_content;
|
refactor_file(file)?;
|
||||||
let indent;
|
|
||||||
if file == "-" {
|
|
||||||
indent = indentation_for(".")?;
|
|
||||||
let mut contents = String::new();
|
|
||||||
std::io::stdin().read_to_string(&mut contents)?;
|
|
||||||
file_content = Ok(contents);
|
|
||||||
} else {
|
|
||||||
indent = indentation_for(".")?;
|
|
||||||
file_content = fs::read_to_string(&file);
|
|
||||||
};
|
|
||||||
|
|
||||||
match file_content {
|
|
||||||
Ok(s) => {
|
|
||||||
let edits = dioxus_autofmt::fmt_file(&s, indent);
|
|
||||||
let out = dioxus_autofmt::apply_formats(&s, edits);
|
|
||||||
if file == "-" {
|
|
||||||
print!("{}", out);
|
|
||||||
} else {
|
|
||||||
match fs::write(&file, out) {
|
|
||||||
Ok(_) => {
|
|
||||||
println!("formatted {}", file);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("failed to write formatted content to file: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("failed to open file: {}", e);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refactor_file(file: String) -> Result<(), Error> {
|
||||||
|
let indent = indentation_for(".")?;
|
||||||
|
let file_content = if file == "-" {
|
||||||
|
let mut contents = String::new();
|
||||||
|
std::io::stdin().read_to_string(&mut contents)?;
|
||||||
|
Ok(contents)
|
||||||
|
} else {
|
||||||
|
fs::read_to_string(&file)
|
||||||
|
};
|
||||||
|
let Ok(s) = file_content else {
|
||||||
|
eprintln!("failed to open file: {}", file_content.unwrap_err());
|
||||||
|
exit(1);
|
||||||
|
};
|
||||||
|
let edits = dioxus_autofmt::fmt_file(&s, indent);
|
||||||
|
let out = dioxus_autofmt::apply_formats(&s, edits);
|
||||||
|
|
||||||
|
if file == "-" {
|
||||||
|
print!("{}", out);
|
||||||
|
} else if let Err(e) = fs::write(&file, out) {
|
||||||
|
eprintln!("failed to write formatted content to file: {e}",);
|
||||||
|
} else {
|
||||||
|
println!("formatted {}", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_project_files(config: &CrateConfig) -> Vec<PathBuf> {
|
||||||
|
let mut files = vec![];
|
||||||
|
|
||||||
|
let gitignore_path = config.crate_dir.join(".gitignore");
|
||||||
|
if gitignore_path.is_file() {
|
||||||
|
let gitigno = gitignore::File::new(gitignore_path.as_path()).unwrap();
|
||||||
|
if let Ok(git_files) = gitigno.included_files() {
|
||||||
|
let git_files = git_files
|
||||||
|
.into_iter()
|
||||||
|
.filter(|f| f.ends_with(".rs") && !is_target_dir(f));
|
||||||
|
files.extend(git_files)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
collect_rs_files(&config.crate_dir, &mut files);
|
||||||
|
}
|
||||||
|
|
||||||
|
files
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_target_dir(file: &Path) -> bool {
|
||||||
|
let stripped = if let Ok(cwd) = std::env::current_dir() {
|
||||||
|
file.strip_prefix(cwd).unwrap_or(file)
|
||||||
|
} else {
|
||||||
|
file
|
||||||
|
};
|
||||||
|
if let Some(first) = stripped.components().next() {
|
||||||
|
first.as_os_str() == "target"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn format_file(
|
||||||
|
path: impl AsRef<Path>,
|
||||||
|
indent: IndentOptions,
|
||||||
|
) -> Result<usize, tokio::io::Error> {
|
||||||
|
let contents = tokio::fs::read_to_string(&path).await?;
|
||||||
|
|
||||||
|
let edits = dioxus_autofmt::fmt_file(&contents, indent);
|
||||||
|
let len = edits.len();
|
||||||
|
|
||||||
|
if !edits.is_empty() {
|
||||||
|
let out = dioxus_autofmt::apply_formats(&contents, edits);
|
||||||
|
tokio::fs::write(path, out).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
|
||||||
/// Read every .rs file accessible when considering the .gitignore and try to format it
|
/// Read every .rs file accessible when considering the .gitignore and try to format it
|
||||||
///
|
///
|
||||||
/// Runs using Tokio for multithreading, so it should be really really fast
|
/// Runs using Tokio for multithreading, so it should be really really fast
|
||||||
@@ -96,8 +141,7 @@ impl Autoformat {
|
|||||||
async fn autoformat_project(check: bool) -> Result<()> {
|
async fn autoformat_project(check: bool) -> Result<()> {
|
||||||
let crate_config = crate::CrateConfig::new(None)?;
|
let crate_config = crate::CrateConfig::new(None)?;
|
||||||
|
|
||||||
let mut files_to_format = vec![];
|
let files_to_format = get_project_files(&crate_config);
|
||||||
collect_rs_files(&crate_config.crate_dir, &mut files_to_format);
|
|
||||||
|
|
||||||
if files_to_format.is_empty() {
|
if files_to_format.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -107,38 +151,17 @@ async fn autoformat_project(check: bool) -> Result<()> {
|
|||||||
|
|
||||||
let counts = files_to_format
|
let counts = files_to_format
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|file| {
|
|
||||||
if file.components().any(|f| f.as_os_str() == "target") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
})
|
|
||||||
.map(|path| async {
|
.map(|path| async {
|
||||||
let _path = path.clone();
|
let path_clone = path.clone();
|
||||||
let _indent = indent.clone();
|
let res = tokio::spawn(format_file(path, indent.clone())).await;
|
||||||
let res = tokio::spawn(async move {
|
|
||||||
let contents = tokio::fs::read_to_string(&path).await?;
|
|
||||||
|
|
||||||
let edits = dioxus_autofmt::fmt_file(&contents, _indent.clone());
|
|
||||||
let len = edits.len();
|
|
||||||
|
|
||||||
if !edits.is_empty() {
|
|
||||||
let out = dioxus_autofmt::apply_formats(&contents, edits);
|
|
||||||
tokio::fs::write(&path, out).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(len) as Result<usize, tokio::io::Error>
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("error formatting file: {}\n{err}", _path.display());
|
eprintln!("error formatting file: {}\n{err}", path_clone.display());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Ok(Err(err)) => {
|
Ok(Err(err)) => {
|
||||||
eprintln!("error formatting file: {}\n{err}", _path.display());
|
eprintln!("error formatting file: {}\n{err}", path_clone.display());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Ok(Ok(res)) => Some(res),
|
Ok(Ok(res)) => Some(res),
|
||||||
@@ -148,13 +171,7 @@ async fn autoformat_project(check: bool) -> Result<()> {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let files_formatted: usize = counts
|
let files_formatted: usize = counts.into_iter().flatten().sum();
|
||||||
.into_iter()
|
|
||||||
.map(|f| match f {
|
|
||||||
Some(res) => res,
|
|
||||||
_ => 0,
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
if files_formatted > 0 && check {
|
if files_formatted > 0 && check {
|
||||||
eprintln!("{} files needed formatting", files_formatted);
|
eprintln!("{} files needed formatting", files_formatted);
|
||||||
@@ -207,26 +224,24 @@ fn indentation_for(file_or_dir: impl AsRef<Path>) -> Result<IndentOptions> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_rs_files(folder: &Path, files: &mut Vec<PathBuf>) {
|
fn collect_rs_files(folder: &impl AsRef<Path>, files: &mut Vec<PathBuf>) {
|
||||||
let Ok(folder) = folder.read_dir() else {
|
if is_target_dir(folder.as_ref()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Ok(folder) = folder.as_ref().read_dir() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// load the gitignore
|
// load the gitignore
|
||||||
|
|
||||||
for entry in folder {
|
for entry in folder {
|
||||||
let Ok(entry) = entry else {
|
let Ok(entry) = entry else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
collect_rs_files(&path, files);
|
collect_rs_files(&path, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ext) = path.extension() {
|
if let Some(ext) = path.extension() {
|
||||||
if ext == "rs" {
|
if ext == "rs" && !is_target_dir(&path) {
|
||||||
files.push(path);
|
files.push(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-13
@@ -42,34 +42,36 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
set_up_logging();
|
set_up_logging();
|
||||||
|
|
||||||
let bin = get_bin(args.bin)?;
|
let bin = get_bin(args.bin);
|
||||||
|
|
||||||
let _dioxus_config = DioxusConfig::load(Some(bin.clone()))
|
if let Ok(bin) = &bin {
|
||||||
|
let _dioxus_config = DioxusConfig::load(Some(bin.clone()))
|
||||||
.map_err(|e| anyhow!("Failed to load Dioxus config because: {e}"))?
|
.map_err(|e| anyhow!("Failed to load Dioxus config because: {e}"))?
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
log::warn!("You appear to be creating a Dioxus project from scratch; we will use the default config");
|
log::warn!("You appear to be creating a Dioxus project from scratch; we will use the default config");
|
||||||
DioxusConfig::default()
|
DioxusConfig::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
PluginManager::init(_dioxus_config.plugin)
|
PluginManager::init(_dioxus_config.plugin)
|
||||||
.map_err(|e| anyhow!("🚫 Plugin system initialization failed: {e}"))?;
|
.map_err(|e| anyhow!("🚫 Plugin system initialization failed: {e}"))?;
|
||||||
|
}
|
||||||
|
|
||||||
match args.action {
|
match args.action {
|
||||||
Translate(opts) => opts
|
Translate(opts) => opts
|
||||||
.translate()
|
.translate()
|
||||||
.map_err(|e| anyhow!("🚫 Translation of HTML into RSX failed: {}", e)),
|
.map_err(|e| anyhow!("🚫 Translation of HTML into RSX failed: {}", e)),
|
||||||
|
|
||||||
Build(opts) => opts
|
Build(opts) if bin.is_ok() => opts
|
||||||
.build(Some(bin.clone()))
|
.build(Some(bin.unwrap().clone()))
|
||||||
.map_err(|e| anyhow!("🚫 Building project failed: {}", e)),
|
.map_err(|e| anyhow!("🚫 Building project failed: {}", e)),
|
||||||
|
|
||||||
Clean(opts) => opts
|
Clean(opts) if bin.is_ok() => opts
|
||||||
.clean(Some(bin.clone()))
|
.clean(Some(bin.unwrap().clone()))
|
||||||
.map_err(|e| anyhow!("🚫 Cleaning project failed: {}", e)),
|
.map_err(|e| anyhow!("🚫 Cleaning project failed: {}", e)),
|
||||||
|
|
||||||
Serve(opts) => opts
|
Serve(opts) if bin.is_ok() => opts
|
||||||
.serve(Some(bin.clone()))
|
.serve(Some(bin.unwrap().clone()))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| anyhow!("🚫 Serving project failed: {}", e)),
|
.map_err(|e| anyhow!("🚫 Serving project failed: {}", e)),
|
||||||
|
|
||||||
@@ -81,8 +83,8 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
.config()
|
.config()
|
||||||
.map_err(|e| anyhow!("🚫 Configuring new project failed: {}", e)),
|
.map_err(|e| anyhow!("🚫 Configuring new project failed: {}", e)),
|
||||||
|
|
||||||
Bundle(opts) => opts
|
Bundle(opts) if bin.is_ok() => opts
|
||||||
.bundle(Some(bin.clone()))
|
.bundle(Some(bin.unwrap().clone()))
|
||||||
.map_err(|e| anyhow!("🚫 Bundling project failed: {}", e)),
|
.map_err(|e| anyhow!("🚫 Bundling project failed: {}", e)),
|
||||||
|
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
@@ -107,5 +109,6 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
_ => Err(anyhow::anyhow!(bin.unwrap_err())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,11 @@ async fn start_desktop_hot_reload(hot_reload_state: HotReloadState) -> Result<()
|
|||||||
println!("Connected to hot reloading 🚀");
|
println!("Connected to hot reloading 🚀");
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if err.kind() != std::io::ErrorKind::WouldBlock {
|
let error_string = err.to_string();
|
||||||
|
// Filter out any error messages about a operation that may block and an error message that triggers on some operating systems that says "Waiting for a process to open the other end of the pipe" without WouldBlock being set
|
||||||
|
let display_error = err.kind() != std::io::ErrorKind::WouldBlock
|
||||||
|
&& !error_string.contains("Waiting for a process");
|
||||||
|
if display_error {
|
||||||
println!("Error connecting to hot reloading: {} (Hot reloading is a feature of the dioxus-cli. If you are not using the CLI, this error can be ignored)", err);
|
println!("Error connecting to hot reloading: {} (Hot reloading is a feature of the dioxus-cli. If you are not using the CLI, this error can be ignored)", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ features = [
|
|||||||
"HtmlFormElement",
|
"HtmlFormElement",
|
||||||
"Text",
|
"Text",
|
||||||
"Window",
|
"Window",
|
||||||
|
"console",
|
||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
+10
-1
@@ -45,7 +45,16 @@ impl WebsysDom {
|
|||||||
let document = load_document();
|
let document = load_document();
|
||||||
let root = match document.get_element_by_id(&cfg.rootname) {
|
let root = match document.get_element_by_id(&cfg.rootname) {
|
||||||
Some(root) => root,
|
Some(root) => root,
|
||||||
None => document.create_element("body").ok().unwrap(),
|
None => {
|
||||||
|
web_sys::console::error_1(
|
||||||
|
&format!(
|
||||||
|
"element '#{}' not found. mounting to the body.",
|
||||||
|
cfg.rootname
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
document.create_element("body").ok().unwrap()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let interpreter = Channel::default();
|
let interpreter = Channel::default();
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user