Browse Source

Merge pull request #56 from bamboo-maker/master

[TOOL] Adding tailwind-css
YuKun Liu 2 năm trước cách đây
mục cha
commit
62bf761c1b
4 tập tin đã thay đổi với 181 bổ sung25 xóa
  1. 24 0
      docs/src/configure.md
  2. 54 6
      src/builder.rs
  3. 12 12
      src/config.rs
  4. 91 7
      src/tools.rs

+ 24 - 0
docs/src/configure.md

@@ -25,6 +25,30 @@ We use `toml` to define some info for `dioxus` project.
    asset_dir = "public"
    ```
 
+### Application.Tool
+
+You can combine different tools with `dioxus`.
+
+1. ***binaryen*** - Use the `binaryen` tooling suite.
+   ```
+   # current support: wasm-opt
+   # default: web
+   binaryen = { wasm_opt = true }
+   ```
+   Use the `wasm_opt = true` key/pair value to activate optimization with wasm-opt.
+   When building on `release` profile, Dioxus will run `wasm_opt` with `-Oz` option.
+2. ***tailwindcss*** - Use the `tailwindcss` standalone binary to generate a Tailwind CSS bundle file.
+   ```
+   tailwindcss = { input = "main.css", config = "tailwind.config.js" }
+   ```
+   You can set two optional keys :
+    - input: path of the input CSS file (default value is "public/tailwind.css")
+    - config: path to the config file for Tailwind (default value is "src/tailwind.config.js")
+
+    When building on `release` profile, Dioxus will run `tailwindcss` with the `--minify` option.
+
+    Note : Dioxus will automatically include the generated tailwind file in the `index.html`
+
 ### Web.App
 
 Web platform application config:

+ 54 - 6
src/builder.rs

@@ -28,7 +28,8 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
     // [2] Generate the appropriate build folders
     // [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm
     // [4] Wasm-opt the .wasm file with whatever optimizations need to be done
-    // [5] Link up the html page to the wasm module
+    // [5][OPTIONAL] Builds the Tailwind CSS file using the Tailwind standalone binary
+    // [6] Link up the html page to the wasm module
 
     let CrateConfig {
         out_dir,
@@ -137,18 +138,23 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
                 if sub.contains_key("wasm_opt")
                     && sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false)
                 {
+                    log::info!("Optimizing WASM size with wasm-opt...");
                     let target_file = out_dir
                         .join("assets")
                         .join("dioxus")
                         .join(format!("{}_bg.wasm", dioxus_config.application.name));
                     if target_file.is_file() {
+                        let mut args = vec![
+                            target_file.to_str().unwrap(),
+                            "-o",
+                            target_file.to_str().unwrap(),
+                        ];
+                        if config.release == true {
+                            args.push("-Oz");
+                        }
                         binaryen.call(
                             "wasm-opt",
-                            vec![
-                                target_file.to_str().unwrap(),
-                                "-o",
-                                target_file.to_str().unwrap(),
-                            ],
+                            args,
                         )?;
                     }
                 }
@@ -160,6 +166,45 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
         }
     }
 
+    // [5][OPTIONAL] If tailwind is enabled and installed we run it to generate the CSS
+    if dioxus_tools.contains_key("tailwindcss") {
+        let info = dioxus_tools.get("tailwindcss").unwrap();
+        let tailwind = crate::tools::Tool::Tailwind;
+
+        if tailwind.is_installed() {
+            if let Some(sub) = info.as_table() {
+                log::info!("Building Tailwind bundle CSS file...");
+
+                let input_path = match sub.get("input") {
+                    Some(val) => val.as_str().unwrap(),
+                    None => "./public"
+                };
+                let config_path = match sub.get("config") {
+                    Some(val) => val.as_str().unwrap(),
+                    None => "./src/tailwind.config.js"
+                };
+                let mut args = vec![
+                    "-i",
+                    input_path,
+                    "-o",
+                    "dist/tailwind.css",
+                    "-c",
+                    config_path
+                ];
+
+                if config.release == true {
+                    args.push("--minify");
+                }
+                
+                tailwind.call("tailwindcss", args)?;
+            }
+        } else {
+            log::warn!(
+                "Tailwind tool not found, you can use `dioxus tool add tailwindcss` to install it."
+            );
+        }
+    }
+
     // this code will copy all public file to the output dir
     let copy_options = fs_extra::dir::CopyOptions {
         overwrite: true,
@@ -414,6 +459,9 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
             &style.to_str().unwrap(),
         ))
     }
+    if config.application.tools.clone().unwrap_or_default().contains_key("tailwindcss") {
+        style_str.push_str("<link rel=\"stylesheet\" href=\"tailwind.css\">\n");
+    }
     html = html.replace("{style_include}", &style_str);
 
     let mut script_str = String::new();

+ 12 - 12
src/config.rs

@@ -38,17 +38,17 @@ impl Default for DioxusConfig {
                 sub_package: None,
             },
             web: WebConfig {
-                app: WebAppConfing {
+                app: WebAppConfig {
                     title: Some("dioxus | ⛺".into()),
                     base_path: None,
                 },
-                watcher: WebWatcherConfing {
+                watcher: WebWatcherConfig {
                     watch_path: Some(vec![PathBuf::from("src")]),
                     reload_html: Some(false),
                     index_on_404: Some(true),
                 },
-                resource: WebResourceConfing {
-                    dev: WebDevResourceConfing {
+                resource: WebResourceConfig {
+                    dev: WebDevResourceConfig {
                         style: Some(vec![]),
                         script: Some(vec![]),
                     },
@@ -72,33 +72,33 @@ pub struct ApplicationConfig {
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct WebConfig {
-    pub app: WebAppConfing,
-    pub watcher: WebWatcherConfing,
-    pub resource: WebResourceConfing,
+    pub app: WebAppConfig,
+    pub watcher: WebWatcherConfig,
+    pub resource: WebResourceConfig,
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct WebAppConfing {
+pub struct WebAppConfig {
     pub title: Option<String>,
     pub base_path: Option<String>,
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct WebWatcherConfing {
+pub struct WebWatcherConfig {
     pub watch_path: Option<Vec<PathBuf>>,
     pub reload_html: Option<bool>,
     pub index_on_404: Option<bool>,
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct WebResourceConfing {
-    pub dev: WebDevResourceConfing,
+pub struct WebResourceConfig {
+    pub dev: WebDevResourceConfig,
     pub style: Option<Vec<PathBuf>>,
     pub script: Option<Vec<PathBuf>>,
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct WebDevResourceConfing {
+pub struct WebDevResourceConfig {
     pub style: Option<Vec<PathBuf>>,
     pub script: Option<Vec<PathBuf>>,
 }

+ 91 - 7
src/tools.rs

@@ -2,6 +2,7 @@ use std::{
     fs::{create_dir_all, File},
     path::{Path, PathBuf},
     process::Command,
+    io::{Read, Write}
 };
 
 use anyhow::Context;
@@ -14,10 +15,11 @@ use tokio::io::AsyncWriteExt;
 pub enum Tool {
     Binaryen,
     Sass,
+    Tailwind,
 }
 
 pub fn tool_list() -> Vec<&'static str> {
-    vec!["binaryen", "sass"]
+    vec!["binaryen", "sass", "tailwindcss"]
 }
 
 pub fn app_path() -> PathBuf {
@@ -54,6 +56,7 @@ impl Tool {
         match name {
             "binaryen" => Some(Self::Binaryen),
             "sass" => Some(Self::Sass),
+            "tailwindcss" => Some(Self::Tailwind),
             _ => None,
         }
     }
@@ -63,6 +66,7 @@ impl Tool {
         match self {
             Self::Binaryen => "binaryen",
             Self::Sass => "sass",
+            Self::Tailwind => "tailwindcss",
         }
     }
 
@@ -71,6 +75,7 @@ impl Tool {
         match self {
             Self::Binaryen => "bin",
             Self::Sass => ".",
+            Self::Tailwind => ".",
         }
     }
 
@@ -99,6 +104,32 @@ impl Tool {
                     panic!("unsupported platformm");
                 }
             }
+            Self::Tailwind => {
+                if cfg!(target_os = "windows") {
+                    "windows"
+                } else if cfg!(target_os = "macos") {
+                    "macos"
+                } else if cfg!(target_os = "linux") {
+                    "linux"
+                } else {
+                    panic!("unsupported platformm");
+                }
+            }
+        }
+    }
+
+    /// get tool version
+    pub fn tool_version(&self) -> &str {
+        match self {
+            Self::Binaryen => {
+                "version_105"
+            }
+            Self::Sass => {
+                "1.51.0"
+            }
+            Self::Tailwind => {
+                "v3.1.6"
+            }
         }
     }
 
@@ -107,17 +138,31 @@ impl Tool {
         match self {
             Self::Binaryen => {
                 format!(
-                    "https://github.com/WebAssembly/binaryen/releases/download/version_105/binaryen-version_105-x86_64-{target}.tar.gz",
+                    "https://github.com/WebAssembly/binaryen/releases/download/{version}/binaryen-{version}-x86_64-{target}.tar.gz",
+                    version = self.tool_version(),
                     target = self.target_platform()
                 )
             }
             Self::Sass => {
                 format!(
-                    "https://github.com/sass/dart-sass/releases/download/1.51.0/dart-sass-1.51.0-{target}-x64.{extension}",
+                    "https://github.com/sass/dart-sass/releases/download/{version}/dart-sass-{version}-{target}-x64.{extension}",
+                    version = self.tool_version(),
                     target = self.target_platform(),
                     extension = self.extension()
                 )
             }
+            Self::Tailwind => {
+                let windows_extension = match self.target_platform() {
+                    "windows" => ".exe",
+                    _ => ""
+                };
+                format!(
+                    "https://github.com/tailwindlabs/tailwindcss/releases/download/{version}/tailwindcss-{target}-x64{optional_ext}",
+                    version = self.tool_version(),
+                    target = self.target_platform(),
+                    optional_ext = windows_extension
+                )
+            }
         }
     }
 
@@ -132,6 +177,7 @@ impl Tool {
                     "tar.gz"
                 }
             }
+            Self::Tailwind => "bin"
         }
     }
 
@@ -169,10 +215,10 @@ impl Tool {
         let temp_path = self.temp_out_path();
         let tool_path = tools_path();
 
-        let dir_name = if self == &Tool::Binaryen {
-            "binaryen-version_105"
-        } else {
-            "dart-sass"
+        let dir_name = match self {
+            Self::Binaryen => format!("binaryen-{}", self.tool_version()),
+            Self::Sass => "dart-sass".to_string(),
+            Self::Tailwind => self.name().to_string()
         };
 
         if self.extension() == "tar.gz" {
@@ -185,6 +231,37 @@ impl Tool {
             // decompress the `zip` file
             extract_zip(&temp_path, &tool_path)?;
             std::fs::rename(tool_path.join(dir_name), tool_path.join(self.name()))?;
+        } else if self.extension() == "bin" {
+            let bin_path = match self.target_platform() {
+                "windows" => tool_path.join(&dir_name).join(self.name()).join(".exe"),
+                _ => tool_path.join(&dir_name).join(self.name())
+            } ;
+            // Manualy creating tool directory because we directly download the binary via Github
+            std::fs::create_dir( tool_path.join(dir_name))?;
+
+            let mut final_file = std::fs::File::create(&bin_path)?;
+            let mut temp_file = File::open(&temp_path)?;
+            let mut content = Vec::new(); 
+
+            temp_file.read_to_end(&mut content)?;
+            final_file.write_all(&content)?;
+
+            if self.target_platform() == "linux" {
+                // This code does not update permissions idk why
+                /*let mut perms = final_file.metadata()?.permissions();
+                perms.set_mode(0o744);*/
+
+                // Adding to the binary execution rights with "chmod"
+                let mut command = Command::new("chmod");
+
+                let _ = command
+                    .args(vec!["+x", bin_path.to_str().unwrap()])
+                    .stdout(std::process::Stdio::inherit())
+                    .stderr(std::process::Stdio::inherit())
+                    .output()?;
+            }
+
+            std::fs::remove_file(&temp_path)?;
         }
 
         Ok(())
@@ -208,6 +285,13 @@ impl Tool {
                     command.to_string()
                 }
             }
+            Tool::Tailwind => {
+                if cfg!(target_os = "windows") {
+                    format!("{}.exe", command)
+                } else {
+                    command.to_string()
+                }
+            }
         };
 
         if !bin_path.join(&command_file).is_file() {