Para iniciar un proyecto de svelte, ejecutamos:
npx degit sveltejs/template ArmeriaFrontEnd
├── package.json
├── public
│ ├── favicon.png
│ ├── global.css
│ └── index.html
├── README.md
├── rollup.config.js
└── src
├── App.svelte
└── main.js
El archivo package.json es el archivo de gestión de proyecto y dependencias. En él. podremos editar el nombre del autor, la versión, el tipo de licencia, etc.
La carpeta public contiene el frontend en forma de contenido estático, el cual deberemos subir a nuestro servidor de producción una vez finalizado el proyecto.
El archivo README.md editado a nuestro gusto.
El archivo rollup.config.js contiene la configuración del empaquetador, que en este caso es Rollup. Otros frameworks utilizan otros empaquetadores como Webpack o Parcel. No debemos borrar este archivo. Tampoco lo editaremos, por ahora.
Finalmente, la carpeta src va a contener nuestro código y todos los componentes web que vayamos creando. Cada vez que realicemos un cambio en los archivos de dicha carpeta, rollup volverá a compilar y pondrá el resultado en public/build/bundle.css y public/build/bundle.js.
El archivo public/index.html tiene enlaces a los anteriores.
Los archivos que crearemos y modificaremos seran los siguientes:
En scr/:
Modificados:
* App.svelte
* main.js
Creados:
* Arma.svelte
* Armeria.svelte
* Boton.svelte
* Buscar.svelte
* Cliente.svelte
* Clientes.svelte
* Contenido.svelte
* Footer.svelte
* Inicio.svelte
* Nav.svelte
* store.js
<script>
import { setContext } from "svelte";
import Nav from "./Nav.svelte";
import Contenido from "./Contenido.svelte";
import { Router } from "svelte-routing";
import Footer from "./Footer.svelte";
const URL = {
armas: "https://armeria.fly.dev/api/armas/",
clientes: "https://armeria.fly.dev/api/clientes/",
};
setContext("URL", URL);
</script>
<Router>
<nav />
<Contenido />
<footer />
</Router>
<style>
:global(body) {
margin: 0 auto;
padding: 0;
background-color: black;
}
</style>
URL esta constante es donde escribiremos las urls a nuestro
BACKEND.
import App from "./App.svelte";
const app = new App({
target: document.body,
props: {
name: "armeria",
},
});
export default app;
En este archivo generamos el modelo de dato de Arma.
StringString<script>
export let arma = {
nombre: "",
tipo: "",
};
</script>
<input
type="text"
class="bg-transparent text-white"
placeholder="Nombre"
bind:value="{arma.nombre}"
/>
<input
type="text"
class="bg-transparent text-white"
placeholder="Tipo"
bind:value="{arma.tipo}"
/>
<slot />
<style></style>
En Armeria.svelte hacemos la llamada asincrona para obtener las armas de la base de datos y almacenarlos en un variable, la cual mostraremos con un for each.
Importamos los componentes de Burcar, Arma, Boton y store.js.
<script>
import { getContext } from "svelte";
import { data } from "./store.js";
import { onMount } from "svelte";
import Buscar from "./Buscar.svelte";
import Arma from "./Arma.svelte";
import Boton from "./Boton.svelte";
const URL = getContext("URL");
let armaInsertada = {};
let datosFiltrados = [];
let patron;
let getArmas = async () => {
const response = await fetch(URL.armas);
$data = await response.json();
};
onMount(getArmas);
$: datosFiltrados = $data.filter((arma) =>
RegExp(patron, "i").test(arma.nombre)
);
</script>
<Buscar bind:busqueda="{patron}" />
<h1 class="text-white">Esta en la Armeria</h1>
<Arma bind:arma="{armaInsertada}">
<Boton tipo="insertar" documento="{armaInsertada}" coleccion="armas" />
</Arma>
<hr />
<div class="container">
<section class=" row row-cols-1 row-cols-md-3 row-col-lg-4 g-2">
{#each datosFiltrados as arma}
<div class="col">
<div class="card text-white bg-secondary mb-3 border-info ">
<Arma bind:arma>
<br />
<div class="container-fluid " role="group">
<Boton tipo="modificar" documento="{arma}" coleccion="armas" />
<Boton tipo="eliminar" documento="{arma}" coleccion="armas" />
</div>
</Arma>
</div>
</div>
{/each}
</section>
</div>
<hr />
<style></style>
Es un componente donde hacemos parte los metodos del CRUD.
Y importa el archivo store.js que usamos como almacen de los datos de la llamada de lectura.
<script>
import { onMount } from "svelte";
import { getContext } from "svelte";
import { data } from "./store";
export let tipo = "insertar";
export let coleccion = "arma";
export let documento = {};
let url;
let URL = getContext("URL");
let handler = () => {};
function insertar() {
let opciones = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(documento),
};
console.log(documento);
fetch(url, opciones)
.then((res) => res.json())
.then((dato) => ($data = [...$data, dato]))
.catch((error) => console.log(error));
}
function modificar() {
let opciones = {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(documento),
};
fetch(url + documento._id, opciones)
.then((res) => res.json())
.then((dato) => console.log(dato))
.catch((error) => console.log(error));
}
function eliminar() {
let opciones = {
method: "DELETE",
};
fetch(url + documento._id, opciones)
.then((res) => res.json())
.then((dato) => ($data = $data.filter((doc) => doc._id != dato._id)))
.catch((error) => console.log(error));
}
function setUp() {
switch (tipo) {
case "insertar":
handler = insertar;
break;
case "modificar":
handler = modificar;
break;
case "eliminar":
handler = eliminar;
break;
default:
break;
}
switch (coleccion) {
case "armas":
url = URL.armas;
break;
case "clientes":
url = URL.clientes;
break;
default:
}
}
onMount(setUp);
</script>
<input
type="button"
class="bg-transparent text-white"
value="{tipo.toLocaleUpperCase()}"
on:click="{handler}"
/>
Este componente hace un input tipo="search" que grindea su valor a la variable busqueda.
<script>
export let busqueda = "";
</script>
<input type="search" id="Buscador" bind:value="{busqueda}" />
En este archivo generamos el modelo de dato de Cliente.
StringStringNumber<script>
export let cliente = {
nombre: "",
apellidos: "",
num_armas: 0,
};
</script>
<input
type="text"
class="bg-transparent text-white"
placeholder="Nombre"
bind:value="{cliente.nombre}"
/>
<input
type="text"
class="bg-transparent text-white"
placeholder="Apellidos"
bind:value="{cliente.apellidos}"
/>
<input
type="number"
class="bg-transparent text-white"
placeholder="Número de Armas"
bind:value="{cliente.num_armas}"
/>
<slot />
<style></style>
En CLiente.svelte hacemos la llamada asincrona para obtener las armas de la base de datos y almacenarlos en un variable, la cual mostraremos con un for each.
Importamos los componentes de Burcar, Cliente, Boton y store.js.
<script>
import { getContext } from "svelte";
import { data } from "./store.js";
import { onMount } from "svelte";
import Buscar from "./Buscar.svelte";
import Cliente from "./Cliente.svelte";
import Boton from "./Boton.svelte";
const URL = getContext("URL");
let clietInsertar = {};
let datosFiltrados = [];
let patron;
let getClientes = async () => {
const response = await fetch(URL.clientes);
$data = await response.json();
};
onMount(getClientes);
$: datosFiltrados = $data.filter((cliente) =>
RegExp(patron, "i").test(cliente.nombre)
);
</script>
<Buscar bind:busqueda="{patron}" />
<h1 class="text-white">Esta en los Clientes.</h1>
<Cliente bind:cliente="{clietInsertar}">
<Boton tipo="insertar" documento="{clietInsertar}" coleccion="clientes" />
</Cliente>
<hr />
<div class="container">
<section class=" row row-cols-1 row-cols-md-3 row-col-lg-4 g-1">
{#each datosFiltrados as cliente}
<div class="col">
<div class="card text-white bg-secondary mb-3 border-info ">
<Cliente bind:cliente>
<br />
<Boton tipo="modificar" documento="{cliente}" coleccion="clientes" />
<Boton tipo="eliminar" documento="{cliente}" coleccion="clientes" />
</Cliente>
</div>
</div>
{/each}
</section>
</div>
<hr />
<style></style>
Contenido.svelte tiene el enrutador para ir a los contenidos de Inicio-Armeria-Clientes.
<script>
import { Route } from "svelte-routing";
import Armeria from "./Armeria.svelte";
import Clientes from "./Clientes.svelte";
import Inicio from "./Inicio.svelte";
</script>
<main>
<Route path="/" component="{Inicio}" />
<Route path="/armas" component="{Armeria}" />
<Route path="/clientes" component="{Clientes}" />
</main>
<style>
main {
text-align: center;
}
</style>
Es un footer general para la pagina que contiene mis redes.
<script>
import { Link } from "svelte-routing";
</script>
<footer>
<section class="d-flex justify-content-center">
<p class="text-white">Román Solanas Barrera</p>
<a
href="https://github.com/RomanCito-969"
target="_blank"
rel="noopener noreferrer"
class="link-light mx-3"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-github"
viewBox="0 0 16 16"
>
<path
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"
/>
</svg>
</a>
<a
href="https://www.linkedin.com/in/romansolanasbarrera969/"
target="_blank"
rel="noopener noreferrer"
class="link-light mx-3"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-linkedin"
viewBox="0 0 16 16"
>
<path
d="M0 1.146C0 .513.526 0 1.175 0h13.65C15.474 0 16 .513 16 1.146v13.708c0 .633-.526 1.146-1.175 1.146H1.175C.526 16 0 15.487 0 14.854V1.146zm4.943 12.248V6.169H2.542v7.225h2.401zm-1.2-8.212c.837 0 1.358-.554 1.358-1.248-.015-.709-.52-1.248-1.342-1.248-.822 0-1.359.54-1.359 1.248 0 .694.521 1.248 1.327 1.248h.016zm4.908 8.212V9.359c0-.216.016-.432.08-.586.173-.431.568-.878 1.232-.878.869 0 1.216.662 1.216 1.634v3.865h2.401V9.25c0-2.22-1.184-3.252-2.764-3.252-1.274 0-1.845.7-2.165 1.193v.025h-.016a5.54 5.54 0 0 1 .016-.025V6.169h-2.4c.03.678 0 7.225 0 7.225h2.4z"
/></svg
></a>
</section>
</footer>
Contiene la pagina de inicio de la aplicación creada.
<script></script>
<main>
<section class="text-aling-center my-5 py-5">
<h1 class="text-secondary">Armeria</h1>
<h1 class="text-secondary">FrontEnd</h1>
</section>
</main>
<style></style>
Es la Barra de navegación de la pagina. La cual contiene los Link de navegación para ir de pagina a pagina.
<script>
import { Link } from "svelte-routing";
</script>
<header>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<Link class="navbar-brand" to="/">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-house"
viewBox="0 0 16 16"
>
<path
d="M8.707 1.5a1 1 0 0 0-1.414 0L.646 8.146a.5.5 0 0 0 .708.708L2 8.207V13.5A1.5 1.5 0 0 0 3.5 15h9a1.5 1.5 0 0 0 1.5-1.5V8.207l.646.647a.5.5 0 0 0 .708-.708L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.707 1.5ZM13 7.207V13.5a.5.5 0 0 1-.5.5h-9a.5.5 0 0 1-.5-.5V7.207l5-5 5 5Z"
/>
</svg>
</Link>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNav"
aria-controls="navbarNav"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon" />
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<Link class="nav-link active" to="/">Inicio</Link>
</li>
<li class="nav-item">
<Link class="nav-link" to="/armas">Armeria</Link>
</li>
<li class="nav-item">
<Link class="nav-link" to="/clientes">Clientes</Link>
</li>
</ul>
</div>
</div>
</nav>
</header>
<style>
</style>
Es un archivo escribible donde almacenamos los datos de la operacion asincrona de recuperación de datos.
import { writable } from "svelte/store";
export const data = writable([]);
Para ejecutar la aplicación deberemos ejecutar:
npm run dev
La ejecución del script anterior dará error. El motivo es que no hemos instalado las dependencias que aparecen indicadas en el archivo package.json.
Para instalar dichas dependencias, ejecutamos:
npm install
Dicho comando, leerá el archivo package.json, e instalará todas las dependencias que aparecen ahí. Ahora ya podemos volver a ejecutar npm run dev.
Podrás ver la aplicación en localhost:5000.
Realizado en Vercel en ArmeriaFrontEnd
para aprender el despliege siga la documentación de este enlace : Documentación