Skip to content
En esta página

Svelte

Al igual que Vue, Svelte es un framework de frontend, pero con una gran diferencia: el build no incluye la librería ya que Svelte funciona como un compilador 🤔️

Pero, ¿qué quiere decir esto?

¿Qué es un compilador?

Por ejemplo, si creamos un proyecto en Vue con Vite y vamos a package.json vamos a ver esto:

json
{
  "name": "vue2-counter",
  "version": "0.0.0",
  "scripts": { 
    "dev": "vite", 
    "build": "vite build", 
    "preview": "vite preview --port 4173" 
  }, 
  "dependencies": {
    "vue": "^2.7.7"
  },
  "devDependencies": {
    "@vitejs/plugin-legacy": "^2.0.0",
    "@vitejs/plugin-vue2": "^1.1.2",
    "terser": "^5.14.2",
    "vite": "^3.0.2"
  }
}

En package.json hay 3 scripts: dev, build y preview.

Cuando le damos npm run dev se ejecuta el servidor de desarrollo de Vite y vemos un mensaje diciendo que podemos ver nuestro proyecto en http://localhost:numero-de-puerto/. Si vamos a esa URL vemos nuestro proyecto corriendo.

Una vez que el proyecto está terminado y queremos verlo online tenemos que hacer un build, es decir construir la aplicación transformando todos los archivos .vue en un archivo .js que el browser pueda ejecutar (porque el browser no entiende qué son los archivos .vue).

Luego de realizado el build se puede hacer un deploy, o sea, subir ese archivo .js (junto con el HTML y CSS) a un servidor donde nuestra aplicación esté online.

Esto se hace con el comando npm run build. Lo que hace este comando es compilar los archivos .vue y transformarlos en un único archivo .js. Si la app es muy grande este archivo .js puede ser dividido en chunks (partes) mediante un proceso llamado code splitting.

Este archivo .js, además de todos los archivos .vue compilados, contiene todos los módulos que tenemos instalados como dependencies, incluyendo la librería entera de Vue:

json
"dependencies": {
  "vue": "^2.7.7"
},

Esto es porque Vue, al igual que React, necesita usar la librería (o mejor dicho, la biblioteca, que es la traducción de la palabra library... pero bueno, la convención es llamarla librería 🤷‍♂️️) para que la aplicación funcione en el browser.

La librería vue 2.7.7 pesa alrededor de 70K (sin compresión GZIP). Esto parece poco, cualquier archivo .jpg pesa más que eso. Pero 70K de JS no es lo mismo que 70K de JPG. Procesar código JavaScript demanda mucho más tiempo y energía por parte del procesador (algo que se nota sobre todo en computadoras con poca velocidad o dispositivos móviles). Así que 70K de JavaScript no es poco.

Svelte como devDependency

Éste es el problema que resuelve Svelte: en lugar de incluir la librería en el build ésta no es más que una devDependency, o sea, una librería de desarrollo que sólo se usa mientras estamos creando la aplicación (como, por ejemplo, sass-loader o babel) pero que no se incluye en el build final:

json
{
  "name": "svelte-app",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "start": "sirv public --no-clear"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^24.0.0",
    "@rollup/plugin-node-resolve": "^15.0.0",
    "@rollup/plugin-terser": "^0.4.0",
    "rollup": "^3.15.0",
    "rollup-plugin-css-only": "^4.3.0",
    "rollup-plugin-livereload": "^2.0.0",
    "rollup-plugin-svelte": "^7.1.2",
    "sirv-cli": "^2.0.0",
    "svelte": "^3.55.0" 
  }
}

Como pueden ver, al final de las devDependencies está svelte. Lo único que hace la librería de Svelte es transformar (o mejor dicho, compilar) los archivos .svelte en un archivo .js con toda la aplicación, pero sin necesidad de incluirse totalmente a sí misma en el build. Lo único que incluye son algunos métodos y clases (como SvelteComponent) necesarios para el renderizado de los componentes.

Esto lo logra, en gran parte, gracias a que prescinde del Virtual DOM, el proceso que usan Vue y React para actualizar el DOM (o sea, el Document Object Model, el objeto que representa el documento HTML que genera la vista) comparando lo que cambió en el DOM con lo que no cambió. El Virtual DOM es una herramienta muy precisa para actualizar la vista en aplicaciones SPA, pero la cantidad de código que insume es muy grande.

Svelte usa otra forma de actualizar la vista, sin Virtual DOM, usando código imperativo (es decir, con los métodos imperativos de Vanilla JS, como createElement, appendChild, textContent) para modificar en el DOM sólo lo que cambia.

Y al no estar la librería de Svelte incluída en el build final éste es mucho más liviano. En realidad, muchísimo más liviano.

Comparando el build en distintos frameworks

Por ejemplo, podemos crear una aplicación simple con Vue 2 que contenga un solo componente con un contador con dos botones para incrementar o decrementar la cantidad:

0

Con Vue 2

El código de Vue 2 sería así:

html
<template>
  <main>
    <button @click="decrement">➖️</button>
    <span>{{ counter }}</span>
    <button @click="increment">➕️</button>
  </main>
</template>

<script>
export default {

  data: () => ({ 
    counter: 0
  }),
  methods: {
    decrement() {
      this.counter > 0 && this.counter--
    },
    increment() {
      this.counter++
    }
  }
}
</script>

Es algo muy simple, sin necesidad de usar librerías adicionales, ni Vue Router, ni Vuex, ni nada.

Al darle npm run build Vite compila la aplicación y por consola nos dice cuánto pesa el archivo final del build:

bash
dist/assets/index.9356cd35.js   70.05K

70.05K solamente para un contador 😒️ y esto es sólamente el archivo .js principal, sin contar el CSS ni los polyfills para la compatibilidad con browsers antiguos, que pesan otros 150K más.

Con Vue 3

Ahora, probemos hacer la misma aplicación con Vue 3:

html
<template>
  <main>
    <button @click="decrement">➖️</button>
    <span>{{ counter }}</span>
    <button @click="increment">➕️</button>
  </main>
</template>

<script setup>

import { ref } from 'vue'

const counter = ref(0)
const decrement = () => counter.value > 0 && counter.value--
const increment = () => counter.value++

</script>

Le damos npm run build y al finalizar la compilación por consola vemos:

bash
dist/assets/index-0bdc572a.js   53.29K

53.29K, un poco menos que en Vue 2, porque en Vue 3, al poder importar sólo lo que necesitamos de la librería (en este caso el método ref) los builds son más livianos que en Vue 2. Esta forma de reducir los builds importando sólo lo que necesitamos es lo que se suele llamar tree shaking.

Por otro lado, Vue 3 prescinde de los polyfills, por lo que sólo funciona en browsers posteriores al 2015, pero como todos los browsers (excepto Explorer) tienen actualizaciones automáticas (lo que se suele llamar evergreen browsers) esto no es un problema.

Con React

Ahora probemos con React 😬️

js
import { useState } from 'react'

const Counter = () => {
  const [counter, setCounter] = useState(0)

  return (
    <>
      <main>
        <button onClick={() => setCounter(Math.max(counter - 1, 0))}>➖️</button>
        <span>{ counter }</span>
        <button onClick={() => setCounter(counter + 1)}>➕️</button>
      </main>
    </>
  )
}
export default Counter

Y, ¿cuánto pesa nuestro contador en el framework más usado en el mundo del desarrollo web?

bash
dist/assets/index-d8e088ed.js   143.07K

143.07K... 🤦‍♂️️ más del doble que con Vue 2 y casi el triple de Vue 3...

Con Svelte

Ahora probemos con Svelte:

html
<main>
	<button on:click={decrement}>➖️</button>
	<span>{counter}</span>
	<button on:click={increment}>➕️</button>
</main>

<script>
let counter = 0
const increment = () => counter++
const decrement = () => counter > 0 && counter--
</script>

Y, ¿cuánto pesa el contador en Svelte?

bash
public/build/bundle.js   3.5K

Sí, solamente 3.5K 🥳️🥳️🥳️ para hacer exactamente lo mismo que en Vue 3 demanda 53K, en Vue 2 70K y en React 143K de JavaScript.

La diferencia es enorme, aunque también hay que tener en cuenta que cada componente de Svelte pesa en promedio 0.5K más que un componente de Vue. Entonces, como señala Evan You, el creador de Vue, en este tweet a medida que una aplicación crece esta diferencia se va acortando.

Por otro lado, Svelte no es perfecto, tiene sus problemas, y en algunos aspectos Vue es mejor (por ejemplo, Svelte no tiene herramientas de manejo de estado global tan sofisticadas como Vuex o Pinia).

En cuanto a React, se podría decir que es mejor a Svelte en una sola cosa: React le exige al programador aprender JavaScript a fondo, algo que en Svelte no es tan necesario.