How to build a basic to do crud app using vue 3 & nodejs & expressjs server & sqlite & vite ? (frontend & backend)
Let’s start by making a simple To-Do app using Vue 3, Node.js, Express.js, SQLite, and Vite.
This guide will help you build both the part of the app you see (frontend) and the part that works behind the scenes (backend).
You’ll learn how to create, view, update, and delete tasks, making a complete to-do list application.
Frontend Technologies:
Web Framework Library
- Vue3
Navigation Library
- Router
Development Server & Build Tool
- Vite
Backend Technologies:
Server-side JavaScript Runtime Environment
- NodeJS
Web Application Framework for building NodeJS APIs
- ExpressJS
Database Technologies:
The Lightweight Database
- SQLite
So now let’s start with the following configuration steps below.
Pre-Configuration:
1. Download & Install NodeJS
https://nodejs.org/en
2. Download & Install VueJS
https://vuejs.org/
Create The Project
1. Create A Project Folder
- i.e. : Create a folder that named as “ TODOLIST “ in your desktop
- The folder structure will be like this below.
TODOLIST (Project Folder)
├── frontend
│ ├── node_modules
│ ├── public
│ ├── src
│ │ ├── assets
│ │ ├── components
│ │ │ ├── HeaderComponent.vue
│ │ │ ├── TheWelcomeComponent.vue
│ │ │ └── TodoComponent.vue
│ │ ├── router
│ │ │ └── index.js
│ │ ├── views
│ │ │ ├── TheWelcomeView.vue
│ │ │ └── TodoView.vue
│ │ ├── app.vue
│ │ └── main.js
│ ├── index.html
│ ├── jsconfig.json
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ └── vite.config.js
├── backend
│ ├── node_modules
│ ├── database.sqlite
│ ├── package.json
│ ├── server.js
│ └── test.http
Create Backend API
Let’s start with creating a backend structure and an API to provide data to this app and make this app dynamic.
TODOLIST (Project Folder)
├── backend
│ ├── node_modules
│ ├── database.sqlite
│ ├── package.json
│ ├── server.js
│ └── test.http
1. Create A Backend API project folder
- Create a folder that named as i.e. “backend” in TODOLIST project folder.
2. Open this folder in VSCode
- Open new terminal in VS Code from the top bar with “Terminal”
- Now you should be in “backend” folder. (check it if you are not in. If not go in it with the command cd desktop > cd TODOLIST > cd backend)
3. Initiate NodeJS
- Terminal command: “ npm init ” command (then press enter and skip all)
4. Install Dependencies:
Install “ExpressJS” packages. ExpressJS
- Still we are in VSCode Terminal and in the-app folder path.
- Run this command to install ExpressJS. “ npm install express — save “
Install “Sequelize” packages.
- Run this command to install SequelizeJS.
- Terminal Command: “ npm install sequelize — save ”
Install “Sqlite3” packages.
- Run this command to install Sqlite3.
- Terminal Command: “ npm install sqlite3 — save ”
5. Create “server.js” file in “TODOLIST” folder
Server.js — Add the following code in file.
* setupDB() function is used for retrieving data and creating data in DB
* startServer() function is used for running the API and activate its methods. This means via the paths that declared in this function you can send requests to retrieve and create data.
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize ({
dialect: 'sqlite',
storage: './database.sqlite'
})
var db = {}
// THIS FUNCTION WILL CREATE DUMMY DATA IN DATABASE TABLE
async function setupDB() {
try {
db.Task = sequelize.define('Task', {
text: {
type: DataTypes.STRING,
allowNull: false
},
});
await sequelize.sync({ force: true });
await db.Task.create({ text: "Item-1-MertKadirGursoy"});
await db.Task.create({ text: "Item-2"});
await db.Task.create({ text: "Item-3"});
} catch (error) {
console.error(error);
}
}
// CREATE APIs URL ENDPOINTS TO CREATE AND DELETE TO DO ITEMS
async function startServer() {
try {
await setupDB()
const port = 3001
const express = require('express')
const app = express()
app.use(express.json())
app.get('/', (req, res) => {
res.send('hello world')
})
// GET METHOD API URL | RETRIEVE ITEMS
app.get('/api/tasks', (req, res) => {
// return all taskls
db.Task.findAll().then(tasks => {
res.json(tasks)
})
})
// POST METHOD API URL | CREATE ITEM
app.post('/api/tasks', (req, res) => {
// create a task
db.Task.create(req.body).then( t => {
res.json(t)
})
})
// DELETE METHOD API URL | DELETE ITEM
app.delete('/api/tasks/:id', (req, res) => {
// delete a task
db.Task.destroy({
where: {
id: req.params.id
}
}).then(() => {
res.sendStatus(204);
}).catch((error) => {
console.error(error);
res.sendStatus(500); // Internal Server Error
});
});
app.listen(port, () => {
console.log(`App listening on port ${port}`)
})
} catch (error) {
console.error(error);
}
}
startServer()
6. Run Server (API)
- i.e. : desktop > TODOLIST > backend
- Run This Terminal Command: “node server”
7. Check This API in Browser
- Open this url in browser.
* “Localhost:3001”
* “Localhost:3001/api/tasks”
Bonus: View API Requests & Responses in VSCode
- Install Rest Client Extension in VSCode
- Create “test.http” file.
- Add API url in it. “GET Localhost:3001/api/tasks”
- You can view the response of it.
Bonus: View DB Tables in VSCode
- Install this extension “Sqlite Viewer” in VSCode
Create Frontend Vue 3
├── frontend
│ ├── node_modules
│ ├── public
│ ├── src
│ │ ├── assets
│ │ ├── components
│ │ │ ├── HeaderComponent.vue
│ │ │ ├── TheWelcomeComponent.vue
│ │ │ └── TodoComponent.vue
│ │ ├── router
│ │ │ └── index.js
│ │ ├── views
│ │ │ ├── TheWelcomeView.vue
│ │ │ └── TodoView.vue
│ │ ├── app.vue
│ │ └── main.js
│ ├── index.html
│ ├── jsconfig.json
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ └── vite.config.js
1. Create A Frontend folder with vue
- i.e. : desktop > TODOLIST
- Open VS Code
* Open TODOLIST project folder in VSCODE
* Open New VSCode Terminal
* Run this command to create “frontend” folder in project folder
* Terminal Command: “ npm init vue@latest “
* It will ask question write y and then enter
* It will ask project name write “ frontend “ and then enter
* Then skip others things
2. Go in frontend folder
- Terminal Command: cd frontend
3. Install npm in frontend folder for vue project
- Terminal Command: “ npm install “
4. Create required vue “ components “ first
- First, we need to create the following components to create pages(views).
- These components will be used in views vue files (pages)
│ │ ├── components
│ │ │ ├── HeaderComponent.vue
<template>
<h1> The Mert's To Do App</h1>
</template>
<style>
h1 {
text-align: center;
margin-top: 45px;
margin-bottom: 45px;
color: white;
width: 100%;
}
</style>
│ │ │ ├── TheWelcomeComponent.vue
<template>
<div id='theContainer'>
<h1> Welcome</h1>
<h2> Mert's To Do App </h2>
<router-link to="/todo-app">
<button style="margin: 23px; width: 24%;">View</button>
</router-link>
</div>
</template>
<style>
body {
background: linear-gradient(135deg, #153575, #4e085f);
}
#theContainer {
text-align: center;
margin: 23px;
padding: 23px;
}
h1 {
text-align: center;
margin-top: 45px;
margin-bottom: 45px;
color: white;
width: 100%;
}
h2 {
text-align: center;
margin-bottom: 24px;
font-weight: lighter;
font-family: system-ui;
color: white;
}
button {
width: 50%;
border: 1px solid white !important;
padding: 10px;
background-color: transparent;
color: white;
border: none;
padding: 12px;
border-radius: 12px;
cursor: pointer;
}
</style>
│ │ │ └── TodoComponent.vue
<script setup>
import { onMounted, ref } from 'vue'
let id = 0
const newTodo = ref('')
const todos = ref([])
// Add Item via FETCH API
async function createTask(text) {
try {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: text })
};
const response = await fetch('/api/tasks', requestOptions)
return await response.json();
} catch (error) {
console.error(error);
}
}
// FETCH API üzerinden öğe silme
async function deleteTask(id) {
try {
const requestOptions = {
method: "DELETE",
};
const response = await fetch(`/api/tasks/${id}`, requestOptions);
if (response.ok) {
// Eğer yanıt durumu OK (204) ise, yerel todos'u güncelle
todos.value = todos.value.filter((t) => t.id !== id);
} else {
console.error("Görev silinirken hata oluştu:", response.statusText);
}
} catch (error) {
console.error(error);
}
}
async function addTodo() {
const newTask = await createTask(newTodo.value)
todos.value.push(newTask)
newTodo.value = ''
}
async function removeTodo(todo) {
await deleteTask(todo.id)
todos.value = todos.value.filter((t) => t.id !== todo.id)
}
onMounted(async () => {
await fetchTasks();
})
async function fetchTasks() {
try {
const response = await fetch('/api/tasks');
todos.value = await response.json();
} catch (error) {
console.error(error);
}
}
</script>
<template>
<div id="containerr" style="text-align: center; display: inline-block; width: 49%;">
<form @submit.prevent="addTodo">
<input autofocus placeholder="add your texthere" id='inptBtn' v-model="newTodo">
<button id="addBtn">Add Todo</button>
</form>
<ul>
<li v-for="item in todos" :key="item.id">
{{ item.text }}
<button style='height: 39px; width: 39px; border-radius: 23px;' @click="removeTodo(item)">X</button>
</li>
</ul>
<router-link to="/">
<button style="width: 157px;">Back to Home</button>
</router-link>
</div>
</template>
<style scoped>
/* Sayfayı ortala */
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
/* Formu ortala ve oval çerçeve ekle */
form {
display: flex;
padding-left: 12px;
padding-right: 12px;
margin-bottom: 23px;
flex-direction: column;
align-items: center;
border: 2px solid #ccc;
border-radius: 34px;
padding-top: 34px;
padding-bottom: 34px;
background-color: transparent;
}
input {
margin-bottom: 10px;
padding: 10px;
border-radius: 5px;
color: black; /* Metin rengini siyah olarak ayarla */
}
#inptBtn {
border-radius: 23px;
height: 59px;
margin-bottom: 5%;
width: 89%;
background: transparent;
color: white;
}
#addBtn {
width: 50%;
border: 1px solid white !important;
}
button {
padding: 10px;
background-color: transparent;
color: white;
border: none;
padding: 12px;
border-radius: 12px;
cursor: pointer;
}
button:hover {
background-color: #aaaaaa23;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ffffff4a;
border-radius: 23px;
background-color: #fff;
color: rgb(255, 255, 255); /* Metin rengini siyah olarak ayarla */
background-color: transparent;
}
</style>
5. Create required vue “ views “
- The created components above will be used in these views vue files.
│ │ ├── views
│ │ │ ├── TheWelcomeView.vue
<script setup>
// Önce TheWelcomeComponent TODOLIST > frontend > src > components klasöründen çekilir.
// Sonra aşağıda <TheWelcomeComponent /> olarak <template> içinde kullanılır.
import TheWelcomeComponent from '../components/TheWelcomeComponent.vue'
</script>
<template>
<main>
<TheWelcomeComponent />
</main>
</template>
│ │ │ └── TodoView.vue
<script setup>
// Önce TodoComponent TODOLIST > frontend > src > components klasöründen çekilir.
// Sonra aşağıda <TodoComponent /> olarak <template> içinde kullanılır.
import TodoComponent from '../components/TodoComponent.vue'
</script>
<template>
<main>
<TodoComponent />
</main>
</template>
6. Create required vue “ router structure & index.js file“
- Run this command to install router dependencies in frontend folder. TODOLIST > frontend | “ npm install vue-router “
- Create “ router “ folder in TODOLIST > frontend > src
├── frontend
│ ├── node_modules
│ ├── public
│ ├── src
│ │ ├── assets
│ │ ├── components
│ │ ├── router
- Create index.js in router folder
├── frontend
│ ├── node_modules
│ ├── public
│ ├── src
│ │ ├── assets
│ │ ├── components
│ │ ├── router
│ │ │ └── index.js
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import TheWelcomeView from '@/views/TheWelcomeView.vue'
import TodoView from '@/views/TodoView.vue'
const routes = [
{ path: '/', component: TheWelcomeView },
{ path: '/todo-app', component: TodoView }
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default routerp>
// Önce TodoComponent TODO
7. Create required vue “ app.vue file“ to display views (pages) via router structure in browser.
├── frontend
│ ├── node_modules
│ ├── public
│ ├── src
│ │ ├── assets
│ │ ├── components
│ │ ├── router
│ │ │ └── index.js
│ │ ├── views
│ │ ├── app.vue
│ │ └── main.js
<!-- src/App.vue -->
<script setup>
// <router-view></router-view> ile yukarıda router'da kurulan yapı
import HeaderComponent from './components/HeaderComponent.vue'
</script>
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<style>
#app {
display: block;
width: 100%;
margin: 0 auto;
margin-bottom: 23px;
padding: 0rem;
font-weight: normal;
text-align: center;
}
header {
text-align: center;
color: white;
}
body {
background: linear-gradient(135deg, var(--colorPrimary), #4e085f);
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
</style>
8. Create required vue “ main.js file“ to create and build vue app.
├── frontend
│ ├── node_modules
│ ├── public
│ ├── src
│ │ ├── assets
│ │ ├── components
│ │ ├── router
│ │ │ └── index.js
│ │ ├── views
│ │ ├── app.vue
│ │ └── main.js
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
9. Install Vite Dev Server & Run
- Terminal Command: “ npm run dev “
- Note: So that inside of frontend folder it will automatically create packages.json dependecies.
10. Check this in browser “http://localhost:5173/”
1. First, build the backend API.
— Navigate to the “TODOLIST > backend” directory in your terminal.
— Run the command: “ node server ”
2. Next, build the frontend using Vite.
— Navigate to the “TODOLIST > frontend” directory in your terminal.
— Run the command: “ npm run dev ”