@luis-angel-martin-dzul/vue3-tmpl
Generador de plantillas para proyectos Vue 3 con Router, Pinia, Tailwind y FontAwesome
706
| Install | |
|---|---|
npm install @luis-angel-martin-dzul/vue3-tmpl |
|
| Latest Version: | 0.0.9 |
| License: | MIT |
| Last Updated: | Oct 20, 2026 |
| Links: | npm |
Maintainer: luis-angel-martin-dzul
vue3-tmpl
Generador de plantillas para proyectos Vue 3 con Router, Pinia, Tailwind CSS y FontAwesome preconfigurados.
Requisitos
- Node.js 18+
- npm 7+
Uso
npx @luis-angel-martin-dzul/vue3-tmpl <nombre-del-proyecto>
Ejemplo
npx @luis-angel-martin-dzul/vue3-tmpl mi-proyecto
Primeros pasos
cd mi-proyecto
npm install
npm run dev
Estructura generada
mi-proyecto/
├── index.html
├── vite.config.js ← alias @ → src/
├── postcss.config.js ← Tailwind + autoprefixer
├── package.json
├── .gitignore
└── src/
├── main.js ← Vue + Pinia + Router + FontAwesome
├── style.css ← Tailwind + clases utilitarias (.btnGreen, .btnBlue, etc.)
├── App.vue ← solo <RouterView />
├── router/
│ └── index.js
├── stores/
│ └── auth.js ← store de ejemplo con Pinia
├── models/
│ └── Auth.js ← clase Auth con ping y updatePassword
├── utils/
│ └── static.js ← BASE url + apiServerRequest
└── views/
├── auth/
│ └── LoginView.vue ← formulario de login
├── menu/
│ └── BaseLayout.vue ← sidebar colapsable + header
├── home/
│ └── HomeView.vue
├── dashboard/
│ └── DashboardView.vue
├── modulo/ ← ejemplo de submenu
│ ├── Opcion1View.vue
│ └── Opcion2View.vue
└── errors/
└── 404NotFound.vue
Rutas incluidas
| Ruta | Componente | Descripción |
|---|---|---|
/login |
LoginView |
Pantalla de inicio de sesión |
/ |
HomeView |
Inicio (dentro de BaseLayout) |
/dashboard |
DashboardView |
Dashboard (dentro de BaseLayout) |
/modulo/opcion-1 |
Opcion1View |
Ejemplo submenu opción 1 |
/modulo/opcion-2 |
Opcion2View |
Ejemplo submenu opción 2 |
/:pathMatch(.*) |
404NotFound |
Página no encontrada |
Incluido por defecto
| Paquete | Uso |
|---|---|
| Vue 3 | Framework |
| Vue Router 4 | Navegación entre vistas |
| Pinia | Estado global |
| Tailwind CSS v4 | Estilos utilitarios |
| FontAwesome 6 | Iconos |
Layout (BaseLayout)
El sidebar incluye:
- Colapso en desktop (icono + texto → solo icono)
- Overlay en mobile con botón hamburguesa
- Estado activo calculado por computed según la ruta actual
- Submenus con animación de apertura/cierre y apertura automática al navegar directo a una ruta hija
Para agregar un nuevo submenu, replica el bloque Módulo en BaseLayout.vue y añade las rutas correspondientes en router/index.js.
Clases de botones
Definidas en src/style.css listas para usar en cualquier vista:
<button class="btnGreen px-4 py-2">Guardar</button>
<button class="btnBlue px-4 py-2">Buscar</button>
<button class="btnOrange px-4 py-2">Editar</button>
<button class="btnRose px-4 py-2">Eliminar</button>
<button class="btnWhite px-4 py-2">Cancelar</button>
Patrón de modelos
Los modelos en src/models/ usan src/utils/static.js como base para las peticiones HTTP:
// src/utils/static.js
export const BASE = 'https://tu-api.com/'
export async function apiServerRequest(url, options = {}) {
try {
return await fetch(url, options)
} catch (error) {
console.error('Request error:', error)
return null
}
}
// src/models/MiModelo.js
import * as Static from '@/utils/static'
class MiModelo {
#endpoint = 'mi-endpoint'
constructor() {
this.#endpoint = Static.BASE + this.#endpoint
}
async getAll() {
const request = await Static.apiServerRequest(this.#endpoint)
if (request?.status === 200) return await request.json()
return null
}
async create(data) {
const request = await Static.apiServerRequest(this.#endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (request?.status === 200) return await request.json()
return null
}
}
export default new MiModelo()
Patrón de stores (Pinia)
// src/stores/miStore.js
import { defineStore } from 'pinia'
import { ref } from 'vue'
import MiModelo from '@/models/MiModelo'
export const useMiStore = defineStore('mi-store', () => {
const datos = ref([])
const loading = ref(false)
async function cargar() {
loading.value = true
datos.value = await MiModelo.getAll()
loading.value = false
}
return { datos, loading, cargar }
})
Scripts disponibles
| Comando | Descripción |
|---|---|
npm run dev |
Servidor de desarrollo |
npm run build |
Build de producción en dist/ |
npm run preview |
Vista previa del build |
Publicar el CLI en npm
npm publish --access public
Autor
Luis A Martin Dzul — luis.martin@gamasis.mx
Gestión de sesión y seguridad (incluido por defecto)
El template ya trae funcional el módulo de seguridad; solo falta apuntar a tu API:
- Sesión:
utils/session.js(access token en memoria + renovación programada),utils/static.js(apiServerRequestcon reintento tras 401 yrefreshSessionvíaPOST /auth/refreshcon cookie HttpOnly),models/Auth.js(login/logout),stores/auth.js(Pinia:login,logout,initSession,can,recargarPermisos). - Permisos: catálogo de módulos en
utils/static.js(MODULOS),$can('Modulo.codigo')en templates (utils/permisos.js),meta.permisospor ruta enrouter/index.js(el menú lateral se filtra con la misma definición) y guard global conmeta.publicpara rutas públicas. - Vistas: Seguridad → Usuarios, Módulo y Permisos (roles), con
models/Usuario.jsymodels/Rol.js. - API en desarrollo:
vite.config.jshace proxy de/apiahttps://127.0.0.1:58603; ajusta el puerto y las clavesAPI_KEYenutils/static.js. - Al agregar un módulo nuevo, regístralo en
MODULOS(utils/static.js) para poder asignarle permisos. - Pantallas de error:
views/errors/incluye 401 (sesión expirada), 403 (acceso denegado, dentro del layout), 500 (error de navegación) y "sin conexión" (el servidor no respondió al validar la sesión). Los 5xx de la API muestran un aviso sin salir de la pantalla.
Version History
| Version | Released | License |
|---|---|---|
| 0.0.9 | MIT | |
| 0.0.8 | MIT | |
| 0.0.6 | MIT | |
| 0.0.5 | MIT | |
| 0.0.4 | MIT |