Creando mi propio IDE con Angular y Node – Parte 1

¿Quieres aprender a crear tu propio IDE con Angular y Node?, chécate esta serie de tutoriales para llegar a crear uno propio de forma fácil y rápida.

Últimamente me he puesto a pensar, ¿valdría la pena desarrollar mi propio IDE que vaya integrando muchas funcionalidades y todas se adapten a mi?… y la respuesta fue: NO.

El motivo es bastante fácil: ¿Para qué quiero un IDE que se adapte a mi si al final de cuentas ya existen cientos de IDEs y simplemente podríamos usarlos?, ej: WebStorm (o en general los de JetBrains), Notepad++, VSCode, Brackets, y un sin fin… entonces, ¿por qué este post? y la respuesta, nuevamente, es fácil: Por que nunca está demás aprender algo…

Y es que en realidad es bastante sencillo trabajarlo, pero aprovecharé esta guía para enseñarles algunas cosas de Angular y Node y quizá, también porque podrían aprovechar y hacer que este IDE viva en su nube y desde el mismo poder editar archivos… digo, puede ser una buena razón si no quieren entrar por FTP puedan ponerle algún login y a darle, a editar en la nube (aunque claro, puede ser muy inseguro al final pero qué más da…); así que si están listos, prepárense porque serán varios tutoriales.

Así que manos a la obra:

Lo primero es obviamente generar un nuevo proyecto de Angular, para esto no les explicaré, para ello tienen mi guía:

Espero algún día terminarla…

Ya que tenemos nuestro proyecto iniciado lo primero será instalar Monaco editor, es básicamente el editor de código que potencia VSCode y está desarrollado por Microsoft.

Si Googleamos, el resultado más favorable para “Angular nativo” (por así llamarlo) en realidad está obsoleto, así que usaremos un fork de este, al que le llamaron “v2”, para ello ejecutamos el siguiente comando:

npm install monaco-editor ngx-monaco-editor-v2 --save

Como vemos, se instala el editor de Monaco y a la vez, su adaptación en Angular. Pero eso no es todo, necesitamos cargarlo en nuestro archivo angular.json , buscamos la línea para los assets dentro del índice de la app y agregamos a Monaco, quedando de la siguiente manera:

{
  "apps": [
    {
      "assets": [
      { "glob": "**/*", "input": "node_modules/monaco-editor", "output": "/assets/monaco/" }
      ],
      ...
    }
    ...
  ],
  ...
}

Ahora, como es costumbre al cargar una librería/dependencia/módulo en Angular, vamos al módulo principal, el app.module.ts y cargamos a Monaco:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { MonacoEditorModule } from 'ngx-monaco-editor-v2';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    MonacoEditorModule.forRoot() // <--aquí se carga y con "forRoot"
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Vamos a nuestro app.component.html y le borramos todo. Después a nuestro app.component.ts y le borramos la variable y agregamos las siguientes:

editorOptions = {theme: 'vs-dark', language: 'javascript'};
code = 'function x() {\nconsole.log("Hello world!");\n}';

Ahora en nuestro app.component.html agregamos lo siguiente:

<ngx-monaco-editor [options]="editorOptions" [(ngModel)]="code"></ngx-monaco-editor>

Hasta este punto, si corremos Angular (ng serve -o ) va a explotar y nos dirá que tenemos un problema, no hemos cargado ngModel al módulo, para ello vamos a agregarle lo siguiente:

...
// En la parte inferior del import de Monaco agregamos lo siguiente:
import { FormsModule } from '@angular/forms';
...
// Luego agregamos el import del FormsModule al array de imports debajo del import de Monaco
...
   imports: [
      ...
      FormsModule
      ...
   ],
...

Ahora sí, si ejecutamos Angular nos va a cargar la pantalla de nuestro editor y veremos el hola mundo de consola, ¡éxito!.

Ahora, hay que entender una cosa, Monaco tiene la posibilidad de leer archivos locales, tipo c:/foo/bar/mi-archivo.ts y entonces, podríamos cargar sin necesidad de usar Node. Pero, para todo esto, nosotros necesitamos setear todo a mano, archivos y documentos que usaríamos. Es aquí donde Node entra a la carga, sin embargo aún no vamos para allá.

Primero, terminemos una base sencilla de Angular, aún sin estilos, pero a ¿Qué me refiero con esto?… bueno, nos falta una librería más para mostrar los directorios y una para las pestañas, porque, ¿qué hueva ir archivo por archivo no?…

Bueno, vamos primero a la de listar directorios, para ello instalamos ngx-treeview:

npm i ngx-treeview --legacy-peer-deps

Y como en el caso anterior, la importamos al módulo:


import { TreeviewModule } from 'ngx-treeview';
...
imports: [
   ...
   TreeviewModule.forRoot()
   ...
]

Ojo, en este caso tuvimos que usar --legacy-peer-deps porque Angular 14 no es soportado directamente en esta dependencia, así que la “forzamos”.

Vamos a agregar el siguiente código en el app.component.ts solo como dummy:

config = {
    hasAllCheckBox: true,
    hasFilter: true,
    hasCollapseExpand: true,
    decoupleChildFromParent: false,
    maxHeight: 500,
    hasDivider: true,
}

items: TreeviewItem[]

Y con esto ya tenemos algo así como una base de filtrados, ahora agregemos algunos “directorios y archivos” (obvio falsos).

Para esto, creamos el constructor en nuestro componente y ponemos:

constructor() {
    this.items = [new TreeviewItem({
      text: 'ide', value: 1, collapsed: true, disabled: false, children: [
        {text: '.angular', value: 11},
        {text: 'node_modules', value: 12},
        {text: 'src', value: 13},
        {text: 'package.json', value: 14},
      ]
    })];
}

Obvio, ocupamos el import de TreeViewItem así que no lo olvides poner hasta arriba:

import {TreeviewItem} from "ngx-treeview";

Ahora, en nuestro style.css vamos a poner el siguiente estilo básico:

body { margin: 0; padding: 0 }

Y vamos a cambiar el app.component.html por el siguiente (ignoren los estilos en línea, luego los limpiamos en otra parte):

<div style="display: flex;">
  <div style="width: 200px;">
    <ngx-treeview
      [config]="config"
      [items]="items"
    >
    </ngx-treeview>
  </div>
  <div style="width: calc(100% - 200px);">
    <ngx-monaco-editor [options]="editorOptions" [(ngModel)]="code"></ngx-monaco-editor>
  </div>
</div>

Listo, ya tenemos un falso listado de directorios y el editor a un costado.

Antes de ir al último paso, quiero agregar que la librería de ngx-treeview usa Bootstrap, pero meter Bootstrap aquí no es viable, así que luego les paso unos estilos para que se acomode todo de la mejor manera.

Por último ahora sí vamos a agregar algunas pestañas…

Para esto vamos a usar la librería de ngx-tiny/tabs la cual instalamos:

npm install @ngx-tiny/tabs --save --legacy-peer-deps

Tampoco tiene soporte Angular 14 esta versión (o Angular 10+) así que instalamos con legacy y mismo caso, importamos:

import { NgxTabsModule } from '@ngx-tiny/tabs';
...
imports: [
   ...
   NgxTabsModule
   ...
]

Por último en nuestro app.component.html agregamos lo siguiente:

<div style="display: flex;">
  <div style="width: 200px;">
    <ngx-treeview
      [config]="config"
      [items]="items"
    >
    </ngx-treeview>
  </div>
  <div style="width: calc(100% - 200px);">
    <ngx-tabs>
      <ngx-tab [active]="true" name="source.ts">
        <ngx-monaco-editor [options]="editorOptions" [(ngModel)]="code"></ngx-monaco-editor>
      </ngx-tab>
      <ngx-tab name="index.html">
        <ngx-monaco-editor [options]="editorOptions2" [(ngModel)]="code2"></ngx-monaco-editor>
      </ngx-tab>
      <ngx-tab name="style.css">
        <ngx-monaco-editor [options]="editorOptions3" [(ngModel)]="code3"></ngx-monaco-editor>
      </ngx-tab>
    </ngx-tabs>
  </div>
</div>

Hasta aquí si guardas no verás nada más que errores y posibles fallos… para ello vamos a crear varios códigos y varios “editorOptions”…Por lo tanto hay que modificar el app.component.ts para agregarlos de la siguiente forma:

editorOptions = {
    theme: 'vs-dark',
    language: 'typescript',
    automaticLayout: true
};
editorOptions2 = {
    theme: 'vs-dark',
    language: 'html',
    automaticLayout: true
};
editorOptions3 = {
    theme: 'vs-dark',
    language: 'css',
    automaticLayout: true
};
code = 'function x() {\nconsole.log("Hello world!");\n}';
code2 = '<h1>Hello world</h1>';
code3 = 'h1 { color: red; }';

Nota que modificamos editorOptions original y agregamos automaticLayout esto es porque explícitamente, Monaco no sabe el tamaño del viewport (o “tamaño de la ventana” por traducirlo burdamente) y por ello requerimos esa configuración.

La idea es que cada editor tenga “sus configuraciones” pero haya algunas globales, esto ya lo veremos después. Y hasta aquí veríamos algo como lo siguiente:

Bastante feo, pero funcional… ¿por qué? porque pues podemos cambiar entre pestañas, podemos ver el código en cada una y podemos ver el nuestro intento chafa de listado de directorios y archivos.

En el siguiente tutorial, vamos a trabajar la cuestión del backend. Así poder conectar nuestro IDE y leer archivos, directorios, crearlos, actualizarlos, así que chécalo:

¿Cuál es tu reacción?
+1
0
+1
0
+1
0
+1
0
+1
2
Total
0
Shares
Publicación anterior

CodeIgniter se modernizó

Siguiente Publicación

Creando mi propio IDE con Angular y Node – Parte 2

Publicaciones Relacionadas