Primero, configuraremos el componente <markdown-render>
para renderizar archivos .md.
Y luego veremos cómo renderizar componentes angulares.
Renderizador Markdown
Instalar las dependencias necesarias:
npm i highlight.js marked marked-highlight
Paso 1: Crear markdown-renderer/highlight-code-block.ts
Esta función se utilizará para resaltar el código en nuestro archivo markdown
import highlightJs from 'highlight.js';
export function highlightCodeBlock(code: string, language: string | undefined) {
if (language) {
return highlightJs.highlight(code, {
language,
}).value;
}
return code;
}
Paso 2: Crear markdown-renderer/transform-markdown.ts
Esta función se utilizará para convertir markdown a html
.
import { marked } from 'marked';
import { markedHighlight } from 'marked-highlight';
import { highlightCodeBlock } from './highlight-code-block';
marked.use(markedHighlight({ highlight: highlightCodeBlock }));
export const markdownToHtml = (content: string) => {
return marked(content);
};
Paso 3: Crear markdown-renderer/markdown.service.ts
Este servicio se utilizará en el componente para leer el archivo .md
desde una ubicación local o externa y luego convertirlo a html.
import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { map } from 'rxjs';
import { markdownToHtml } from './transform-markdown';
@Injectable({
providedIn: 'root',
})
export class MarkdownService {
private httpClient = inject(HttpClient);
htmlContent(src: string) {
return this.httpClient.get(src, { responseType: 'text' }).pipe(
map((markdownContent) => {
return markdownToHtml(markdownContent);
})
);
}
}
Paso 4: Crear markdown-renderer/markdown-renderer.ts
Finalmente, este será el componente que podremos usar para renderizar archivos markdown.
import { Component, ElementRef, effect, inject, input } from '@angular/core';
import { MarkdownService } from './markdown.service';
import { take } from 'rxjs';
import highlightJs from 'highlight.js';
@Component({
selector: 'markdown-renderer',
template: 'Loading document...',
standalone: true,
})
export class MarkdownRendererComponent {
src = input.required<string>();
textContent = '';
private _elementRef = inject<ElementRef>(ElementRef);
private markdownService = inject(MarkdownService);
constructor() {
effect(() => {
const src = this.src();
this.setDataFromSrc(src);
});
}
setDataFromSrc(src: string) {
this.markdownService
.htmlContent(src)
.pipe(take(1))
.subscribe((htmlContent) => {
this.updateDocument(htmlContent as string);
});
}
updateDocument(rawHTML: string) {
this._elementRef.nativeElement.innerHTML = rawHTML;
this.textContent = this._elementRef.nativeElement.textContent;
highlightJs.highlightAll();
}
}
Paso 5: Proporcionar HTTP
bootstrapApplication(App, {
providers: [
provideHttpClient(withFetch())
],
});
Paso 6: Uso
Ahora, siempre que queramos renderizar markdown, simplemente usaremos <markdown-renderer>
:
import { Component } from '@angular/core';
import { MarkdownRendererComponent } from './markdown-renderer/markdown-renderer';
@Component({
selector: 'article',
standalone: true,
template: `<markdown-renderer src="/assets/article.md"></markdown-renderer>`,
imports: [MarkdownRendererComponent],
})
export class ArticleComponent {}
Componentes Angular en Markdown
Instale las dependencias necesarias:
npm i @angular/elements
Paso 1: Crear custom-elements.service.ts
Este servicio se utilizará para convertir los componentes angulares en elementos personalizados, de modo que podamos utilizar fácilmente los componentes angulares en el archivo .md.
import { inject, Injectable, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { SubscribeComponent } from './components/subscribe';
import { CounterComponent } from './components/counter';
@Injectable({ providedIn: 'root' })
export class CustomElementsService {
private _injector = inject(Injector);
setupCustomElements() {
const subscribeElement = createCustomElement(SubscribeComponent, {
injector: this._injector,
});
customElements.define('subscribe-component', subscribeElement);
const counterElement = createCustomElement(CounterComponent, {
injector: this._injector,
});
customElements.define('counter-component', counterElement);
}
}
Paso 2: Llamar a setupCustomElements a través de APP_INITIALIZER
Como queremos que los elementos personalizados estén presentes desde la inicialización, utilizaremos APP_INITIALIZER
.
bootstrapApplication(App, {
providers: [
provideHttpClient(withFetch()),
{
provide: APP_INITIALIZER,
useFactory: initializeCustomElements,
multi: true,
deps: [CustomElementsService],
},
],
});
Paso 3: Uso
Por último, sólo tiene que utilizar su elemento personalizado en el archivo .md
para que se muestre el componente angular, como se muestra a continuación:
<subscribe-component></subscribe-component>
<counter-component></counter-component>
Código
Espero que puedas llevar a la práctica lo leído. Nos vemos en el siguiente blog.