¿Cómo implementar una aplicación Bun?

Bun es un tiempo de ejecución de JavaScript diseñado para ser rápido, liviano y fácil de usar. Está escrito en Zig y funciona con JavaScriptCore, el motor de JavaScript que impulsa Safari.

Bun tiene un administrador de paquetes, un ejecutor de pruebas y un paquete integrados compatibles con Node.js.

También proporciona un conjunto mínimo de API altamente optimizadas para realizar tareas comunes, como iniciar un servidor HTTP y escribir archivos.

En este artículo, creará una API web simple con Bun y la implementará en Back4app usando contenedores Back4app. Continúe leyendo para obtener más información sobre cómo alojar una aplicación Bun.

Ventajas de Bun

Desde el anuncio inicial de Bun, incluso antes del lanzamiento de la V1 en septiembre de 2023, Bun se ha vuelto cada vez más popular en la comunidad de JavaScript. Estas son algunas de las razones.

Velocidad

Bun está escrito en Zig, un lenguaje de programación de bajo nivel diseñado para la programación de sistemas, centrándose en el rendimiento, la seguridad y la legibilidad. Diseñado para ser una alternativa moderna a C y C++.

Además, a diferencia de Node.js y Deno, que utilizan el motor JavaScript V8 de Chrome, utiliza el motor JavaScriptCore, que impulsa Safari.

Además de Zig y JavaScript Core, Bun también utiliza otras técnicas, como un asignador de memoria personalizado optimizado para JavaScript y un compilador justo a tiempo (JIT) para optimizar el código a medida que se ejecuta.

En general, la combinación de Zig, JavaScript Core y otras optimizaciones hacen de Bun un tiempo de ejecución de JavaScript muy rápido en comparación con otros tiempos de ejecución.

Compatibilidad con Node.js

Bun está diseñado para ser un reemplazo directo de Node.js y, como tal, es compatible con todas las API de Node.js.

También tiene todos los módulos integrados de Node.js, como crypto, fs, path, etc. Puede verificar los módulos de Node.js disponibles y no disponibles en la documentación de Bun.js.

Además, Bun es un administrador de paquetes compatible con npm. Esto significa que puedes usar Bun para instalar y administrar paquetes de Node.js usando Bun.

Compatibilidad con TypeScript lista para usar

Bun tiene soporte nativo y perfecto para TypeScript, lo que lo convierte en una excelente opción si prefiere o necesita TypeScript en sus proyectos.

TypeScript, una versión extendida y de tipo estático de JavaScript, introduce funciones avanzadas de lenguaje y escritura estática para mejorar el desarrollo de JavaScript.

Con Bun, no hay necesidad de configuración adicional y no se requieren procedimientos de configuración o compilación adicionales para habilitar la funcionalidad TypeScript.

Limitaciones de Bun

A pesar de sus ventajas, Bun tiene ciertas limitaciones que debe considerar antes de usarlo en su proyecto.

Recursos limitados

Bun es todavía relativamente nuevo, lo que significa que la comunidad es actualmente pequeña.

No hay muchos recursos que cubran el desarrollo específico de Bun-js, lo que significa que puede resultarle difícil descubrir cómo utilizar el tiempo de ejecución.

Sin embargo, la documentación de Bun es completa y sirve como un valioso punto de referencia. Si encuentra dificultades, también existe la opción de buscar ayuda a través de su canal Discord.

Soporte para Windows

Actualmente, Bun ofrece soporte limitado para el sistema operativo Windows. En el momento de escribir este artículo, solo se admite el tiempo de ejecución en Windows.

El ejecutor de pruebas, el administrador de paquetes y el paquete aún están en desarrollo y, como tales, no funcionan en Windows. Continúe leyendo para obtener más información sobre cómo alojar una aplicación Bun.

Crear una aplicación para Bun

Antes de poder utilizar Bun, debe instalarlo.

Para instalar Bun en macOS, WSL y Linux, ejecute el siguiente comando:

curl -fsSL https://bun.sh/install | bash

Configurando su entorno de desarrollo

Para crear un nuevo proyecto Bun, ejecute el siguiente comando:

bun init

Al ejecutar el comando anterior, se inicializa un proyecto Bun vacío en el directorio de su proyecto.

Para el tutorial, creará una API simple con Elysia, uno de los marcos de servidor Bun HTTP más rápidos (según sus puntos de referencia).

Ejecute el siguiente comando para instalar Elysia y otras dependencias necesarias para este proyecto:

bun add elysia knex dotenv pg

Las otras dependencias instaladas en el comando incluyen:

  • Knex, un generador de consultas. Utilizará esta dependencia para simplificar la interacción con su base de datos.
  • dotenv, este paquete le ayuda a gestionar las variables ambientales en su proyecto.
  • pg (controlador de base de datos Postgres) para interactuar con su base de datos Postgres.

A continuación, inicialice knex en su proyecto ejecutando:

knex init

El comando anterior crea un archivo knexfile.js. Este archivo contiene opciones de configuración para su base de datos.

Reemplace el código en el archivo con el bloque de código a continuación:

require("dotenv").config();

export const development = {
  client: "pg",
  connection: process.env.DATABASE_URL,
  migrations: {
    directory: "./db/migrations",
  }
};

A continuación, cree un archivo db.js en el directorio raíz de su proyecto y agréguele el bloque de código a continuación.

const knex = require("knex");
const knexFile = require("./knexfile.js");

const environment = process.env.NODE_ENV || "development";

export default knex(knexFile[environment]);

A continuación, cree un archivo .env y agregue los detalles de conexión de su base de datos o URI al archivo.

Por ejemplo:

DATABASE_URL = <YOUR_DATABASE_URI>

Reemplace “YOUR_DATABASE_URI” con la URL de su base de datos.

Nota: Asegúrese de agregar su archivo .env a su archivo .gitignore para asegurarse de no enviar información privada al control de versiones.

Creando su modelo de base de datos

Para crear su modelo de base de datos usando Knex, creará un archivo de migración y escribirá un comando de creación SQL usando Knex.

Ejecute el siguiente comando para crear su primera migración:

knex migrate:make blog

A continuación, reemplace el código en el archivo de migración generado con el siguiente bloque de código:

/**
 * @param { import("knex").Knex } knex
 * @returns { Promise<void> }
 */
export function up (knex) {
  return knex.schema.createTable("blog", (table) => {
    table.increments("id").primary();
    table.string("title").notNullable();
    table.string("content").notNullable();
    table.string("author").notNullable();
    table.timestamp("created_at").defaultTo(knex.fn.now());
  });
}

/**
 * @param { import("knex").Knex } knex
 * @returns { Promise<void> }
 */
export function down (knex) {
  return knex.schema.dropTable("blog");
}

Finalmente, ejecute el siguiente bloque de código para ejecutar su archivo de migración:

knex migrate:latest

El comando anterior ejecuta el archivo de migración que generó anteriormente, creando así una tabla Blog en su base de datos.

Creando un servidor Bun-Elysia

En este paso, creará un servidor API simple.

Abra su archivo index.ts y agregue el bloque de código a continuación:

//index.ts
const { Elysia } = require("elysia");
let db = require("./db");

db = db.default;

const app = new Elysia();

En el bloque de código a continuación, importó Elysia y creó una instancia del marco (aplicación) Elysia.

Creando controladores de ruta

A continuación, creará controladores de ruta para su aplicación. El controlador que cree será para las siguientes rutas:

  • POST /posts/create-new-post
  • GET /posts
  • GET /posts/:id
  • PATCH /posts/:id/update-post
  • DELETE /posts/:id/delete-post

Agregue el siguiente bloque de código a su archivo index.ts para crear el controlador para “/posts/create-new-post”:

app.post("/posts/create-new-post", async (context) => {
  try {
    //Extract the title, content and author from the request body
    const { title, content, author } = context.body;

    //Insert the post into the database
    const post = await db("blog").insert({
      title,
      content,
      author,
    });

    //Send response to the client
    return new Response(JSON.stringify(post));
  } catch (error: any) {
    //Send error to the client
    return new Response(error.message, { status: 500 });
  }
});

El bloque de código anterior es un controlador de ruta para su punto final que agrega nuevas publicaciones a su base de datos.

Agregue el siguiente bloque de código a su archivo index.ts para crear el controlador que recupera todas sus publicaciones “/posts”:

app.get("/posts", async (context) => {
  try {
    //Get all posts from the database
    const posts = await db.select("*").from("blog");

    //Send response to the client
    return new Response(JSON.stringify(posts));
  } catch (error: any) {
    //Send error to the client
    return new Response(error.message, { status: 500 });
  }
});

Agregue el siguiente bloque de código a su archivo index.ts para crear el controlador que recupera una sola publicación por ID “/posts/:id”:

app.get("/posts/:id", async (context) => {
  //Extract the id from the request params
  const { id } = context.params;

  //Get the post from the database
  const post = await db("blog").where({ id });

  //If the post is not found, send a 404 response
  if (post.length === 0) {
    return new Response("Post not found", { status: 404 });
  }

  //Send response to the client
  return new Response(JSON.stringify(post));
});

Agregue el siguiente bloque de código a su archivo index.ts para crear el controlador que actualiza una sola publicación con los datos en la carga útil por ID “/posts/:id/update-post”:

app.patch("/posts/:id/update-post", async (context) => {
  //Extract the id from the request params
  const { id } = context.params;

  //Extract the title and content from the request body
  const { title, content } = context.body;

  //Update the post in the database
  const post = await db("blog").where({ id }).update(
    {
      title,
      content,
    },
    ["id", "title", "content"]
  );

  //Send response to the client
  return new Response(JSON.stringify(post));
});

Agregue el siguiente bloque de código a su archivo index.ts para crear el controlador que elimina una sola publicación por ID “/posts/:id/delete-post”:

app.delete("/posts/:id/delete-post", async (context) => {
  //Extract the id from the request params
  const { id } = context.params;

  //Delete the post from the database
  const post = await db("blog").where({ id }).del();

  //Send response to the client
  return new Response(JSON.stringify(post));
});

Finalmente, agregue el bloque de código a continuación para configurar el PUERTO para su aplicación.

app.listen(3000, () => {
  console.log("Server running on port 3000");
});

Ejecute el siguiente comando para iniciar su aplicación:

bun --watch index.ts

Implementación de una aplicación Bun en Back4app Containers

La implementación de su aplicación Bun requiere algunos pasos.

Paso 1: Escribir un archivo Docker

Para crear un Dockerfile, ejecute el siguiente comando en su terminal.

touch Dockerfile

Al ejecutar el comando anterior se crea un Dockerfile en el directorio raíz de su proyecto.

A continuación, abra su Dockerfile y agréguele el siguiente bloque de código:

FROM oven/bun

WORKDIR /app

COPY package.json .
COPY bun.lockb .

RUN bun install

COPY . .

EXPOSE 3000

CMD ["bun", "index.ts"]

En el Dockerfile anterior, la primera línea, FROM oven/bun, especifica la imagen base que se utilizará.

Esta imagen es una imagen prediseñada que contiene el tiempo de ejecución de Bun y todas sus dependencias.

La siguiente línea, WORKDIR /app, establece el directorio de trabajo de la imagen. Este es el directorio donde se copiará y ejecutará el código de la aplicación.

Las siguientes dos líneas, COPY package.json . y COPY bun.lockb ., copian los archivos package.json y bun.lockb del directorio actual a la imagen.

Estos archivos son necesarios para que el tiempo de ejecución de Bun instale las dependencias de la aplicación.

La siguiente línea, RUN bun install, instala las dependencias de la aplicación utilizando el tiempo de ejecución de Bun.

La siguiente línea, COPY . ., copia todo el directorio actual en la imagen. Esto incluye el código de la aplicación y cualquier otro archivo necesario.

La siguiente línea, EXPOSE 3000, expone el puerto 3000 del contenedor al mundo exterior. Este es el puerto en el que escuchará la aplicación.

La última línea, CMD [“bun”, “index.ts”], especifica el comando que se ejecutará cuando se inicie el contenedor. Este comando iniciará el tiempo de ejecución de Bun y ejecutará el archivo index.ts de la aplicación.

Finalmente, envíe su código a GitHub.

Paso 2: Cree una aplicación Back4app

El siguiente paso para alojar una aplicación Bun es crear una nueva aplicación en Back4App. Primero, inicie sesión en su cuenta Back4App o regístrese si aún no tiene una. Una vez que haya iniciado sesión, se encontrará en el panel de Back4App.

Haga clic en el botón “NUEVA APLICACIÓN” y seleccione la opción “Contenedores como servicio”.

Back4app BaaS vs CaaS

Como siguiente paso para alojar una aplicación Bun, conecte su cuenta de GitHub a su cuenta Back4app. Conectar su cuenta permite a Back4app acceder a los repositorios de su cuenta.

Puede decidir otorgar acceso a todos los repositorios de su cuenta o a repositorios específicos. Elija la aplicación que desea implementar, en este caso, la aplicación que creó en este tutorial, y haga clic en Seleccionar.

New app back4app

Después de hacer clic en el botón Seleccionar, se lo dirigirá a una página de configuración, donde completará detalles sobre su aplicación, como el PUERTO y las variables de entorno.

Después de completar los detalles, haga clic en el botón Crear aplicación. Esto inicia el proceso de implementación.

Su implementación debería tener éxito y obtendrá una URL para acceder a su aplicación, pero si falla, puede aprovechar la integración de Back4app ChatGPT para resolver los problemas que tenga con su Dockerfile.

Alternativamente, puede solucionar manualmente los errores de implementación utilizando los registros detallados y la guía de solución de problemas de Back4app.

Conclusión

En este artículo, ha explorado el tiempo de ejecución de JavaScript de Bun, sus ventajas y limitaciones aparentes. También ha explorado cómo crear una aplicación Bun usando Elysia, Knex y PostgreSQL.

Finalmente, exploró los contenedores Back4app y cómo implementar sus aplicaciones Bun en la plataforma.

Al usar Bun, es importante tener en cuenta que aún se encuentra en sus primeras etapas y podría introducir algunos cambios importantes más adelante en el futuro.


Leave a reply

Your email address will not be published.