Prechádzať zdrojové kódy

improve build times by extracting asset opt into its own crate (#3273)

* improve build types by extracing asset opt as a dylib
* dont use dylib, but let regular workspace caching do the heavy lifting
* add prebuild to cli for better lock contention
* hoist deps
* disable slow tests
* re-enable sequential, debug=0 for dev
* use vfs for windows
* dont cache on failure, fix windows vfs caceh
* free disk space re-order
* add clippy + fmt to windows channel
* yoink makefile
* proper rustfmt/clippy on toolchain
* set incremental to zero since cargo-cache disables it
Jonathan Kelley 6 mesiacov pred
rodič
commit
1cbfcde6cd

+ 1 - 1
.docker/Dockerfile_test

@@ -3,7 +3,7 @@ FROM dioxus-pre-test
 RUN mkdir run_test
 COPY tmp /run_test
 WORKDIR /run_test
-RUN cargo make tests
+RUN cargo test --workspace --tests
 RUN cargo cache -a
 
 CMD ["exit"]

+ 63 - 44
.github/workflows/main.yml

@@ -37,7 +37,7 @@ concurrency:
 
 env:
   CARGO_TERM_COLOR: always
-  CARGO_INCREMENTAL: "1"
+  CARGO_INCREMENTAL: 0 # todo(jon): cargo-cache wipes incremental artifacts, but we eventually want to cache them
   RUST_BACKTRACE: 1
   rust_nightly: nightly-2024-10-20
 
@@ -48,11 +48,10 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - uses: dtolnay/rust-toolchain@stable
+      - uses: dtolnay/rust-toolchain@1.79.0
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          cache-on-failure: "true"
       # https://github.com/foresterre/cargo-msrv/blob/4345edfe3f4fc91cc8ae6c7d6804c0748fae92ae/.github/workflows/msrv.yml
       - name: install_cargo_msrv
         run: cargo install cargo-msrv --all-features
@@ -78,15 +77,14 @@ jobs:
           swap-storage: false
       - run: sudo apt-get update
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
-      - uses: dtolnay/rust-toolchain@stable
+      - uses: dtolnay/rust-toolchain@1.79.0
+        with:
+          components: rustfmt, clippy
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          cache-on-failure: "true"
-      - uses: davidB/rust-cargo-make@v1
       - uses: browser-actions/setup-firefox@latest
-      - uses: jetli/wasm-pack-action@v0.4.0
-      - run: cargo make tests
+      - run: cargo test --lib --bins --tests --examples --workspace --exclude dioxus-desktop --exclude dioxus-mobile
 
   release-test:
     if: github.event.pull_request.draft == false
@@ -94,23 +92,22 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - run: sudo apt-get update
-      - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
-      - uses: dtolnay/rust-toolchain@stable
-      - uses: Swatinem/rust-cache@v2
-        with:
-          cache-all-crates: "true"
-          cache-on-failure: "true"
-      - uses: davidB/rust-cargo-make@v1
-      - uses: browser-actions/setup-firefox@latest
-      - uses: jetli/wasm-pack-action@v0.4.0
       - name: Free Disk Space (Ubuntu)
         uses: jlumbroso/free-disk-space@v1.3.1
         with: # speed things up a bit
           large-packages: false
           docker-images: false
           swap-storage: false
-      - run: cargo test --profile release-unoptimized --lib --bins --tests --examples --workspace --exclude dioxus-desktop --exclude dioxus-mobile
+      - run: sudo apt-get update
+      - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
+      - uses: dtolnay/rust-toolchain@1.79.0
+        with:
+          components: rustfmt, clippy
+      - uses: Swatinem/rust-cache@v2
+        with:
+          cache-all-crates: "true"
+      - uses: browser-actions/setup-firefox@latest
+      - run: cargo test --lib --bins --tests --examples --workspace --exclude dioxus-desktop --exclude dioxus-mobile --profile release-unoptimized
 
   fmt:
     if: github.event.pull_request.draft == false
@@ -118,13 +115,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - uses: dtolnay/rust-toolchain@stable
+      - uses: dtolnay/rust-toolchain@1.79.0
         with:
           components: rustfmt
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          cache-on-failure: "true"
       - run: cargo fmt --all -- --check
 
   typos:
@@ -151,7 +147,6 @@ jobs:
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          cache-on-failure: "true"
       - name: "doc --lib --all-features"
         run: |
           cargo doc --workspace --no-deps --all-features --document-private-items
@@ -189,11 +184,10 @@ jobs:
       - uses: actions/checkout@v4
       - run: sudo apt-get update
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
-      - uses: dtolnay/rust-toolchain@stable
+      - uses: dtolnay/rust-toolchain@1.79.0
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          cache-on-failure: "true"
       - run: cargo check --workspace --all-features --all-targets
 
   clippy:
@@ -204,13 +198,12 @@ jobs:
       - uses: actions/checkout@v4
       - run: sudo apt-get update
       - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
-      - uses: dtolnay/rust-toolchain@stable
+      - uses: dtolnay/rust-toolchain@1.79.0
         with:
           components: rustfmt, clippy
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          cache-on-failure: "true"
       - run: cargo clippy --workspace --examples --tests --all-features --all-targets -- -D warnings
 
   nix:
@@ -237,6 +230,12 @@ jobs:
     steps:
       # Do our best to cache the toolchain and node install steps
       - uses: actions/checkout@v4
+      - name: Free Disk Space (Ubuntu)
+        uses: jlumbroso/free-disk-space@v1.3.1
+        with: # speed things up a bit
+          large-packages: false
+          docker-images: false
+          swap-storage: false
       - uses: actions/setup-node@v4
         with:
           node-version: 16
@@ -248,13 +247,9 @@ jobs:
       - uses: Swatinem/rust-cache@v2
         with:
           cache-all-crates: "true"
-          cache-on-failure: "true"
-      - name: Free Disk Space (Ubuntu)
-        uses: jlumbroso/free-disk-space@v1.3.1
-        with: # speed things up a bit
-          large-packages: false
-          docker-images: false
-          swap-storage: false
+      - name: Prebuild CLI
+        run: |
+          cargo build --package dioxus-cli --release
       - name: Playwright
         working-directory: ./packages/playwright-tests
         run: |
@@ -277,14 +272,6 @@ jobs:
     strategy:
       matrix:
         platform:
-          - {
-              target: x86_64-pc-windows-msvc,
-              os: windows-latest,
-              toolchain: "1.79.0",
-              cross: false,
-              command: "test",
-              args: "--all --tests",
-            }
           - {
               target: aarch64-apple-darwin,
               os: macos-latest,
@@ -340,19 +327,51 @@ jobs:
 
       - name: Install cross
         if: ${{ matrix.platform.cross == true }}
-
         uses: taiki-e/install-action@cross
 
       - uses: Swatinem/rust-cache@v2
         with:
           key: "matrix-${{ matrix.platform.target }}"
           cache-all-crates: "true"
-          cache-on-failure: "true"
 
       - name: test
         run: |
           ${{ env.RUST_CARGO_COMMAND }} ${{ matrix.platform.command }} ${{ matrix.platform.args }} --target ${{ matrix.platform.target }}
 
+  # borrowed from uv
+  # https://raw.githubusercontent.com/astral-sh/uv/refs/heads/main/.github/workflows/ci.yml
+  cargo-test-windows:
+    if: github.event.pull_request.draft == false
+    runs-on:
+      labels: "windows-latest"
+    name: "cargo test | windows"
+    steps:
+      - uses: actions/checkout@v4
+      - name: Create Dev Drive using ReFS
+        run: ${{ github.workspace }}/.github/workflows/setup-dev-drive.ps1
+
+      # actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone...
+      - name: Copy Git Repo to Dev Drive
+        run: |
+          Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse
+
+      - uses: dtolnay/rust-toolchain@1.79.0
+        with:
+          components: rustfmt, clippy
+      - uses: Swatinem/rust-cache@v2
+        with:
+          workspaces: ${{ env.UV_WORKSPACE }}
+          cache-all-crates: "true"
+
+      - name: "Install Rust toolchain"
+        working-directory: ${{ env.UV_WORKSPACE }}
+        run: rustup show
+
+      - name: "Cargo test"
+        working-directory: ${{ env.UV_WORKSPACE }}
+        run: |
+          cargo test --workspace --tests
+
   # Only run semver checks if the PR is not a draft and does not have the breaking label
   # Breaking PRs don't need to follow semver since they are breaking changes
   # However, this means we won't attempt to backport them, so you should be careful about using this label, as it will
@@ -369,7 +388,7 @@ jobs:
   #   runs-on: ubuntu-latest
   #   steps:
   #     - uses: actions/checkout@v4
-  #     - uses: dtolnay/rust-toolchain@stable
+  #     - uses: dtolnay/rust-toolchain@1.79.0
   #     - uses: Swatinem/rust-cache@v2
   #       with:
   #         cache-all-crates: "true"

+ 25 - 0
.github/workflows/setup-dev-drive.ps1

@@ -0,0 +1,25 @@
+# This creates a 20GB dev drive, and exports all required environment
+# variables so that rustup, uv and others all use the dev drive as much
+# as possible.
+$Volume = New-VHD -Path C:/uv_dev_drive.vhdx -SizeBytes 20GB |
+					Mount-VHD -Passthru |
+					Initialize-Disk -Passthru |
+					New-Partition -AssignDriveLetter -UseMaximumSize |
+					Format-Volume -FileSystem ReFS -Confirm:$false -Force
+
+Write-Output $Volume
+
+$Drive = "$($Volume.DriveLetter):"
+$Tmp = "$($Drive)/uv-tmp"
+
+# Create the directory ahead of time in an attempt to avoid race-conditions
+New-Item $Tmp -ItemType Directory
+
+Write-Output `
+	"DEV_DRIVE=$($Drive)" `
+	"TMP=$($Tmp)" `
+	"TEMP=$($Tmp)" `
+	"RUSTUP_HOME=$($Drive)/.rustup" `
+	"CARGO_HOME=$($Drive)/.cargo" `
+	"UV_WORKSPACE=$($Drive)/uv" `
+	>> $env:GITHUB_ENV

+ 49 - 34
Cargo.lock

@@ -3445,7 +3445,6 @@ dependencies = [
  "axum-extra",
  "axum-server",
  "brotli 6.0.0",
- "browserslist-rs",
  "built",
  "cargo-config2",
  "cargo-generate",
@@ -3462,6 +3461,7 @@ dependencies = [
  "dioxus-autofmt",
  "dioxus-check",
  "dioxus-cli-config",
+ "dioxus-cli-opt",
  "dioxus-core",
  "dioxus-core-types",
  "dioxus-devtools-types",
@@ -3483,21 +3483,16 @@ dependencies = [
  "hyper-rustls 0.27.3",
  "hyper-util",
  "ignore",
- "image",
- "imagequant",
  "include_dir",
  "itertools 0.13.0",
  "krates",
- "lightningcss",
  "log",
  "manganis-core",
- "mozjpeg",
  "notify",
  "object 0.36.5",
  "once_cell",
  "open",
  "path-absolutize",
- "png",
  "prettyplease",
  "proc-macro2",
  "ratatui",
@@ -3508,6 +3503,54 @@ dependencies = [
  "serde",
  "serde_json",
  "strum 0.26.3",
+ "syn 2.0.90",
+ "tauri-bundler",
+ "tauri-utils",
+ "tempfile",
+ "thiserror 1.0.69",
+ "throbber-widgets-tui",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "toml",
+ "toml_edit 0.22.22",
+ "tower 0.4.13",
+ "tower-http",
+ "tracing",
+ "tracing-subscriber",
+ "unicode-segmentation",
+ "uuid",
+ "walkdir",
+ "walrus 0.22.0",
+ "wasm-bindgen-cli-support",
+ "wasm-bindgen-shared",
+ "wasm-opt",
+]
+
+[[package]]
+name = "dioxus-cli-config"
+version = "0.6.0-alpha.5"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "dioxus-cli-opt"
+version = "0.6.0-alpha.5"
+dependencies = [
+ "anyhow",
+ "browserslist-rs",
+ "const-serialize",
+ "image",
+ "imagequant",
+ "lightningcss",
+ "manganis-core",
+ "mozjpeg",
+ "object 0.36.5",
+ "png",
+ "rayon",
+ "serde",
+ "serde_json",
  "swc",
  "swc_allocator",
  "swc_atoms",
@@ -3559,35 +3602,7 @@ dependencies = [
  "swc_transform_common",
  "swc_typescript",
  "swc_visit",
- "syn 2.0.90",
- "tauri-bundler",
- "tauri-utils",
- "tempfile",
- "thiserror 1.0.69",
- "throbber-widgets-tui",
- "tokio",
- "tokio-stream",
- "tokio-util",
- "toml",
- "toml_edit 0.22.22",
- "tower 0.4.13",
- "tower-http",
  "tracing",
- "tracing-subscriber",
- "unicode-segmentation",
- "uuid",
- "walkdir",
- "walrus 0.22.0",
- "wasm-bindgen-cli-support",
- "wasm-bindgen-shared",
- "wasm-opt",
-]
-
-[[package]]
-name = "dioxus-cli-config"
-version = "0.6.0-alpha.5"
-dependencies = [
- "wasm-bindgen",
 ]
 
 [[package]]

+ 10 - 3
Cargo.toml

@@ -6,6 +6,7 @@ members = [
     "packages/core",
     "packages/core-types",
     "packages/cli",
+    "packages/cli-opt",
     "packages/core-types",
     "packages/core-macro",
     "packages/config-macro",
@@ -131,16 +132,18 @@ dioxus-rsx-hotreload = { path = "packages/rsx-hotreload", version = "0.6.0-alpha
 dioxus-rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.6.0-alpha.5" }
 dioxus-signals = { path = "packages/signals", version = "0.6.0-alpha.5" }
 dioxus-cli-config = { path = "packages/cli-config", version = "0.6.0-alpha.5" }
-generational-box = { path = "packages/generational-box", version = "0.6.0-alpha.5" }
+dioxus-cli-opt = { path = "packages/cli-opt", version = "0.6.0-alpha.5" }
 dioxus-devtools = { path = "packages/devtools", version = "0.6.0-alpha.5" }
 dioxus-devtools-types = { path = "packages/devtools-types", version = "0.6.0-alpha.5" }
 dioxus-fullstack = { path = "packages/fullstack", version = "0.6.0-alpha.5" }
 dioxus_server_macro = { path = "packages/server-macro", version = "0.6.0-alpha.5", default-features = false }
-const-serialize = { path = "packages/const-serialize", version = "0.6.0-alpha.5" }
-const-serialize-macro = { path = "packages/const-serialize-macro", version = "0.6.0-alpha.5" }
 dioxus-dx-wire-format = { path = "packages/dx-wire-format", version = "0.6.0-alpha.5" }
 
+const-serialize = { path = "packages/const-serialize", version = "0.6.0-alpha.5" }
+const-serialize-macro = { path = "packages/const-serialize-macro", version = "0.6.0-alpha.5" }
+generational-box = { path = "packages/generational-box", version = "0.6.0-alpha.5" }
 lazy-js-bundle = { path = "packages/lazy-js-bundle", version = "0.6.0-alpha.5" }
+
 manganis = { path = "packages/manganis/manganis", version = "0.6.0-alpha.5" }
 manganis-core = { path = "packages/manganis/manganis-core", version = "0.6.0-alpha.5" }
 manganis-macro = { path = "packages/manganis/manganis-macro", version = "0.6.0-alpha.5" }
@@ -236,6 +239,10 @@ objc = { version = "0.2.7", features = ["exception"] }
 objc_id = "0.1.1"
 tray-icon = "0.19"
 
+# disable debug symbols in dev builds - shouldn't matter for downstream crates but makes our binaries (examples, cli, etc) build faster
+[profile.dev]
+debug = 0
+
 # our release profile should be fast to compile and fast to run
 # when we ship our CI builds, we turn on LTO which improves perf leftover by turning on incremental
 [profile.release]

+ 0 - 102
Makefile.toml

@@ -1,102 +0,0 @@
-[config]
-default_to_workspace = false
-min_version = "0.32.4"
-
-[env]
-CARGO_MAKE_CLIPPY_ARGS = "-- --deny=warnings"
-CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
-
-[config.modify_core_tasks]
-namespace = "core"
-private = true
-
-[tasks.tests-setup]
-private = true
-script = [
-  """
-    test_flags = array --headless --firefox
-    dioxus_test_features = set wasm_test
-    dioxus_test_flags = array_join ${test_flags} " "
-    echo "running tests with flags: ${dioxus_test_flags} and features: ${dioxus_test_features}"
-    set_env DIOXUS_TEST_FLAGS ${dioxus_test_flags}
-    set_env DIOXUS_TEST_FEATURES ${dioxus_test_features}
-    """,
-]
-script_runner = "@duckscript"
-
-[tasks.format]
-command = "cargo"
-args = ["fmt", "--all"]
-
-[tasks.check]
-command = "cargo"
-args = ["check", "--workspace", "--examples", "--tests"]
-
-[tasks.clippy]
-command = "cargo"
-args = [
-  "clippy",
-  "--workspace",
-  "--examples",
-  "--tests",
-  "--",
-  "-D",
-  "warnings",
-]
-
-[tasks.tidy]
-category = "Formatting"
-dependencies = ["format", "check", "clippy"]
-description = "Format and Check workspace"
-
-[tasks.tests]
-category = "Testing"
-dependencies = ["tests-setup"]
-description = "Run all tests"
-env = { CARGO_MAKE_WORKSPACE_SKIP_MEMBERS = ["**/examples/*"] }
-run_task = { name = ["test-flow", "test-with-browser"], fork = true }
-
-[tasks.build]
-command = "cargo"
-args = ["build"]
-
-[tasks.test-flow]
-dependencies = ["test", "docs"]
-private = true
-
-[tasks.test]
-dependencies = ["build"]
-command = "cargo"
-args = [
-  "test",
-  "--lib",
-  "--bins",
-  "--tests",
-  "--examples",
-  "--workspace",
-  # These tests run on Ubuntu without a screen. Desktop tests that require a screen fail, so we skip them
-  "--exclude",
-  "dioxus-desktop",
-  "--exclude",
-  "dioxus-mobile",
-]
-private = true
-
-[tasks.docs]
-dependencies = ["build"]
-command = "cargo"
-args = [
-  "test",
-  "--doc",
-  "--workspace",
-  "--all-features",
-]
-private = true
-
-[tasks.test-with-browser]
-env = { CARGO_MAKE_WORKSPACE_INCLUDE_MEMBERS = [
-  "**/packages/router",
-  "**/packages/desktop",
-] }
-private = true
-workspace = true

+ 91 - 0
packages/cli-opt/Cargo.toml

@@ -0,0 +1,91 @@
+[package]
+name = "dioxus-cli-opt"
+edition = "2021"
+version.workspace = true
+authors = ["Jonathan Kelley", "Evan Almloff"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/DioxusLabs/dioxus/"
+homepage = "https://dioxuslabs.com"
+description = "CLI optimizations for dioxus-cli"
+keywords = ["dom", "ui", "gui", "react"]
+
+[dependencies]
+anyhow = "1"
+manganis-core = { workspace = true }
+object = {version="0.36.0", features=["wasm"]}
+serde = { workspace = true, features = ["derive"] }
+serde_json = { workspace = true }
+const-serialize = { workspace = true, features = ["serde"] }
+tracing = { workspace = true }
+rayon = "1.8.0"
+
+# Image compression/conversion
+# - JPEG
+mozjpeg = { version = "0.10.7", default-features = false, features = [
+    "parallel",
+] }
+# - PNG
+imagequant = "4.2.0"
+png = "0.17.9"
+
+# Image format/conversion
+image = { version = "0.25", features = ["avif"] }
+
+# CSS Minification
+lightningcss = "1.0.0-alpha.60"
+
+# Js minification - swc has introduces minor versions with breaking changes in the past so we pin all of their crates
+swc = "=0.283.0"
+swc_allocator = { version = "=0.1.8", default-features = false }
+swc_atoms = { version = "=0.6.7", default-features = false }
+swc_cached = { version = "=0.3.20", default-features = false }
+swc_common = { version = "=0.37.5", default-features = false }
+swc_compiler_base = { version = "=0.19.0", default-features = false }
+swc_config = { version = "=0.1.15", default-features = false }
+swc_config_macro = { version = "=0.1.4", default-features = false }
+swc_ecma_ast = { version = "=0.118.2", default-features = false }
+swc_ecma_codegen = { version = "=0.155.1", default-features = false }
+swc_ecma_codegen_macros = { version = "=0.7.7", default-features = false }
+swc_ecma_compat_bugfixes = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_common = { version = "=0.11.0", default-features = false }
+swc_ecma_compat_es2015 = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_es2016 = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_es2017 = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_es2018 = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_es2019 = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_es2020 = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_es2021 = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_es2022 = { version = "=0.12.0", default-features = false }
+swc_ecma_compat_es3 = { version = "=0.12.0", default-features = false }
+swc_ecma_ext_transforms = { version = "=0.120.0", default-features = false }
+swc_ecma_lints = { version = "=0.100.0", default-features = false }
+swc_ecma_loader = { version = "=0.49.1", default-features = false }
+swc_ecma_minifier = { version = "=0.204.0", default-features = false }
+swc_ecma_parser = { version = "=0.149.1", default-features = false }
+swc_ecma_preset_env = { version = "=0.217.0", default-features = false, features = [
+    "serde",
+] }
+swc_ecma_transforms = { version = "=0.239.0", default-features = false }
+swc_ecma_transforms_base = { version = "=0.145.0", default-features = false }
+swc_ecma_transforms_classes = { version = "=0.134.0", default-features = false }
+swc_ecma_transforms_compat = { version = "=0.171.0", default-features = false }
+swc_ecma_transforms_macros = { version = "=0.5.5", default-features = false }
+swc_ecma_transforms_module = { version = "=0.190.0", default-features = false }
+swc_ecma_transforms_optimization = { version = "=0.208.0", default-features = false }
+swc_ecma_transforms_proposal = { version = "=0.178.0", default-features = false }
+swc_ecma_transforms_react = { version = "=0.191.0", default-features = false }
+swc_ecma_transforms_typescript = { version = "=0.198.1", default-features = false }
+swc_ecma_usage_analyzer = { version = "=0.30.3", default-features = false }
+swc_ecma_utils = { version = "=0.134.2", default-features = false }
+swc_ecma_visit = { version = "=0.104.8", default-features = false }
+swc_eq_ignore_macros = { version = "=0.1.4", default-features = false }
+swc_error_reporters = { version = "=0.21.0", default-features = false }
+swc_fast_graph = { version = "=0.25.0", default-features = false }
+swc_macros_common = { version = "=0.3.13", default-features = false }
+swc_node_comments = { version = "=0.24.0", default-features = false }
+swc_timer = { version = "=0.25.0", default-features = false }
+swc_trace_macro = { version = "=0.1.3", default-features = false }
+swc_transform_common = { version = "=0.1.1", default-features = false }
+swc_typescript = { version = "=0.5.0", default-features = false }
+swc_visit = { version = "=0.6.2", default-features = false }
+browserslist-rs = { version = "=0.16.0" }

+ 0 - 0
packages/cli/src/assets/css.rs → packages/cli-opt/src/css.rs


+ 1 - 1
packages/cli/src/assets/file.rs → packages/cli-opt/src/file.rs

@@ -8,7 +8,7 @@ use super::{
 };
 
 /// Process a specific file asset with the given options reading from the source and writing to the output path
-pub(crate) fn process_file_to(
+pub fn process_file_to(
     options: &AssetOptions,
     source: &Path,
     output_path: &Path,

+ 0 - 0
packages/cli/src/assets/folder.rs → packages/cli-opt/src/folder.rs


+ 0 - 0
packages/cli/src/assets/image/jpg.rs → packages/cli-opt/src/image/jpg.rs


+ 0 - 0
packages/cli/src/assets/image/mod.rs → packages/cli-opt/src/image/mod.rs


+ 0 - 0
packages/cli/src/assets/image/png.rs → packages/cli-opt/src/image/png.rs


+ 0 - 0
packages/cli/src/assets/js.rs → packages/cli-opt/src/js.rs


+ 0 - 0
packages/cli/src/assets/json.rs → packages/cli-opt/src/json.rs


+ 5 - 5
packages/cli/src/assets/mod.rs → packages/cli-opt/src/lib.rs

@@ -13,20 +13,20 @@ mod image;
 mod js;
 mod json;
 
-pub(crate) use file::process_file_to;
+pub use file::process_file_to;
 
 /// A manifest of all assets collected from dependencies
 ///
 /// This will be filled in primarily by incremental compilation artifacts.
 #[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize)]
-pub(crate) struct AssetManifest {
+pub struct AssetManifest {
     /// Map of bundled asset name to the asset itself
-    pub(crate) assets: HashMap<PathBuf, BundledAsset>,
+    pub assets: HashMap<PathBuf, BundledAsset>,
 }
 
 impl AssetManifest {
     #[allow(dead_code)]
-    pub(crate) fn load_from_file(path: &Path) -> anyhow::Result<Self> {
+    pub fn load_from_file(path: &Path) -> anyhow::Result<Self> {
         let src = std::fs::read_to_string(path)?;
 
         serde_json::from_str(&src)
@@ -34,7 +34,7 @@ impl AssetManifest {
     }
 
     /// Fill this manifest with a file object/rlib files, typically extracted from the linker intercepted
-    pub(crate) fn add_from_object_path(&mut self, path: &Path) -> anyhow::Result<()> {
+    pub fn add_from_object_path(&mut self, path: &Path) -> anyhow::Result<()> {
         let data = std::fs::read(path)?;
 
         match path.extension().and_then(|ext| ext.to_str()) {

+ 1 - 70
packages/cli/Cargo.toml

@@ -20,6 +20,7 @@ dioxus-core = { workspace = true, features = ["serialize"] }
 dioxus-core-types = { workspace = true }
 dioxus-devtools-types = { workspace = true }
 dioxus-cli-config = { workspace = true }
+dioxus-cli-opt = { workspace = true }
 dioxus-fullstack = { workspace = true }
 dioxus-dx-wire-format = { workspace = true }
 
@@ -90,76 +91,6 @@ ignore = "0.4.22"
 env_logger = { workspace = true }
 const-serialize = { workspace = true, features = ["serde"] }
 
-# Image compression/conversion
-# - JPEG
-mozjpeg = { version = "0.10.7", default-features = false, features = [
-    "parallel",
-] }
-# - PNG
-imagequant = "4.2.0"
-png = "0.17.9"
-# Image format/conversion
-image = { version = "0.25", features = ["avif"] }
-
-# CSS Minification
-lightningcss = "1.0.0-alpha.60"
-
-# Js minification - swc has introduces minor versions with breaking changes in the past so we pin all of their crates
-swc = "=0.283.0"
-swc_allocator = { version = "=0.1.8", default-features = false }
-swc_atoms = { version = "=0.6.7", default-features = false }
-swc_cached = { version = "=0.3.20", default-features = false }
-swc_common = { version = "=0.37.5", default-features = false }
-swc_compiler_base = { version = "=0.19.0", default-features = false }
-swc_config = { version = "=0.1.15", default-features = false }
-swc_config_macro = { version = "=0.1.4", default-features = false }
-swc_ecma_ast = { version = "=0.118.2", default-features = false }
-swc_ecma_codegen = { version = "=0.155.1", default-features = false }
-swc_ecma_codegen_macros = { version = "=0.7.7", default-features = false }
-swc_ecma_compat_bugfixes = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_common = { version = "=0.11.0", default-features = false }
-swc_ecma_compat_es2015 = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_es2016 = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_es2017 = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_es2018 = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_es2019 = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_es2020 = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_es2021 = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_es2022 = { version = "=0.12.0", default-features = false }
-swc_ecma_compat_es3 = { version = "=0.12.0", default-features = false }
-swc_ecma_ext_transforms = { version = "=0.120.0", default-features = false }
-swc_ecma_lints = { version = "=0.100.0", default-features = false }
-swc_ecma_loader = { version = "=0.49.1", default-features = false }
-swc_ecma_minifier = { version = "=0.204.0", default-features = false }
-swc_ecma_parser = { version = "=0.149.1", default-features = false }
-swc_ecma_preset_env = { version = "=0.217.0", default-features = false, features = [
-    "serde",
-] }
-swc_ecma_transforms = { version = "=0.239.0", default-features = false }
-swc_ecma_transforms_base = { version = "=0.145.0", default-features = false }
-swc_ecma_transforms_classes = { version = "=0.134.0", default-features = false }
-swc_ecma_transforms_compat = { version = "=0.171.0", default-features = false }
-swc_ecma_transforms_macros = { version = "=0.5.5", default-features = false }
-swc_ecma_transforms_module = { version = "=0.190.0", default-features = false }
-swc_ecma_transforms_optimization = { version = "=0.208.0", default-features = false }
-swc_ecma_transforms_proposal = { version = "=0.178.0", default-features = false }
-swc_ecma_transforms_react = { version = "=0.191.0", default-features = false }
-swc_ecma_transforms_typescript = { version = "=0.198.1", default-features = false }
-swc_ecma_usage_analyzer = { version = "=0.30.3", default-features = false }
-swc_ecma_utils = { version = "=0.134.2", default-features = false }
-swc_ecma_visit = { version = "=0.104.8", default-features = false }
-swc_eq_ignore_macros = { version = "=0.1.4", default-features = false }
-swc_error_reporters = { version = "=0.21.0", default-features = false }
-swc_fast_graph = { version = "=0.25.0", default-features = false }
-swc_macros_common = { version = "=0.3.13", default-features = false }
-swc_node_comments = { version = "=0.24.0", default-features = false }
-swc_timer = { version = "=0.25.0", default-features = false }
-swc_trace_macro = { version = "=0.1.3", default-features = false }
-swc_transform_common = { version = "=0.1.1", default-features = false }
-swc_typescript = { version = "=0.5.0", default-features = false }
-swc_visit = { version = "=0.6.2", default-features = false }
-browserslist-rs = { version = "=0.16.0" }
-
 tracing-subscriber = { version = "0.3.18", features = ["std", "env-filter", "json"] }
 console-subscriber = { version = "0.3.0", optional = true }
 tracing = { workspace = true }

+ 2 - 3
packages/cli/src/build/bundle.rs

@@ -1,8 +1,7 @@
-use crate::assets::process_file_to;
-use crate::Result;
-use crate::{assets::AssetManifest, TraceSrc};
 use crate::{BuildRequest, Platform};
+use crate::{Result, TraceSrc};
 use anyhow::Context;
+use dioxus_cli_opt::{process_file_to, AssetManifest};
 use manganis_core::AssetOptions;
 use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
 use std::collections::HashSet;

+ 12 - 4
packages/cli/src/build/request.rs

@@ -1,11 +1,10 @@
 use super::{progress::ProgressTx, BuildArtifacts};
 use crate::dioxus_crate::DioxusCrate;
-use crate::Result;
-use crate::{assets::AssetManifest, TraceSrc};
 use crate::{link::LinkAction, BuildArgs};
-use crate::{AppBundle, Platform};
+use crate::{AppBundle, Platform, Result, TraceSrc};
 use anyhow::Context;
 use dioxus_cli_config::{APP_TITLE_ENV, ASSET_ROOT_ENV};
+use dioxus_cli_opt::AssetManifest;
 use serde::Deserialize;
 use std::{
     path::{Path, PathBuf},
@@ -46,7 +45,10 @@ impl BuildRequest {
     pub(crate) async fn build_all(self) -> Result<AppBundle> {
         tracing::debug!("Running build command...");
 
-        let (app, server) = self.build_concurrent().await?;
+        let (app, server) = match self.build.force_sequential {
+            true => self.build_sequential().await?,
+            false => self.build_concurrent().await?,
+        };
 
         AppBundle::new(self, app, server).await
     }
@@ -59,6 +61,12 @@ impl BuildRequest {
         Ok((app, server))
     }
 
+    async fn build_sequential(&self) -> Result<(BuildArtifacts, Option<BuildArtifacts>)> {
+        let app = self.build_app().await?;
+        let server = self.build_server().await?;
+        Ok((app, server))
+    }
+
     pub(crate) async fn build_app(&self) -> Result<BuildArtifacts> {
         tracing::debug!("Building app...");
 

+ 190 - 188
packages/cli/src/cli/create.rs

@@ -223,191 +223,193 @@ fn remove_triple_newlines(string: &str) -> String {
     new_string
 }
 
-#[cfg(test)]
-pub(crate) mod tests {
-    use escargot::{CargoBuild, CargoRun};
-    use once_cell::sync::Lazy;
-    use std::fs::{create_dir_all, read_to_string};
-    use std::path::{Path, PathBuf};
-    use std::process::Command;
-    use tempfile::tempdir;
-    use toml::Value;
-
-    static BINARY: Lazy<CargoRun> = Lazy::new(|| {
-        CargoBuild::new()
-            .bin(env!("CARGO_BIN_NAME"))
-            .current_release()
-            .run()
-            .expect("Couldn't build the binary for tests.")
-    });
-
-    // Note: tests below (at least 6 of them) were written to mainly test
-    // correctness of project's directory and its name, because previously it
-    // was broken and tests bring a peace of mind. And also so that I don't have
-    // to run my local hand-made tests every time.
-
-    pub(crate) type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
-
-    pub(crate) fn subcommand(name: &str) -> Command {
-        let mut command = BINARY.command();
-        command.arg(name).arg("--yes"); // Skip any questions by choosing default answers.
-        command
-    }
-
-    pub(crate) fn get_cargo_toml_path(project_path: &Path) -> PathBuf {
-        project_path.join("Cargo.toml")
-    }
-
-    pub(crate) fn get_project_name(cargo_toml_path: &Path) -> Result<String> {
-        Ok(toml::from_str::<Value>(&read_to_string(cargo_toml_path)?)?
-            .get("package")
-            .unwrap()
-            .get("name")
-            .unwrap()
-            .as_str()
-            .unwrap()
-            .to_string())
-    }
-
-    fn subcommand_new() -> Command {
-        subcommand("new")
-    }
-
-    #[test]
-    fn test_subcommand_new_with_dot_path() -> Result<()> {
-        let project_dir = "dir";
-        let project_name = project_dir;
-
-        let temp_dir = tempdir()?;
-        // Make current dir's name deterministic.
-        let current_dir = temp_dir.path().join(project_dir);
-        create_dir_all(&current_dir)?;
-        let project_path = &current_dir;
-        assert!(project_path.exists());
-
-        assert!(subcommand_new()
-            .arg(".")
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let cargo_toml_path = get_cargo_toml_path(project_path);
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_new_with_1_dir_path() -> Result<()> {
-        let project_dir = "dir";
-        let project_name = project_dir;
-
-        let current_dir = tempdir()?;
-
-        assert!(subcommand_new()
-            .arg(project_dir)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let project_path = current_dir.path().join(project_dir);
-        let cargo_toml_path = get_cargo_toml_path(&project_path);
-        assert!(project_path.exists());
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_new_with_2_dir_path() -> Result<()> {
-        let project_dir = "a/b";
-        let project_name = "b";
-
-        let current_dir = tempdir()?;
-
-        assert!(subcommand_new()
-            .arg(project_dir)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let project_path = current_dir.path().join(project_dir);
-        let cargo_toml_path = get_cargo_toml_path(&project_path);
-        assert!(project_path.exists());
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_new_with_dot_path_and_custom_name() -> Result<()> {
-        let project_dir = "dir";
-        let project_name = "project";
-
-        let temp_dir = tempdir()?;
-        // Make current dir's name deterministic.
-        let current_dir = temp_dir.path().join(project_dir);
-        create_dir_all(&current_dir)?;
-        let project_path = &current_dir;
-        assert!(project_path.exists());
-
-        assert!(subcommand_new()
-            .arg("--name")
-            .arg(project_name)
-            .arg(".")
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let cargo_toml_path = get_cargo_toml_path(project_path);
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_new_with_1_dir_path_and_custom_name() -> Result<()> {
-        let project_dir = "dir";
-        let project_name = "project";
-
-        let current_dir = tempdir()?;
-
-        assert!(subcommand_new()
-            .arg(project_dir)
-            .arg("--name")
-            .arg(project_name)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let project_path = current_dir.path().join(project_dir);
-        let cargo_toml_path = get_cargo_toml_path(&project_path);
-        assert!(project_path.exists());
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_new_with_2_dir_path_and_custom_name() -> Result<()> {
-        let project_dir = "a/b";
-        let project_name = "project";
-
-        let current_dir = tempdir()?;
-
-        assert!(subcommand_new()
-            .arg(project_dir)
-            .arg("--name")
-            .arg(project_name)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let project_path = current_dir.path().join(project_dir);
-        let cargo_toml_path = get_cargo_toml_path(&project_path);
-        assert!(project_path.exists());
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-}
+// todo: re-enable these tests with better parallelization
+//
+// #[cfg(test)]
+// pub(crate) mod tests {
+//     use escargot::{CargoBuild, CargoRun};
+//     use once_cell::sync::Lazy;
+//     use std::fs::{create_dir_all, read_to_string};
+//     use std::path::{Path, PathBuf};
+//     use std::process::Command;
+//     use tempfile::tempdir;
+//     use toml::Value;
+
+//     static BINARY: Lazy<CargoRun> = Lazy::new(|| {
+//         CargoBuild::new()
+//             .bin(env!("CARGO_BIN_NAME"))
+//             .current_release()
+//             .run()
+//             .expect("Couldn't build the binary for tests.")
+//     });
+
+//     // Note: tests below (at least 6 of them) were written to mainly test
+//     // correctness of project's directory and its name, because previously it
+//     // was broken and tests bring a peace of mind. And also so that I don't have
+//     // to run my local hand-made tests every time.
+
+//     pub(crate) type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
+
+//     pub(crate) fn subcommand(name: &str) -> Command {
+//         let mut command = BINARY.command();
+//         command.arg(name).arg("--yes"); // Skip any questions by choosing default answers.
+//         command
+//     }
+
+//     pub(crate) fn get_cargo_toml_path(project_path: &Path) -> PathBuf {
+//         project_path.join("Cargo.toml")
+//     }
+
+//     pub(crate) fn get_project_name(cargo_toml_path: &Path) -> Result<String> {
+//         Ok(toml::from_str::<Value>(&read_to_string(cargo_toml_path)?)?
+//             .get("package")
+//             .unwrap()
+//             .get("name")
+//             .unwrap()
+//             .as_str()
+//             .unwrap()
+//             .to_string())
+//     }
+
+//     fn subcommand_new() -> Command {
+//         subcommand("new")
+//     }
+
+//     #[test]
+//     fn test_subcommand_new_with_dot_path() -> Result<()> {
+//         let project_dir = "dir";
+//         let project_name = project_dir;
+
+//         let temp_dir = tempdir()?;
+//         // Make current dir's name deterministic.
+//         let current_dir = temp_dir.path().join(project_dir);
+//         create_dir_all(&current_dir)?;
+//         let project_path = &current_dir;
+//         assert!(project_path.exists());
+
+//         assert!(subcommand_new()
+//             .arg(".")
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let cargo_toml_path = get_cargo_toml_path(project_path);
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_new_with_1_dir_path() -> Result<()> {
+//         let project_dir = "dir";
+//         let project_name = project_dir;
+
+//         let current_dir = tempdir()?;
+
+//         assert!(subcommand_new()
+//             .arg(project_dir)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let project_path = current_dir.path().join(project_dir);
+//         let cargo_toml_path = get_cargo_toml_path(&project_path);
+//         assert!(project_path.exists());
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_new_with_2_dir_path() -> Result<()> {
+//         let project_dir = "a/b";
+//         let project_name = "b";
+
+//         let current_dir = tempdir()?;
+
+//         assert!(subcommand_new()
+//             .arg(project_dir)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let project_path = current_dir.path().join(project_dir);
+//         let cargo_toml_path = get_cargo_toml_path(&project_path);
+//         assert!(project_path.exists());
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_new_with_dot_path_and_custom_name() -> Result<()> {
+//         let project_dir = "dir";
+//         let project_name = "project";
+
+//         let temp_dir = tempdir()?;
+//         // Make current dir's name deterministic.
+//         let current_dir = temp_dir.path().join(project_dir);
+//         create_dir_all(&current_dir)?;
+//         let project_path = &current_dir;
+//         assert!(project_path.exists());
+
+//         assert!(subcommand_new()
+//             .arg("--name")
+//             .arg(project_name)
+//             .arg(".")
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let cargo_toml_path = get_cargo_toml_path(project_path);
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_new_with_1_dir_path_and_custom_name() -> Result<()> {
+//         let project_dir = "dir";
+//         let project_name = "project";
+
+//         let current_dir = tempdir()?;
+
+//         assert!(subcommand_new()
+//             .arg(project_dir)
+//             .arg("--name")
+//             .arg(project_name)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let project_path = current_dir.path().join(project_dir);
+//         let cargo_toml_path = get_cargo_toml_path(&project_path);
+//         assert!(project_path.exists());
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_new_with_2_dir_path_and_custom_name() -> Result<()> {
+//         let project_dir = "a/b";
+//         let project_name = "project";
+
+//         let current_dir = tempdir()?;
+
+//         assert!(subcommand_new()
+//             .arg(project_dir)
+//             .arg("--name")
+//             .arg(project_name)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let project_path = current_dir.path().join(project_dir);
+//         let cargo_toml_path = get_cargo_toml_path(&project_path);
+//         assert!(project_path.exists());
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+// }

+ 151 - 149
packages/cli/src/cli/init.rs

@@ -78,152 +78,154 @@ impl Init {
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use std::{fs::create_dir_all, process::Command};
-    use tempfile::tempdir;
-
-    use super::create::tests::*;
-
-    // Note: tests below (at least 6 of them) were written to mainly test
-    // correctness of project's directory and its name, because previously it
-    // was broken and tests bring a peace of mind. And also so that I don't have
-    // to run my local hand-made tests every time.
-
-    fn subcommand_init() -> Command {
-        subcommand("init")
-    }
-
-    #[test]
-    fn test_subcommand_init_with_default_path() -> Result<()> {
-        let project_dir = "dir";
-        let project_name = project_dir;
-
-        let temp_dir = tempdir()?;
-        // Make current dir's name deterministic.
-        let current_dir = temp_dir.path().join(project_dir);
-        create_dir_all(&current_dir)?;
-        let project_path = &current_dir;
-        assert!(project_path.exists());
-
-        assert!(subcommand_init().current_dir(&current_dir).status().is_ok());
-
-        let cargo_toml_path = get_cargo_toml_path(project_path);
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_init_with_1_dir_path() -> Result<()> {
-        let project_dir = "dir";
-        let project_name = project_dir;
-
-        let current_dir = tempdir()?;
-
-        assert!(subcommand_init()
-            .arg(project_dir)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let project_path = current_dir.path().join(project_dir);
-        let cargo_toml_path = get_cargo_toml_path(&project_path);
-        assert!(project_path.exists());
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_init_with_2_dir_path() -> Result<()> {
-        let project_dir = "a/b";
-        let project_name = "b";
-
-        let current_dir = tempdir()?;
-
-        assert!(subcommand_init()
-            .arg(project_dir)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let project_path = current_dir.path().join(project_dir);
-        let cargo_toml_path = get_cargo_toml_path(&project_path);
-        assert!(project_path.exists());
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_init_with_default_path_and_custom_name() -> Result<()> {
-        let project_dir = "dir";
-        let project_name = "project";
-
-        let temp_dir = tempdir()?;
-        // Make current dir's name deterministic.
-        let current_dir = temp_dir.path().join(project_dir);
-        create_dir_all(&current_dir)?;
-        let project_path = &current_dir;
-        assert!(project_path.exists());
-
-        assert!(subcommand_init()
-            .arg("--name")
-            .arg(project_name)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let cargo_toml_path = get_cargo_toml_path(project_path);
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_init_with_1_dir_path_and_custom_name() -> Result<()> {
-        let project_dir = "dir";
-        let project_name = "project";
-
-        let current_dir = tempdir()?;
-
-        assert!(subcommand_init()
-            .arg(project_dir)
-            .arg("--name")
-            .arg(project_name)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let project_path = current_dir.path().join(project_dir);
-        let cargo_toml_path = get_cargo_toml_path(&project_path);
-        assert!(project_path.exists());
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-
-    #[test]
-    fn test_subcommand_init_with_2_dir_path_and_custom_name() -> Result<()> {
-        let project_dir = "a/b";
-        let project_name = "project";
-
-        let current_dir = tempdir()?;
-
-        assert!(subcommand_init()
-            .arg(project_dir)
-            .arg("--name")
-            .arg(project_name)
-            .current_dir(&current_dir)
-            .status()
-            .is_ok());
-
-        let project_path = current_dir.path().join(project_dir);
-        let cargo_toml_path = get_cargo_toml_path(&project_path);
-        assert!(project_path.exists());
-        assert!(cargo_toml_path.exists());
-        assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
-        Ok(())
-    }
-}
+// todo: re-enable these tests with better parallelization
+//
+// #[cfg(test)]
+// mod tests {
+//     use std::{fs::create_dir_all, process::Command};
+//     use tempfile::tempdir;
+
+//     use super::create::tests::*;
+
+//     // Note: tests below (at least 6 of them) were written to mainly test
+//     // correctness of project's directory and its name, because previously it
+//     // was broken and tests bring a peace of mind. And also so that I don't have
+//     // to run my local hand-made tests every time.
+
+//     fn subcommand_init() -> Command {
+//         subcommand("init")
+//     }
+
+//     #[test]
+//     fn test_subcommand_init_with_default_path() -> Result<()> {
+//         let project_dir = "dir";
+//         let project_name = project_dir;
+
+//         let temp_dir = tempdir()?;
+//         // Make current dir's name deterministic.
+//         let current_dir = temp_dir.path().join(project_dir);
+//         create_dir_all(&current_dir)?;
+//         let project_path = &current_dir;
+//         assert!(project_path.exists());
+
+//         assert!(subcommand_init().current_dir(&current_dir).status().is_ok());
+
+//         let cargo_toml_path = get_cargo_toml_path(project_path);
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_init_with_1_dir_path() -> Result<()> {
+//         let project_dir = "dir";
+//         let project_name = project_dir;
+
+//         let current_dir = tempdir()?;
+
+//         assert!(subcommand_init()
+//             .arg(project_dir)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let project_path = current_dir.path().join(project_dir);
+//         let cargo_toml_path = get_cargo_toml_path(&project_path);
+//         assert!(project_path.exists());
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_init_with_2_dir_path() -> Result<()> {
+//         let project_dir = "a/b";
+//         let project_name = "b";
+
+//         let current_dir = tempdir()?;
+
+//         assert!(subcommand_init()
+//             .arg(project_dir)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let project_path = current_dir.path().join(project_dir);
+//         let cargo_toml_path = get_cargo_toml_path(&project_path);
+//         assert!(project_path.exists());
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_init_with_default_path_and_custom_name() -> Result<()> {
+//         let project_dir = "dir";
+//         let project_name = "project";
+
+//         let temp_dir = tempdir()?;
+//         // Make current dir's name deterministic.
+//         let current_dir = temp_dir.path().join(project_dir);
+//         create_dir_all(&current_dir)?;
+//         let project_path = &current_dir;
+//         assert!(project_path.exists());
+
+//         assert!(subcommand_init()
+//             .arg("--name")
+//             .arg(project_name)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let cargo_toml_path = get_cargo_toml_path(project_path);
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_init_with_1_dir_path_and_custom_name() -> Result<()> {
+//         let project_dir = "dir";
+//         let project_name = "project";
+
+//         let current_dir = tempdir()?;
+
+//         assert!(subcommand_init()
+//             .arg(project_dir)
+//             .arg("--name")
+//             .arg(project_name)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let project_path = current_dir.path().join(project_dir);
+//         let cargo_toml_path = get_cargo_toml_path(&project_path);
+//         assert!(project_path.exists());
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+
+//     #[test]
+//     fn test_subcommand_init_with_2_dir_path_and_custom_name() -> Result<()> {
+//         let project_dir = "a/b";
+//         let project_name = "project";
+
+//         let current_dir = tempdir()?;
+
+//         assert!(subcommand_init()
+//             .arg(project_dir)
+//             .arg("--name")
+//             .arg(project_name)
+//             .current_dir(&current_dir)
+//             .status()
+//             .is_ok());
+
+//         let project_path = current_dir.path().join(project_dir);
+//         let cargo_toml_path = get_cargo_toml_path(&project_path);
+//         assert!(project_path.exists());
+//         assert!(cargo_toml_path.exists());
+//         assert_eq!(get_project_name(&cargo_toml_path)?, project_name);
+//         Ok(())
+//     }
+// }

+ 1 - 1
packages/cli/src/cli/link.rs

@@ -1,4 +1,4 @@
-use crate::assets::AssetManifest;
+use dioxus_cli_opt::AssetManifest;
 use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
 

+ 0 - 1
packages/cli/src/main.rs

@@ -3,7 +3,6 @@
 #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
 #![cfg_attr(docsrs, feature(doc_cfg))]
 
-mod assets;
 mod build;
 mod bundle_utils;
 mod cli;

+ 3 - 3
packages/const-serialize-macro/Cargo.toml

@@ -10,9 +10,9 @@ homepage = "https://dioxuslabs.com/learn/0.5/getting_started"
 keywords = ["const", "serialize"]
 
 [dependencies]
-syn = "2.0"
-quote = "1.0"
-proc-macro2 = "1.0.86"
+syn = { workspace = true }
+quote = { workspace = true }
+proc-macro2 = { workspace = true }
 
 [lib]
 proc-macro = true

+ 3 - 3
packages/manganis/manganis-macro/Cargo.toml

@@ -15,9 +15,9 @@ proc-macro = true
 # be careful with dependencies you add here - these need to get compiled for the proc macro and therefore
 # prevent the main code from compiling!
 [dependencies]
-proc-macro2 = { version = "1.0" }
-quote = "1.0"
-syn = { version = "2.0", features = ["full", "extra-traits"] }
+proc-macro2 = { workspace = true }
+quote = { workspace = true }
+syn = { workspace = true, features = ["full", "extra-traits"] }
 manganis-core = { workspace = true }
 
 [features]