Visualizador de markdown con Ionic como aplicación web y nativa para celulares maximizando el desarrollo en OpenBSD/adJ

1. Introducción

Continuando con el ejemplo de {vite-vue} desarrollamos la misma aplicación usando Ionic dejando sus fuentes en https://gitlab.com:vtamara/markdown-aprender-ionic así como varios experimentos en ramas del mismo repositorio así:

Rama Experimento Notas
main Previsualizador con npm y typescript Opera aplicación web y genera código para Android e iOS
pnpm Previsualizador con pnpm y typescript Opera aplicación web, hay problemas para instalar generador de código para Android e IOS al parecer por conflicto entre npm y pnpm
solojs Previsualizador más componentes ionic más otra ruta/vista con pnpm y javascript Opera aplicación web, mismo problema de la anterior

Hemos encontrado con agrado que Ionic soporta Angular, React y Vue y que a partir de una aplicación genera código nativo para Android y para iOS.

Infortunadamente recomienda typescript y para el desarrollo de aplicaciones nativas requiere npm (encontramos errores con pnpm tanto en OpenBSD/adJ como en Ubuntu 22.04).

2. Iniciar una aplicación con una plantilla para vue en blanco

Instala ionic con

doas npm install -g @ionic/cli@latest

Al momento de este escrito aunque Ionic está en su versión 8.0 la versión más reciente del cli (visible con ionic --version) es 7.2.0, pero opera.

Después inicia un proyecto con una plantilla en blanco y vue con:

ionic start markdown-aprender-ionic blank --type vue

Esto generará un error porque cypress no tiene soporte para OpenBSD aún (ver incidente que iniciamos en cypres), pero puede pasar a la carpeta del proyecto y quitar la dependencia de cypress eliminado la línea de package.json.

Las plantillas de ionic también usan vite, que como se describió en {vite-vue}, puede usarse para aplicaciones web con pnpm pero encontramos como hacerlas operar con npm (el truco se simplifica al leer la documentación de overrides en https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides).

Para usar rollup con WebAssembly (al menos mientras se resuelve el incidente que iniciamos en rollup y en wasm-pack) agregar a package.json:

  "overrides": {
    "rollup": "npm:@rollup/wasm-node"
  }

Complete la instalación inicial con:

npm i

Tras esto ya puede servir esta aplicación mínima y ver el resultado en el navegador:

ionic serve

O si ejecuta la aplicación en otro servidor via ssh puede especificar máquina y puerto con:

ionic serve --no-open --host=192.168.177.47 --port=4400

3. Agregar la funcionalidad de visualizador de mardown

La aplicación generada emplea vistas que se ubican en src/views y, bueno, una única vista HomePage en la cual inicialmente podemos emplear el mismo HTML dentro de la sección template de {vite-vue} dentro del div con id container y la misma lógica del controlador dentro de la sección script –aunque usamos encabezado y pie de página de ionic tras consultar {ionic-footer}.

El archivo src/views/HomePage fue el único que modificamos de la plantilla, cuidando insertar lo de vue dentro del elemento <ion-content> que a su vez debe estar dentro del elemento <ion-page> (que debe estar presente en toda página enrutable) . En la sección <styles> le agregamos los elementos de estilo del ejemplo {vita-vue} las secciones <template> y <script> quedaron asi:

<template>
  <ion-page>
    <ion-header :translucent="true">
      <ion-toolbar>
        <ion-title>Previsualizador de Markdown</ion-title>
      </ion-toolbar>
    </ion-header>

    <ion-content :fullscreen="true">
      <ion-header collapse="condense">
        <ion-toolbar>
          <ion-title size="large">Previsualizador de Markdown</ion-title>
        </ion-toolbar>
      </ion-header>
      <div id="container">
        <div class="editor">
          <div class="texto-md">
            <h2>Digite un texto Markdown</h2>
            <textarea style="height:auto" 
                      rows="16" 
                      class='area-de-texto' 
                      v-model='textoMd'>
            </textarea>
          </div>
          <div class="html-gen">
            <h2>Previsualización</h2>
            <div v-html='htmlGen'
                 ></div>
          </div>
        </div>
      </div>
    </ion-content>
    <ion-footer>
      <strong>Ready to create an app?</strong>
      <p>Start with Ionic <a target="_blank" rel="noopener noreferrer"
href="https://ionicframework.com/docs/components">UI Components</a></p>
    </ion-footer>
  </ion-page>
</template>

<script setup lang="ts">
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from
'@ionic/vue';

import { ref, computed } from 'vue'
import { marked } from "marked"

const textoMd = ref("")

const htmlGen = computed(() => marked(textoMd.value))
</script>
...

Hemos dejado el código fuente de la aplicación completa en https://gitlab.com/vtamara/markdown-aprender-ionic

Y su visualización es:

Pantallazo

4. Pasando de typescript a javascript y agregando componentes ionic y ruta/vista

Hemos visto comentarios de los desarrolladores de ionic que guían a los usuarios de ionic a usar typescript. Como preferimos las soluciones tipo importmaps que no requieren compilación previa seguimos con éxito los pasos de {ionic-vue-quickstart} para quitar typescript. En esas instrucciones sólo falta indicar que al modificar el archivo src/router/index.js el segundo parámetro de createRouter debe cambiarse de routes a routes: routes.

El contenido completo de ese archivo con las rutas a las vistas de la aplicación quedó así:

import { createRouter, createWebHistory } from '@ionic/vue-router';
import HomePage from '../views/HomePage.vue'

const routes = [
  {
    path: '/',
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: HomePage
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: routes
})

export default router

La aplicación de ejemplo completa convertida a javascript está disponible en la rama solojs del repositorio antes mencionado, i.e https://gitlab.com/vtamara/markdown-aprender-ionic/-/tree/solojs

Y pueden verse las difrencias entre esa rama y la inicial con typescript en https://gitlab.com/vtamara/markdown-aprender-ionic/-/compare/main...solojs?from_project_id=57045554&straight=false

Esta aplicación además agrega varios componentes ionic y otra ruta/vista, lo cual no tuvo inconveniente en operar con vue y javascript plano.

4. Generación de aplicaciones nativas para teléfonos Android e iOS

Seguimos las instrucciones de https://ionicframework.com/docs/vue/quickstart#build-a-native-app con el ejemplo mínimo con typescript y npm de manera que si nos operó:

% ionic integrations enable capacitor
% ionic build
% ionic cap add ios
% ionic cap add android

Para generar los proyectos iniciales ios y android. También nos operó:

% ionic cap copy
% ionic cap sync

Para sincronizar la aplicación web con las aplicaciones nativas y viceversa.

Al momento de este escrito no es posible la compilación ni la ejecución de esas aplicaciones nativas desde OpenBSD/adJ.

De hecho para iOS es indispensable emplear un Mac con XCode. Por su parte para compilar aplicaciones para Android las instrucciones de ionic requieren Android Studio bien con emulador o bien con posibilidades de ejecutar pruebas en hardware Android.

Android Studio no ha sido portado a OpenBSD y no se ve viable por su su masivo tamaño, rápido desarrollo y sus requerimientos de GPU.

5. Compilación de aplicación para Android desde Ubuntu mediante conexión VNC

Avanzamos en la compilación de la aplicación para Android con una conexión remota a un Ubuntu 22.04, para lo cual configuramos vnc con TightVNC en el Ubuntu y TigerVNC en OpenBSD/adJ con base en las instrucciones de https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-vnc-on-ubuntu-20-04.

En OpenBSD/adJ instalamos el cliente de TigerVNC con doas pkg_add tigervnc

En el Ubuntu tras instalar TightVNC nos operó vncserver -localhost -geometry 1280x800

Y para terminar la sesión: vncserver -kill :1

Localmente en OpenBSD/adJ nos conectamos al Ubuntu desde una primera terminal con:

ssh -p14112 -L 59000:localhost:5901 -C -l vtamara servidor.org

Y desde una segunda terminal iniciamos vncviewer con:

vncviewer localhost:59000

En el Ubuntu, descargamos Android Studio como se indica en https://developer.android.com/studio y configuramos aceleración de kvm incluyendo: usermod -a -G kvn miusuario

Cada vez que queremos iniciar Android Studio en el Ubuntu ejecutamos: /usr/local/android-studio/bin/studio.sh

Con este método aunque logramos la compilación, no logramos probar remotamente con el emulador debido al error:

WARN - Emulator: Pixel_3a_API_34_extension_level_7_x86_64 - Your GPU drivers may
have a bug. Switching to software rendering.
2024-04-28 19:52:27,266 [ 120333]   WARN - Emulator:
Pixel_3a_API_34_extension_level_7_x86_64 - NativeEventFilter: warning: cannot
get mod mask info
2024-04-28 19:52:27,325 [ 120392]   WARN - Emulator:
Pixel_3a_API_34_extension_level_7_x86_64 - QEMU main loop exits abnormally with
code 1
2024-04-28 19:52:37,541 [ 130608]   WARN - Emulator:
Pixel_3a_API_34_extension_level_7_x86_64 - Emulator terminated with exit code
137

Por otra parte probar en hardware real requiere operar directamente desde el Ubuntu pues el teléfono debe conectarse mediante un cable o en la misma LAN wifi.

5. Conclusiones

Ha sido bastante simple crear una aplicación web mínima con vue e ionic. Prácticamente bastó "insertar" lo hecho en una aplicación vue en una plantilla ionic –habría que validar mezclando una aplicación más grande de vue dentro de una aplicación más grande de ionic.

Nos parece una desventaja que deba usarse typescript, pero nos anima haber podido convertir el ejemplo mínimo con vue a javascript y haber podido incrustar componentes ionic y rutas/vistas. Debe validarse con más componentes ionic y aplicaciones más grandes.

Nos ha parecido una gran ventaja la generación código nativo para teléfonos iOS y Android mediante capacitor.

Es un poco inconveniente no poder compilar ni probar esas aplicaciones nativas desde OpenBSD/adJ y ni siquiera que sea posible probarlas mediante una conexión VNC a un Linux por exigencias de GPU. Estas dificultades se debe en parte al monopolio de Apple que obliga a desarrollar aplicaciones para iOS desde MacOSX, en parte a lo grande y rápido que se desarrollan las herramientas para Android, en parte a las inexistencia de controladores en OpenBSD para muchas tarjetas de video (en particular a todas las NVIDIA por falta de interés de esa empresa en OpenBSD, ver https://www.nvidia.com/en-us/geforce/forums/-/5/463072/openbsd-drivers/?commentPage=2 ) y por la falta de desarrolladores en OpenBSD y adJ para portar y mantener controladores y herramientas.

En la situación actual el flujo de trabajo para desarrollar aplicaciones web y para celular con ionic que más usaría OpenBSD/adJ sería mantener el desarrollo de lo del lado del servidor (backend) y de la aplicación web en OpenBSD/adJ y completar el desarrollo de las aplicaciones nativas para celular desde un MacOSX reciente (o si se desea prescindir del monopolio de Apple y sólo desarrollar la interfaz para Android sería directamente desde un computador con Ubuntu con más de 16G en RAM, más de 50G en disco sólo para lo de Android y tarjeta de video con GPU reciente y soportada).

Este mismo flujo sería necesario aún empleando otros marcos para desarrollo simultaneo de aplicaciones web y nativas como strada –que por cierto queremos evaluar proximamente.

6. Bibliografía