Created new repo. Inital Commit🍡

This commit is contained in:
MrDulfin 2024-12-07 15:43:46 -05:00
commit 7ba2925a98
74 changed files with 7909 additions and 0 deletions

26
.gitignore vendored Normal file
View file

@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
*/cargo.lock
*.dlib
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

3
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
}

6
README.md Normal file
View file

@ -0,0 +1,6 @@
# Dango Music Player
### Dango Music Player is an easy to use Music Player for all types of users to enjoy their music!
This project is under construction and everything is subject to change

11
index.html Normal file
View file

@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

1721
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

30
package.json Normal file
View file

@ -0,0 +1,30 @@
{
"name": "dango-music-player",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"tauri": "tauri"
},
"dependencies": {
"@jprochazk/cbor": "github:jprochazk/cbor",
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-shell": "^2",
"cbor": "github:jprochazk/cbor",
"cbor-x": "^1.6.0",
"node-fetch": "^3.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@tauri-apps/cli": "^2",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.2.2",
"vite": "^5.3.1"
}
}

7
src-tauri/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Generated by Tauri
# will have schema files for capabilities auto-completion
/gen/schemas

5409
src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

35
src-tauri/Cargo.toml Normal file
View file

@ -0,0 +1,35 @@
[package]
name = "dango-music-player"
version = "0.0.0"
description = "A music player."
authors = ["G2", "MrDulfin"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
# The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
name = "dango_music_player_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = ["unstable"] }
tauri-plugin-shell = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
dmp-core = { path = "/media/rocket/Dangoware/Dango Music Player/dmp-core" }
futures = "0.3.31"
crossbeam = "0.8.4"
directories = "5.0.1"
uuid = { version = "1.11.0", features = ["v4"] }
ciborium = "0.2.2"
mime = "0.3.17"
[features]
default = [ "custom-protocol" ]
custom-protocol = [ "tauri/custom-protocol" ]

3
src-tauri/build.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

View file

@ -0,0 +1,10 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"shell:allow-open"
]
}

BIN
src-tauri/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
src-tauri/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
src-tauri/icons/icon.icns Normal file

Binary file not shown.

BIN
src-tauri/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
src-tauri/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

155
src-tauri/src/lib.rs Normal file
View file

@ -0,0 +1,155 @@
use std::{fs, path::PathBuf, str::FromStr, thread::spawn};
use crossbeam::channel::{unbounded, Receiver, Sender};
use dmp_core::{config::{Config, ConfigLibrary}, music_controller::controller::{Controller, ControllerHandle}, music_player::gstreamer::GStreamer, music_storage::library::MusicLibrary};
use tauri::{Manager, State, WebviewWindowBuilder, Wry};
use uuid::Uuid;
use crate::wrappers::{get_library, play, pause, prev, set_volume, get_song, next};
pub mod wrappers;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let (rx, tx) = unbounded::<Config>();
let (lib_rx, lib_tx) = unbounded::<PathBuf>();
let (handle_rx, handle_tx) = unbounded::<ControllerHandle>();
let t1 = spawn(move || {
let mut config = { tx.recv().unwrap() } ;
let scan_path = { lib_tx.recv().unwrap() };
let save_path = config.libraries.library_folder.join("library.dlib");
let mut library = MusicLibrary::init(
save_path.clone(),
if let Ok(lib) = config.libraries.get_default() {
lib.uuid
} else {
Uuid::new_v4()
}
).unwrap();
library.scan_folder(&scan_path).unwrap();
config.push_library( ConfigLibrary::new(save_path, String::from("Library"), Some(vec![scan_path.clone()])));
// config.write_file().unwrap();
let (handle, input) = ControllerHandle::new(
library,
std::sync::Arc::new(std::sync::RwLock::new(config))
);
handle_rx.send(handle).unwrap();
let controller = futures::executor::block_on(Controller::<GStreamer>::start(input)).unwrap();
});
let app = tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.invoke_handler(tauri::generate_handler![
get_config,
new_library_window,
create_library,
get_library,
play,
pause,
set_volume,
next,
prev,
get_song,
]).manage(ConfigRx(rx))
.manage(LibRx(lib_rx))
.manage(HandleTx(handle_tx))
.build(tauri::generate_context!())
.expect("error while building tauri application");
app
.run(|_app_handle, event| match event {
tauri::RunEvent::ExitRequested { api, .. } => {
api.prevent_exit();
}
_ => {}
});
t1.join().unwrap();
}
struct ConfigRx(Sender<Config>);
struct LibRx(Sender<PathBuf>);
struct HandleTx(Receiver<ControllerHandle>);
#[tauri::command]
async fn get_config(state: State<'_, ConfigRx>) -> Result<Config, String> {
if let Some(dir) = directories::ProjectDirs::from("", "Dangoware", "dmp") {
let path = dir.config_dir();
fs::create_dir(path).or_else(|err| {
if err.kind() == std::io::ErrorKind::AlreadyExists {
Ok(())
} else {
Err(err)
}
}).unwrap();
// dbg!(&dir);
let config = if let Ok(c) = Config::read_file(PathBuf::from(path).join("config")) {
c
} else {
let c = Config {
path: PathBuf::from(path).join("config"),
..Default::default()
};
c.write_file().unwrap();
c
};
state.inner().0.send(config.clone()).unwrap();
Ok(config)
} else {
panic!("No config dir for DMP")
}
}
#[tauri::command]
async fn new_library_window(app: tauri::AppHandle<Wry>) -> Result<(), String> {
WebviewWindowBuilder::new(
&app,
"library_create",
tauri::WebviewUrl::App(PathBuf::from_str("/src/create_library_window/index.html").unwrap())
).title("Create a Library")
.focused(true)
.maximizable(false)
.build()
.unwrap();
Ok(())
}
#[tauri::command]
async fn create_library(
app: tauri::AppHandle<Wry>,
lib_rx: State<'_, LibRx>,
handle_tx: State<'_, HandleTx>,
window: tauri::Window<Wry>,
path: String
) -> Result<(), String> {
println!("{path}");
let path = PathBuf::from(path);
if !path.exists() {
panic!("Path {} does not exist!", path.display())
} else if !path.is_dir() {
panic!("Path {} is not a directory!", path.display())
}
lib_rx.inner().0.send(path).unwrap();
app.manage(handle_tx.inner().0.recv().unwrap());
window.close().unwrap();
Ok(())
}

9
src-tauri/src/main.rs Normal file
View file

@ -0,0 +1,9 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
pub mod wrappers;
fn main() {
dango_music_player_lib::run()
}

80
src-tauri/src/wrappers.rs Normal file
View file

@ -0,0 +1,80 @@
use dmp_core::{music_controller::controller::{ControllerHandle, LibraryCommand, LibraryResponse, PlayerResponse}, music_storage::library::Song};
use tauri::{ipc::Response, State};
use uuid::Uuid;
#[tauri::command]
pub async fn play(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::Play).await.unwrap();
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
unreachable!()
};
Ok(())
}
#[tauri::command]
pub async fn pause(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::Pause).await.unwrap();
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
unreachable!()
};
Ok(())
}
#[tauri::command]
pub async fn set_volume(ctrl_handle: State<'_, ControllerHandle>, volume: f64) -> Result<(), String> {
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::SetVolume(volume)).await.unwrap();
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
unreachable!()
};
Ok(())
}
#[tauri::command]
pub async fn get_volume(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
Ok(())
}
#[tauri::command]
pub async fn next(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::NextSong).await.unwrap();
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
unreachable!()
};
Ok(())
}
#[tauri::command]
pub async fn prev(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::PrevSong).await.unwrap();
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
unreachable!()
};
Ok(())
}
#[tauri::command]
pub async fn now_playing(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
Ok(())
}
#[tauri::command]
pub async fn get_library(ctrl_handle: State<'_, ControllerHandle>) -> Result<Response, String> {
println!("getting songs");
ctrl_handle.lib_mail.send(LibraryCommand::AllSongs).await.unwrap();
let LibraryResponse::AllSongs(songs) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
println!("got songs");
let mut buf = vec![];
ciborium::into_writer(&songs, &mut buf);
Ok(Response::new(buf))
}
#[tauri::command]
pub async fn get_song(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
ctrl_handle.lib_mail.send(LibraryCommand::Song(Uuid::default())).await.unwrap();
let LibraryResponse::Song(_) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
println!("got songs");
Ok(())
}

35
src-tauri/tauri.conf.json Normal file
View file

@ -0,0 +1,35 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Dango Music Player",
"version": "0.0.1",
"identifier": "com.dango-music-player.app",
"build": {
"beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "npm run build",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"title": "Dango Music Player",
"width": 800,
"height": 600
}
],
"security": {
"csp": null
}
},
"bundle": {
"active": true,
"targets": "all",
"icon": [
"./icons/32x32.png",
"./icons/128x128.png",
"./icons/128x128@2x.png",
"./icons/icon.icns",
"./icons/icon.ico"
]
}
}

73
src/App.css Normal file
View file

@ -0,0 +1,73 @@
.container {
position: absolute;
top: -1px;
left: 0;
height: 100%;
width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: stretch;
}
.leftSide {
width: 85%;
height: 100%;
display: flex;
flex-direction: column;
}
.rightSide {
position: relative;
align-self:flex-end;
width: 15%;
height: 100%;
background-color: #c1bcd1;
display: flex;
flex-direction: column;
}
.playlistHead {
position: relative;
height: 3.5%;
width: 100%;
background-color: #876765;
}
.mainView {
background-color: #f5eab2;
height: 91.5%;
}
#playBar {
position:relative;
bottom: 0;
left: 0;
background-color: #4c4373;
width: 100%;
height: 5%;
padding: 1.5%;
}
.topHalf {
display: flex;
justify-content: space-around;
}
#seekBar {
width: 100%;
}
.nowPlaying {
text-align: center;
height: 25%;
}
#nowPlayingArtwork {
width: 90%;
padding: 5%;
}
.Queue {
position: relative;
bottom: -25%;
background-color: burlywood;
height: 50%;
}

122
src/App.tsx Normal file
View file

@ -0,0 +1,122 @@
import { useEffect, useRef, useState } from "react";
import reactLogo from "./assets/react.svg";
import { invoke } from "@tauri-apps/api/core";
import "./App.css";
import { Config, Song } from "./types";
import { decode, encode } from 'cbor-x';
import CBOR from "cbor";
function App() {
useEffect(() => {
getConfig();
invoke('set_volume', { volume: 0.04 }).then( () => {} )
}, [])
return (
<main className="container">
<div className="leftSide">
<PlaylistHead />
<MainView />
<PlayBar />
</div>
<div className="rightSide">
<NowPlaying />
<Queue />
</div>
</main>
);
}
export default App;
function getConfig(): any {
invoke('get_config').then( (_config) => {
let config = _config as Config;
if (config.libraries.libraries.length == 0) {
newWindow()
}
})
}
function newWindow() {
invoke('new_library_window').then(() => {})
}
function PlaylistHead() {
return (
<section className="playlistHead">
<button>Library</button>
<button>Playlist 1</button>
<button>Playlist 2</button>
<button>Playlist 3</button>
<button>Playlist 4</button>
<button>Playlist 5</button>
<button>Playlist 6</button>
</section>
)
}
function MainView() {
return (
<div className="mainView">
main view
<button onClick={ () => invoke('get_library').then((bytes) => {
console.log(bytes);
let arr = new Uint8Array(bytes as ArrayBuffer);
let a: any = CBOR.decode(arr);
console.log(a);
}) }>get library</button>
</div>
)
}
function PlayBar() {
let [playing, setPlaying] = useState('play');
return (
<section id="playBar" className="playBar">
<div className="topHalf">
<div>
<button>shuffle</button>
<button>loop</button>
</div>
<button onClick={ () => invoke('prev').then(() => {}) }>prev</button>
<button onClick={ (_) => {
if (playing == 'play') {
setPlaying('pause')
invoke('play').then(() => {})
} else {
setPlaying('play')
invoke('pause').then(() => {})
}
}}>{ playing }</button>
<button onClick={ () => invoke('next').then(() => {}) }>next</button>
<input type="range" name="volume" id="volumeSlider" />
</div>
<input type="range" name="seek" id="seekBar" />
</section>
)
}
function NowPlaying() {
return (
<section className="nowPlaying">
<img id="nowPlayingArtwork" src="https://images.genius.com/22648cfc4f618884df6d6082962b34d2.1000x1000x1.png" />
<h2></h2>
<p>t+pazolite; </p>
<p>Heartache Debug</p>
</section>
)
}
function Queue() {
return (
<section className="Queue">
This is where the Queue be
</section>
)
}

View file

@ -0,0 +1,24 @@
import { invoke } from "@tauri-apps/api/core";
import { useRef } from "react";
import ReactDOM from "react-dom/client";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<App />,
);
function App() {
let x = useRef('')
return (
<>
<h2>Insert your music folder path here</h2>
<form>
<input type="text" name="libinput" id="libinput" onChange={ (event) => x.current = event.target.value as string } />
<input type="submit" value="sumbit" onClick={(event) => {
event.preventDefault();
invoke('create_library', { path: x.current }).then(() => {})
}} />
</form>
</>
)
}

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Library Thing</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./code.tsx"></script>
</body>
</html>

7
src/main.tsx Normal file
View file

@ -0,0 +1,7 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<App />,
);

63
src/types.ts Normal file
View file

@ -0,0 +1,63 @@
export interface Configlibrary {
name: string,
path: string,
uuid: string,
scan_folders?: string[]
}
export interface ConfigLibraries {
default_library: string,
library_folder: string,
libraries: Configlibrary[]
}
export interface Config {
path: string,
backup_folder?: string,
libraries: ConfigLibraries,
volume: number,
connections: ConfigConnections,
}
export interface ConfigConnections {
listenbrainz_token?: string
}
export interface Song {
location: URI[],
uuid: string,
plays: number,
skips: number,
favorited: boolean,
banned?: BannedType,
rating?: number,
format?: string,
duration: number,
play_time: number,
last_played?: number,
date_added?: number,
date_modified?: number,
album_art: AlbumArt[],
tags: Map<Tag, String>,
internal_tags: InternalTag[],
}
export enum InternalTag {
}
export enum Tag {
}
export enum AlbumArt {
}
export enum URI {
}
export enum BannedType {
}

1
src/vite-env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="vite/client" />

25
tsconfig.json Normal file
View file

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

10
tsconfig.node.json Normal file
View file

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

32
vite.config.ts Normal file
View file

@ -0,0 +1,32 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// @ts-expect-error process is a nodejs global
const host = process.env.TAURI_DEV_HOST;
// https://vitejs.dev/config/
export default defineConfig(async () => ({
plugins: [react()],
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
//
// 1. prevent vite from obscuring rust errors
clearScreen: false,
// 2. tauri expects a fixed port, fail if that port is not available
server: {
port: 1420,
strictPort: true,
host: host || false,
hmr: host
? {
protocol: "ws",
host,
port: 1421,
}
: undefined,
watch: {
// 3. tell vite to ignore watching `src-tauri`
ignored: ["**/src-tauri/**"],
},
},
}));