From d601484a17366dee7987906dbb761a6ef6bb8671 Mon Sep 17 00:00:00 2001 From: Nathy-bajo Date: Wed, 18 Dec 2024 15:18:48 +0100 Subject: [PATCH 1/3] fix(cli): Updated logic to resolve out_dir paths relative to workspace --- packages/cli/src/config/app.rs | 7 +++++++ packages/cli/src/config/dioxus_config.rs | 1 + packages/cli/src/dioxus_crate.rs | 18 +++++++++++++++--- packages/cli/src/wasm_bindgen.rs | 16 +++++++++------- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/config/app.rs b/packages/cli/src/config/app.rs index c1e4bd72d3..ffc1a2094b 100644 --- a/packages/cli/src/config/app.rs +++ b/packages/cli/src/config/app.rs @@ -8,8 +8,15 @@ pub(crate) struct ApplicationConfig { #[serde(default)] pub(crate) sub_package: Option, + + #[serde(default = "out_dir_default")] + pub(crate) out_dir: PathBuf, } pub(crate) fn asset_dir_default() -> PathBuf { PathBuf::from("assets") } + +pub(crate) fn out_dir_default() -> PathBuf { + PathBuf::from("dist") +} \ No newline at end of file diff --git a/packages/cli/src/config/dioxus_config.rs b/packages/cli/src/config/dioxus_config.rs index ec8e7607fb..5b95e0289e 100644 --- a/packages/cli/src/config/dioxus_config.rs +++ b/packages/cli/src/config/dioxus_config.rs @@ -24,6 +24,7 @@ impl Default for DioxusConfig { application: ApplicationConfig { asset_dir: asset_dir_default(), sub_package: None, + out_dir: out_dir_default(), }, web: WebConfig { app: WebAppConfig { diff --git a/packages/cli/src/dioxus_crate.rs b/packages/cli/src/dioxus_crate.rs index ba41a16ac8..c30cde0803 100644 --- a/packages/cli/src/dioxus_crate.rs +++ b/packages/cli/src/dioxus_crate.rs @@ -97,9 +97,21 @@ impl DioxusCrate { /// is "distributed" after building an application (configurable in the /// `Dioxus.toml`). fn out_dir(&self) -> PathBuf { - let dir = self.workspace_dir().join("target").join("dx"); - std::fs::create_dir_all(&dir).unwrap(); - dir + // Resolve the out_dir based on the configuration or default + let out_dir_config = self.config.application.out_dir.clone(); + // Resolve relative paths against the workspace root + let resolved_out_dir = if out_dir_config.is_relative() { + self.workspace_dir().join(out_dir_config) + } else { + out_dir_config + }; + + // Create the directory and handle potential errors + if let Err(e) = std::fs::create_dir_all(&resolved_out_dir) { + tracing::error!("Failed to create output directory: {}", e); + } + + resolved_out_dir } /// Create a workdir for the given platform diff --git a/packages/cli/src/wasm_bindgen.rs b/packages/cli/src/wasm_bindgen.rs index 436689661f..4ae8a3122d 100644 --- a/packages/cli/src/wasm_bindgen.rs +++ b/packages/cli/src/wasm_bindgen.rs @@ -57,10 +57,14 @@ impl WasmBindgen { args.push(&self.out_name); // Out dir - let out_dir = self + let canonical_out_dir = self .out_dir + .canonicalize() + .expect("out_dir should resolve to a valid path"); + + let out_dir = canonical_out_dir .to_str() - .expect("input_path should be valid utf8"); + .expect("out_dir should be valid UTF-8"); args.push("--out-dir"); args.push(out_dir); @@ -342,11 +346,9 @@ impl WasmBindgenBuilder { } } - pub fn out_dir(self, out_dir: &Path) -> Self { - Self { - out_dir: out_dir.to_path_buf(), - ..self - } + pub fn out_dir(mut self, out_dir: &Path) -> Self { + self.out_dir = out_dir.canonicalize().expect("Invalid out_dir path"); + self } pub fn out_name(self, out_name: &str) -> Self { From b558c86c5ed2d66a9bca3f134af52664be80c16c Mon Sep 17 00:00:00 2001 From: Nathy-bajo Date: Thu, 19 Dec 2024 13:36:17 +0100 Subject: [PATCH 2/3] Clarify and improve #[server] macro docs --- packages/server-macro/src/lib.rs | 61 ++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/packages/server-macro/src/lib.rs b/packages/server-macro/src/lib.rs index d3d50f1640..44e07c3116 100644 --- a/packages/server-macro/src/lib.rs +++ b/packages/server-macro/src/lib.rs @@ -31,23 +31,39 @@ use syn::__private::ToTokens; /// /// ## Named Arguments /// -/// You can any combination of the following named arguments: +/// You can use any combination of the following named arguments: /// - `name`: sets the identifier for the server function’s type, which is a struct created -/// to hold the arguments (defaults to the function identifier in PascalCase) -/// - `prefix`: a prefix at which the server function handler will be mounted (defaults to `/api`) +/// to hold the arguments (defaults to the function identifier in PascalCase). +/// Example: `name = MyServerFunction`. +/// - `prefix`: a prefix at which the server function handler will be mounted (defaults to `/api`). +/// Example: `prefix = "/my_api"`. /// - `endpoint`: specifies the exact path at which the server function handler will be mounted, -/// relative to the prefix (defaults to the function name followed by unique hash) -/// - `input`: the encoding for the arguments (defaults to `PostUrl`) -/// - `output`: the encoding for the response (defaults to `Json`) -/// - `client`: a custom `Client` implementation that will be used for this server fn +/// relative to the prefix (defaults to the function name followed by unique hash). +/// Example: `endpoint = "my_fn"`. +/// - `input`: the encoding for the arguments (defaults to `PostUrl`). +/// - The `input` argument specifies how the function arguments are encoded for transmission. +/// - Acceptable values include: +/// - `PostUrl`: A `POST` request with URL-encoded arguments, suitable for form-like submissions. +/// - `Json`: A `POST` request where the arguments are encoded as JSON. This is a common choice for modern APIs. +/// - `Cbor`: A `POST` request with CBOR-encoded arguments, useful for binary data transmission with compact encoding. +/// - `GetUrl`: A `GET` request with URL-encoded arguments, suitable for simple queries or when data fits in the URL. +/// - `GetCbor`: A `GET` request with CBOR-encoded arguments, useful for query-style APIs when the payload is binary. +/// - `output`: the encoding for the response (defaults to `Json`). +/// - The `output` argument specifies how the server should encode the response data. +/// - Acceptable values include: +/// - `Json`: A response encoded as JSON (default). This is ideal for most web applications. +/// - `Cbor`: A response encoded in the CBOR format for efficient, binary-encoded data. +/// - `client`: a custom `Client` implementation that will be used for this server function. This allows +/// customization of the client-side behavior if needed. /// - `encoding`: (legacy, may be deprecated in future) specifies the encoding, which may be one -/// of the following (not case sensitive) +/// of the following (not case sensitive): /// - `"Url"`: `POST` request with URL-encoded arguments and JSON response /// - `"GetUrl"`: `GET` request with URL-encoded arguments and JSON response /// - `"Cbor"`: `POST` request with CBOR-encoded arguments and response /// - `"GetCbor"`: `GET` request with URL-encoded arguments and CBOR response -/// - `req` and `res` specify the HTTP request and response types to be used on the server (these -/// should usually only be necessary if you are integrating with a server other than Actix/Axum) +/// - `req` and `res`: specify the HTTP request and response types to be used on the server. These +/// are typically necessary if you are integrating with a custom server framework (other than Actix/Axum). +/// Example: `req = SomeRequestType`, `res = SomeResponseType`. /// ```rust,ignore /// #[server( /// name = SomeStructName, @@ -143,15 +159,30 @@ use syn::__private::ToTokens; /// ``` #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { + let default_prefix: &str = "/api"; + let default_input: Option = Some(syn::parse_quote!(server_fn)); + let default_output: Option = None; + let default_preset: Option = None; + match server_macro_impl( args.into(), s.into(), - Some(syn::parse_quote!(server_fn)), - "/api", - None, - None, + default_input, + default_prefix, + default_output, + default_preset, ) { - Err(e) => e.to_compile_error().into(), + // Generate detailed error message with context when macro fails. + Err(e) => { + let detailed_error = format!( + "Failed to process the `server` macro. Check your arguments and function signature. Error: {}", + e + ); + syn::Error::new(proc_macro2::Span::call_site(), detailed_error) + .to_compile_error() + .into() + } + // Successful case: return the generated token stream. Ok(s) => s.to_token_stream().into(), } } From c28ba151515922eabeb1d7d79c8616e0f627fc60 Mon Sep 17 00:00:00 2001 From: Nathy-bajo Date: Mon, 23 Dec 2024 12:51:10 +0100 Subject: [PATCH 3/3] Clarify and improve #[server] macro docs --- packages/server-macro/src/lib.rs | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/packages/server-macro/src/lib.rs b/packages/server-macro/src/lib.rs index 44e07c3116..6fadae1480 100644 --- a/packages/server-macro/src/lib.rs +++ b/packages/server-macro/src/lib.rs @@ -64,6 +64,53 @@ use syn::__private::ToTokens; /// - `req` and `res`: specify the HTTP request and response types to be used on the server. These /// are typically necessary if you are integrating with a custom server framework (other than Actix/Axum). /// Example: `req = SomeRequestType`, `res = SomeResponseType`. +/// +/// +/// ## Advanced Usage of `input` and `output` Fields +/// +/// The `input` and `output` fields allow you to customize how arguments and responses are encoded and decoded. +/// These fields impose specific trait bounds on the types you use. Here are detailed examples for different scenarios: +/// +/// ### `output = StreamingJson` +/// +/// Setting the `output` type to `StreamingJson` requires the return type to implement `From>`, +/// where `T` implements `serde::Serialize` and `serde::de::DeserializeOwned`. +/// +/// ```rust,ignore +/// #[server(output = StreamingJson)] +/// pub async fn json_stream_fn() -> Result, ServerFnError> { +/// todo!() +/// } +/// ``` +/// +/// ### `output = StreamingText` +/// +/// Setting the `output` type to `StreamingText` requires the return type to implement `From`. +/// +/// ```rust,ignore +/// #[server(output = StreamingText)] +/// pub async fn text_stream_fn() -> Result { +/// todo!() +/// } +/// ``` +/// +/// ### `output = PostUrl` +/// +/// Setting the `output` type to `PostUrl` requires the return type to implement `Serialize` and `Deserialize`. +/// Note that this uses `serde_qs`, which imposes the following constraints: +/// - The structure must be less than 5 levels deep. +/// - The structure must not contain any `serde(flatten)` attributes. +/// +/// ```rust,ignore +/// #[server(output = PostUrl)] +/// pub async fn form_fn() -> Result { +/// todo!() +/// } +/// ``` +/// +/// These examples illustrate how the `output` type impacts the bounds and expectations for your server function. Ensure your return types comply with these requirements. +/// +/// /// ```rust,ignore /// #[server( /// name = SomeStructName,