├── Images ├── example1.png ├── example2.png └── tauri-sveltekit-sqlite.png ├── README.md ├── src-tauri ├── Cargo.toml ├── build.rs ├── icons │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── 32x32.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ ├── Square30x30Logo.png │ ├── Square310x310Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── StoreLogo.png │ ├── icon.icns │ ├── icon.ico │ └── icon.png ├── sqlite.db ├── src │ ├── commands.rs │ ├── db.rs │ └── main.rs └── tauri.conf.json ├── src ├── app.d.ts ├── app.html ├── lib │ ├── index.ts │ └── table.svelte └── routes │ ├── +layout.ts │ └── +page.svelte ├── static └── favicon.png ├── svelte.config.js ├── tsconfig.json └── vite.config.ts /Images/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/Images/example1.png -------------------------------------------------------------------------------- /Images/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/Images/example2.png -------------------------------------------------------------------------------- /Images/tauri-sveltekit-sqlite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/Images/tauri-sveltekit-sqlite.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![tauri-svelte-sqlite](https://github.com/Lmedmo/Tauri-SvelteKit-SQLite/assets/102483463/dce676f1-d899-4695-98be-df16a02a0eab) 2 | 3 | # Overview 4 | This guide will walk you through the process of integrating the primary components of a modern full stack desktop application — Frontend, Backend, and Database. Tauri which is implemented in Rust will serve as our Backend, while SvelteKit will serve as our Frontend. The database we will use is SQLite and to do this we will be using SQLx; a Rust toolkit for communicating asynchronously with a number of different databases (MySQL, MSSQL, PostgreSQL, and SQLite). We will use Tauri’s built-in capabilities to then pass information back and forth between the front and backend. The purpose of this guide is simply to share what I have learned in my journey to create cross platform applications for a number of personal and professional projects. As I continue to grow my understanding and refine techniques to build applications on top of this core architecture, I will be sure to update the project’s GitHub repository along with this guide to reflect my methodology (See the ‘Additional Enhancements’ section). I will also include this [link to my Notion page for this project](https://leafdeveloper.notion.site/Tauri-SvelteKit-SQLite-e520a1051f5c47c29f919fbf6bc02015?pvs=4) which includes helpful links to articles, documentation, examples, and eventually links to my own applications once I have gotten them ready enough to be seen and taken seriously haha. With all that said, let’s get coding!! 5 | 6 | --- 7 | 8 |
9 | 10 |

11 | Step 1: Set up environment and Install prerequisites 12 |

13 |
14 | 15 |

Windows

16 | 17 | - [ ] Install **MS Visual Studio C++ build tools** and **Windows 10 SDK** 18 | - [ ] WebView2 (Most likely already installed as it is part of Win10 and Win11 by default) 19 | - [ ] Install Rust from the [website](https://www.rust-lang.org/tools/install) or by running the following command 20 | ```powershell 21 | winget install --id Rustlang.Rustup 22 | ``` 23 |
24 |

macOS

25 | 26 | - [ ] Install CLang and macOS Dev Dependencies using the following command 27 | ```shell 28 | xcode-select --install 29 | ``` 30 | - [ ] Install Rust with the following command then restart your Terminal for changes to take effect 31 | ```shell 32 | curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh 33 | ``` 34 |
35 |

Linux

36 | 37 | Use this link to [the official Tauri website](https://tauri.app/v1/guides/getting-started/prerequisites#installing) to find instructions on how to install system dependencies for your specific distro 38 |
39 |
40 | 41 | --- 42 | 43 |
44 | 45 |

46 | Step 2: Create the SvelteKit Frontend 47 |

48 |
49 | 50 | - [ ] Using the tool of your choice, run one of the following commands 51 | ```shell 52 | npm create svelte@latest 53 | ``` 54 | ```shell 55 | pnpm create svelte 56 | ``` 57 | - [ ] Select the following options: 58 | - Current directory 59 | - Yes (to Continue) 60 | - Skeleton project 61 | - TypeScript 62 | - Additions: ESLint, Prettier 63 | - [ ] Using the tool of your choice, run one of the following commands 64 | ```shell 65 | npm install 66 | ``` 67 | ```shell 68 | pnpm install 69 | ``` 70 | - [ ] Add static adapter for Static Site Generation 71 | ```shell 72 | npm install --save-dev @sveltejs/adapter-static 73 | ``` 74 | ```shell 75 | pnpm add -D @sveltejs/adapter-static 76 | ``` 77 | - [ ] Open the `svelte.config.js` file and edit the adapter import line: 78 | ```jsx 79 | import adapter from '@sveltejs/adapter-static'; // <-- This was changed from 'adapter-auto' to 'adapter-static' 80 | import { vitePreprocess } from '@sveltejs/kit/vite'; 81 | 82 | /** @type {import('@sveltejs/kit').Config} */ 83 | const config = { 84 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 85 | // for more information about preprocessors 86 | preprocess: vitePreprocess(), 87 | 88 | kit: { 89 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 90 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 91 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 92 | adapter: adapter() 93 | } 94 | }; 95 | 96 | export default config; 97 | ``` 98 | - [ ] Create a `+layout.ts` file inside the `/*app_name*/src/routes` directory. Insert the following 2 lines of code to disable Server Side Rendering (SSR): 99 | ```tsx 100 | export const prerender = true 101 | export const ssr = false 102 | ``` 103 |
104 | 105 | --- 106 | 107 |
108 | 109 |

110 | Step 3: Add and Configure Tauri 111 |

112 |
113 | 114 | - [ ] Install the Tauri CLI with the following command: 115 | ```shell 116 | pnpm add -D @tauri-apps/cli 117 | ``` 118 | ```shell 119 | npm install --save-dev @tauri-apps/cli 120 | ``` 121 | > Note: 122 | > For **npm** to detect Tauri correctly you need to add it to the "scripts" section in your package.json file: 123 | > ```json 124 | > "scripts": { 125 | > "tauri": "tauri" 126 | > } 127 | > ``` 128 | - [ ] Run the Tauri scaffolding utility and use the options below. Use the following command to run the utility: 129 | ```shell 130 | npm run tauri init 131 | ``` 132 | - App Name: *Any* 133 | - Window Title: *Any* 134 | - Web Asset Path: `../build` (*located relative to the `/src-tauri/tauri.conf.json` file that will be created)* 135 | - Dev Server URL: `http://localhost:5173` 136 | - Frontend dev command: `npm run dev` or `pnpm run dev` 137 | - Frontend build command: `npm run build` or `pnpm run build` 138 | 139 | The result is a folder called `src-tauri` that should contain files such as `Cargo.toml`, `tauri.conf.json`, *icons* and `src/main.rs`. Each is used for tauri to work. To learn more about how to use these files visit the [tauri docs site](https://tauri.app/v1/guides/getting-started/setup/sveltekit). 140 | 141 | - [ ] Add the tauri-apps/api JavaScript library 142 | ```shell 143 | pnpm add @tauri-apps/api 144 | ``` 145 | ```shell 146 | npm install @tauri-apps/api 147 | ``` 148 | 149 |
150 | 151 | --- 152 | 153 |
154 | 155 |

156 | Step 4: SQLite and SQLx 157 |

158 |
159 | 160 | - [ ] Open `Cargo.toml` and add the following dependencies for **SQLx** and the **async-std** runtime 161 | ```toml 162 | [dependencies] 163 | serde_json = "1.0" 164 | serde = { version = "1.0", features = ["derive"] } 165 | tauri = { version = "1.4.0", features = [] } 166 | sqlx = { version = "0.7", features = [ "runtime-async-std", "tls-native-tls", "sqlite", "macros" ] } 167 | async-std = { version = "1.7.0", features = [ "attributes" ] } 168 | ``` 169 | - [ ] Open `main.rs` and add **async_std** to `main()` function. Save changes 170 | ```rust 171 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 172 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 173 | 174 | #[async_std::main] 175 | async fn main() { 176 | tauri::Builder::default() 177 | .run(tauri::generate_context!()) 178 | .expect("error while running tauri application"); 179 | } 180 | ``` 181 | - [ ] Create `db.rs` file in `src-tauri/src` directory and add the following 182 | ```rust 183 | use sqlx::{ migrate::MigrateDatabase, Sqlite, SqlitePool }; 184 | 185 | const DB_URL: &str = "sqlite://sqlite.db"; 186 | 187 | // Check for DB, create if non existent 188 | pub async fn init() { 189 | if !Sqlite::database_exists(DB_URL).await.unwrap_or(false) { 190 | match Sqlite::create_database(DB_URL).await { 191 | Ok(_) => println!("Create db success"), 192 | Err(error) => panic!("error: {}", error), 193 | } 194 | } else { 195 | println!("Database already exists"); 196 | } 197 | 198 | create_schema().await; 199 | } 200 | 201 | // Create Schema 202 | async fn create_schema() { 203 | let pool = SqlitePool::connect(DB_URL).await.expect("unable to connect"); 204 | let sql = " 205 | PRAGMA foreign_keys = ON ; 206 | CREATE TABLE IF NOT EXISTS projects 207 | ( 208 | id INTEGER PRIMARY KEY NOT NULL, 209 | name TEXT NOT NULL 210 | ); 211 | 212 | CREATE TABLE IF NOT EXISTS tasks 213 | ( 214 | id INTEGER PRIMARY KEY NOT NULL, 215 | value TEXT NOT NULL, 216 | completed INTEGER NOT NULL, 217 | date_completed TEXT, 218 | project_id INTEGER NOT NULL, 219 | FOREIGN KEY (project_id) REFERENCES projects (id) ON UPDATE SET NULL ON DELETE SET NULL 220 | ); 221 | "; 222 | 223 | let query = sqlx::query(&sql); 224 | let result = query.execute(&pool).await.unwrap(); 225 | println!("Create Schema result: {:?}", result); 226 | pool.close().await; 227 | } 228 | ``` 229 | - [ ] Add `db.rs` to `main.rs` as a module and call the `init()` function within the `main()` 230 | ```rust 231 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 232 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 233 | 234 | mod db; 235 | 236 | #[async_std::main] 237 | async fn main() { 238 | db::init().await; 239 | 240 | tauri::Builder::default() 241 | .run(tauri::generate_context!()) 242 | .expect("error while running tauri application"); 243 | } 244 | ``` 245 | - [ ] Create `commands.rs` file in the `src-tauri/src` directory and add the following 246 | ```rust 247 | use sqlx::FromRow; 248 | use serde::{Deserialize, Serialize}; 249 | 250 | #[derive(Debug,FromRow,Deserialize,Serialize)] 251 | pub struct Task { 252 | pub id: i64, 253 | pub value: String, 254 | pub completed: i8, 255 | pub date_completed: String, 256 | pub project_id: i64, 257 | } 258 | 259 | #[tauri::command(rename_all = "snake_case")] 260 | pub async fn get_tasks() -> Result, String>{ 261 | let url = "sqlite://sqlite.db"; 262 | 263 | let pool = sqlx::sqlite::SqlitePool::connect(url).await.expect("unable to connect"); 264 | 265 | let sql = "SELECT * FROM tasks"; 266 | 267 | let query = sqlx::query_as::<_, Task>(sql); 268 | 269 | let response = query.fetch_all(&pool).await.expect("unable to list tasks"); 270 | 271 | pool.close().await; 272 | 273 | Ok(response) 274 | } 275 | ``` 276 | - [ ] Add `commands.rs` to `main.rs` as a module and add the following to `tauri::Builder::default()` 277 | ```rust 278 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 279 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 280 | 281 | mod db; 282 | mod commands; 283 | 284 | #[async_std::main] 285 | async fn main() { 286 | db::init().await; 287 | 288 | tauri::Builder::default() 289 | .invoke_handler(tauri::generate_handler![ 290 | commands::get_tasks, 291 | ]) 292 | .run(tauri::generate_context!()) 293 | .expect("error while running tauri application"); 294 | } 295 | ``` 296 | - [ ] Create a set of records in each table to test the functionality of the application. There are a number of different ways to achieve this, I chose to create a function that will perform this operation as part of the `db::init()` fn, and by commenting it out or uncommenting it when necessary *(This fn would need to be deleted before building and deploying)* 297 | ```rust 298 | // Check for DB, create if non existent 299 | pub async fn init() { 300 | if !Sqlite::database_exists(DB_URL).await.unwrap_or(false) { 301 | match Sqlite::create_database(DB_URL).await { 302 | Ok(_) => println!("Create db success"), 303 | Err(error) => panic!("error: {}", error), 304 | } 305 | } else { 306 | println!("Database already exists"); 307 | } 308 | 309 | create_schema().await; 310 | 311 | // Uncomment the fn below and run to make some records for testing 312 | insert_dev_records().await; 313 | } 314 | 315 | // Create schema 316 | // ... 317 | 318 | // Create some test records in each table 319 | async fn insert_dev_records() { 320 | let pool = SqlitePool::connect(DB_URL).await.expect("unable to connect"); 321 | let sql = " 322 | INSERT INTO projects (name) 323 | VALUES ('Awesome Current Product'), ('Top Secret Product'), ('Super Top Secret Product'); 324 | 325 | INSERT INTO tasks (value, completed, date_completed, project_id) 326 | VALUES ('Design the UI', 0, NULL, 3), 327 | ('Design DB Schema', 0, NULL, 3), 328 | ('Build prototype app', 0, NULL, 3), 329 | ('Design a cool logo', 1, DATE('2023-04-22'), 3), 330 | ('Refactor component lib', 0, NULL, 2), 331 | ('Add input sanitization to ipc', 0, NULL, 2), 332 | ('Security audit testing for v1.5', 0, NULL, 1), 333 | ('Add Dark Mode', 1, DATE('2023-04-20'), 1), 334 | ('Fix UI glitch', 1, DATE('2023-04-20'), 1); 335 | "; 336 | 337 | let query = sqlx::query(&sql); 338 | let result = query.execute(&pool).await.unwrap(); 339 | println!("Create Records result: {:?}", result); 340 | pool.close().await; 341 | } 342 | ``` 343 |
344 | 345 | --- 346 | 347 |
348 |

Step 5: Build Frontend

349 | 350 | - [ ] Within `/src/lib` folder, create 2 new files called `table.svelte` and `index.ts` with the following contents 351 | ```tsx 352 | 377 | 378 |
379 |

Tasks

380 | 381 | 382 | 383 | 384 | {#each fields as field} 385 | 386 | {/each} 387 | 388 | 389 | 390 | 391 | 392 | 393 | {#each records as record} 394 | 395 | 396 | {#each Object.values(record) as value} 397 | 398 | {/each} 399 | 400 | 401 | {/each} 402 | 403 | 404 |
{field}
{value}
405 |
406 | ``` 407 | ```tsx 408 | // place files you want to import through the `$lib` alias in this folder. 409 | export { default } from "./table.svelte"; 410 | ``` 411 |
412 |
413 | Optional Table styles 414 | 415 | ```tsx 416 | 452 | ``` 453 | 454 |
455 |
456 | - [ ] Within `src/routes`, open the `+page.svelte` file and change it’s contents to the following 457 | ```tsx 458 | 462 | 463 |

My Tauri + SvelteKit + SQLite App

464 | 465 | 466 | ``` 467 | 468 | 469 | --- 470 | 471 |
472 | 473 |

474 | Step 6: Test the App 475 |

476 |
477 | 478 | - [ ] Make sure everything is saved then run the following command in the terminal 479 | ```shell 480 | pnpm tauri dev 481 | ``` 482 | ![tauri-sveltekit-sqlx_screenshot](https://github.com/Lmedmo/Tauri-SvelteKit-SQLite/assets/102483463/8a67c736-c59c-4fb1-bc3c-d11e540aef82) 483 | 484 | > **🎉 Congrats!** 485 | > You have built a very basic full-stack desktop app with an embedded database. There’s a lot of potential with how this template can be applied and there are plenty of concepts, best practices, and steps that you should be aware of that are not discussed/included in this basic example, so do your own research regarding the technologies used here, experiment with new things, and most importantly have fun — coding is cool😎 486 | > PS: If you like this or have suggestions let me know!! I’m still pretty new to Rust and backend web development, and I’m always looking for ways to improve my skills as a developer (Rust, Svelte, SQLite/DBs, etc.). Furthermore, I like knowing when I do a good job so that I can flex or if my code is trash so I can fix it and then flex (Just kidding, maybe). 487 | 488 |
489 | -------------------------------------------------------------------------------- /src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "app" 3 | version = "0.1.0" 4 | description = "A Tauri App" 5 | authors = ["you"] 6 | license = "" 7 | repository = "" 8 | default-run = "app" 9 | edition = "2021" 10 | rust-version = "1.60" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [build-dependencies] 15 | tauri-build = { version = "1.4.0", features = [] } 16 | 17 | [dependencies] 18 | serde_json = "1.0" 19 | serde = { version = "1.0", features = ["derive"] } 20 | tauri = { version = "1.4.0", features = [] } 21 | sqlx = { version = "0.7", features = [ "runtime-async-std", "tls-native-tls", "sqlite", "macros" ] } 22 | async-std = { version = "1.7.0", features = [ "attributes" ] } 23 | 24 | [features] 25 | # this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled. 26 | # If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes. 27 | # DO NOT REMOVE!! 28 | custom-protocol = [ "tauri/custom-protocol" ] 29 | -------------------------------------------------------------------------------- /src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /src-tauri/sqlite.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/src-tauri/sqlite.db -------------------------------------------------------------------------------- /src-tauri/src/commands.rs: -------------------------------------------------------------------------------- 1 | use sqlx::FromRow; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Debug,FromRow,Deserialize,Serialize)] 5 | pub struct Task { 6 | pub id: i64, 7 | pub value: String, 8 | pub completed: i8, 9 | pub date_completed: String, 10 | pub project_id: i64, 11 | } 12 | 13 | #[tauri::command(rename_all = "snake_case")] 14 | pub async fn get_tasks() -> Result, String>{ 15 | let url = "sqlite://sqlite.db"; 16 | 17 | let pool = sqlx::sqlite::SqlitePool::connect(url).await.expect("unable to connect"); 18 | 19 | let sql = "SELECT * FROM tasks"; 20 | 21 | let query = sqlx::query_as::<_, Task>(sql); 22 | 23 | let response = query.fetch_all(&pool).await.expect("unable to list tasks"); 24 | 25 | pool.close().await; 26 | 27 | Ok(response) 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src-tauri/src/db.rs: -------------------------------------------------------------------------------- 1 | use sqlx::{ migrate::MigrateDatabase, Sqlite, SqlitePool }; 2 | 3 | const DB_URL: &str = "sqlite://sqlite.db"; 4 | 5 | // Check for DB, create if non existent 6 | pub async fn init() { 7 | if !Sqlite::database_exists(DB_URL).await.unwrap_or(false) { 8 | match Sqlite::create_database(DB_URL).await { 9 | Ok(_) => println!("Create db success"), 10 | Err(error) => panic!("error: {}", error), 11 | } 12 | } else { 13 | println!("Database already exists"); 14 | } 15 | 16 | create_schema().await; 17 | 18 | // Uncomment the fn below and run to make some records for testing 19 | // insert_dev_records().await; 20 | } 21 | 22 | // Create Schema 23 | async fn create_schema() { 24 | let pool = SqlitePool::connect(DB_URL).await.expect("unable to connect"); 25 | let sql = " 26 | PRAGMA foreign_keys = ON ; 27 | CREATE TABLE IF NOT EXISTS projects 28 | ( 29 | id INTEGER PRIMARY KEY NOT NULL, 30 | name TEXT NOT NULL 31 | ); 32 | 33 | CREATE TABLE IF NOT EXISTS tasks 34 | ( 35 | id INTEGER PRIMARY KEY NOT NULL, 36 | value TEXT NOT NULL, 37 | completed INTEGER NOT NULL, 38 | date_completed TEXT, 39 | project_id INTEGER NOT NULL, 40 | FOREIGN KEY (project_id) REFERENCES projects (id) ON UPDATE SET NULL ON DELETE SET NULL 41 | ); 42 | "; 43 | 44 | let query = sqlx::query(&sql); 45 | let result = query.execute(&pool).await.unwrap(); 46 | println!("Create Schema result: {:?}", result); 47 | pool.close().await; 48 | } 49 | 50 | // Create some test records in each table 51 | #[allow(dead_code)] 52 | async fn insert_dev_records() { 53 | let pool = SqlitePool::connect(DB_URL).await.expect("unable to connect"); 54 | let sql = " 55 | INSERT INTO projects (name) 56 | VALUES ('Awesome Current Product'), ('Top Secret Product'), ('Super Top Secret Product'); 57 | 58 | INSERT INTO tasks (value, completed, date_completed, project_id) 59 | VALUES ('Design the UI', 0, NULL, 3), 60 | ('Design DB Schema', 0, NULL, 3), 61 | ('Build prototype app', 0, NULL, 3), 62 | ('Design a cool logo', 1, DATE('2023-04-22'), 3), 63 | ('Refactor component lib', 0, NULL, 2), 64 | ('Add input sanitization to ipc', 0, NULL, 2), 65 | ('Security audit testing for v1.5', 0, NULL, 1), 66 | ('Add Dark Mode', 1, DATE('2023-04-20'), 1), 67 | ('Fix UI glitch', 1, DATE('2023-04-20'), 1); 68 | "; 69 | 70 | let query = sqlx::query(&sql); 71 | let result = query.execute(&pool).await.unwrap(); 72 | println!("Create Records result: {:?}", result); 73 | pool.close().await; 74 | } -------------------------------------------------------------------------------- /src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | mod db; 5 | mod commands; 6 | 7 | #[async_std::main] 8 | async fn main() { 9 | db::init().await; 10 | 11 | tauri::Builder::default() 12 | .invoke_handler(tauri::generate_handler![ 13 | commands::get_tasks 14 | ]) 15 | .run(tauri::generate_context!()) 16 | .expect("error while running tauri application"); 17 | } 18 | -------------------------------------------------------------------------------- /src-tauri/tauri.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../node_modules/@tauri-apps/cli/schema.json", 3 | "build": { 4 | "beforeBuildCommand": "pnpm run build", 5 | "beforeDevCommand": "pnpm run dev", 6 | "devPath": "http://localhost:5173", 7 | "distDir": "../build" 8 | }, 9 | "package": { 10 | "productName": "tauri-sveltekit-sqlite", 11 | "version": "0.1.0" 12 | }, 13 | "tauri": { 14 | "allowlist": { 15 | "all": false 16 | }, 17 | "bundle": { 18 | "active": true, 19 | "category": "DeveloperTool", 20 | "copyright": "", 21 | "deb": { 22 | "depends": [] 23 | }, 24 | "externalBin": [], 25 | "icon": [ 26 | "icons/32x32.png", 27 | "icons/128x128.png", 28 | "icons/128x128@2x.png", 29 | "icons/icon.icns", 30 | "icons/icon.ico" 31 | ], 32 | "identifier": "com.tauri.dev", 33 | "longDescription": "", 34 | "macOS": { 35 | "entitlements": null, 36 | "exceptionDomain": "", 37 | "frameworks": [], 38 | "providerShortName": null, 39 | "signingIdentity": null 40 | }, 41 | "resources": [], 42 | "shortDescription": "", 43 | "targets": "all", 44 | "windows": { 45 | "certificateThumbprint": null, 46 | "digestAlgorithm": "sha256", 47 | "timestampUrl": "" 48 | } 49 | }, 50 | "security": { 51 | "csp": null 52 | }, 53 | "updater": { 54 | "active": false 55 | }, 56 | "windows": [ 57 | { 58 | "fullscreen": false, 59 | "height": 600, 60 | "resizable": true, 61 | "title": "Tauri-Notes", 62 | "width": 800 63 | } 64 | ] 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | 14 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | export { default } from "./table.svelte"; -------------------------------------------------------------------------------- /src/lib/table.svelte: -------------------------------------------------------------------------------- 1 | 26 | 27 |
28 |

Tasks

29 |
30 | 31 | 32 | 33 | {#each fields as field} 34 | 35 | {/each} 36 | 37 | 38 | 39 | 40 | 41 | 42 | {#each records as record} 43 | 44 | 45 | {#each Object.values(record) as value} 46 | 47 | {/each} 48 | 49 | 50 | {/each} 51 | 52 | 53 |
{field}
{value}
54 | 55 | 56 | -------------------------------------------------------------------------------- /src/routes/+layout.ts: -------------------------------------------------------------------------------- 1 | export const prerender = true 2 | export const ssr = false -------------------------------------------------------------------------------- /src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |

My Tauri + SvelteKit + SQLite App

7 | 8 | 9 | -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lmedmo/Tauri-SvelteKit-SQLite/6607eb7132879afcc6038f35717374a542cbb8d9/static/favicon.png -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static'; 2 | import { vitePreprocess } from '@sveltejs/kit/vite'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "ignoreDeprecations": "5.0" 13 | } 14 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 15 | // 16 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 17 | // from the referenced tsconfig.json - TypeScript does not merge them in 18 | } 19 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | --------------------------------------------------------------------------------