8000 refactor: remove `AsyncPipe` to reduce bundle size by arturovt · Pull Request #578 · jfcere/ngx-markdown · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

refactor: remove AsyncPipe to reduce bundle size #578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 31, 2025

Conversation

arturovt
Copy link
Contributor
@arturovt arturovt commented Apr 4, 2025

This commit removes the AsyncPipe from the bundle and replaces its usage with signals (currently the primary communication mechanism with the view in Angular).

Use case: We're using ngx-markdown, but not using AsyncPipe directly. However, it’s still being included in the initial bundle due to its usage within ngx-markdown.

This commit removes the `AsyncPipe` from the bundle and replaces its usage with signals (currently the primary communication mechanism with the view in Angular).

**Use case:** We're using `ngx-markdown`, but not using `AsyncPipe` directly. However, it’s still being included in the initial bundle due to its usage within `ngx-markdown`.
@midzer
Copy link
midzer commented May 29, 2025

Would be cool to see this landed.

Signals became fully stable in v20: "Promoting reactivity features to stable" https://blog.angular.dev/announcing-angular-v20-b5c9c06cf301#0665

@arturovt
Copy link
Contributor Author

@midzer if you need a quick fix, you can use patch-package, here's patches/ngx-markdown+19.1.0.patch:

Diff
diff --git a/node_modules/ngx-markdown/fesm2022/ngx-markdown.mjs b/node_modules/ngx-markdown/fesm2022/ngx-markdown.mjs
index c3194b6..f1392bf 100644
--- a/node_modules/ngx-markdown/fesm2022/ngx-markdown.mjs
+++ b/node_modules/ngx-markdown/fesm2022/ngx-markdown.mjs
@@ -1,8 +1,9 @@
-import { AsyncPipe, isPlatformBrowser, CommonModule } from '@angular/common';
 import * as i0 from '@angular/core';
-import { Component, ChangeDetectionStrategy, InjectionToken, Pipe, PLATFORM_ID, Injectable, Inject, Optional, EventEmitter, Input, Output, SecurityContext, NgModule } from '@angular/core';
+import { computed, Component, ChangeDetectionStrategy, InjectionToken, Pipe, PLATFORM_ID, Injectable, Inject, Optional, EventEmitter, Input, Output, SecurityContext, NgModule } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
 import { Subject, merge, of, timer } from 'rxjs';
-import { switchMap, mapTo, distinctUntilChanged, shareReplay, startWith, map, takeUntil, first } from 'rxjs/operators';
+import { switchMap, mapTo, distinctUntilChanged, shareReplay, map, takeUntil, first } from 'rxjs/operators';
+import { isPlatformBrowser } from '@angular/common';
 import { Renderer, marked } from 'marked';
 export { Renderer as MarkedRenderer } from 'marked';
 import * as i1 from '@angular/common/http';
@@ -13,10 +14,11 @@ const BUTTON_TEXT_COPIED = 'Copied';
 class ClipboardButtonComponent {
     constructor() {
         this._buttonClick$ = new Subject();
-        this.copied$ = this._buttonClick$.pipe(switchMap(() => merge(of(true), timer(3000).pipe(mapTo(false)))), distinctUntilChanged(), shareReplay(1));
-        this.copiedText$ = this.copied$.pipe(startWith(false), map(copied => copied
-            ? BUTTON_TEXT_COPIED
-            : BUTTON_TEXT_COPY));
+        this.copied = toSignal(this._buttonClick$.pipe(switchMap(() => merge(of(true), timer(3000).pipe(mapTo(false)))), distinctUntilChanged(), shareReplay(1)));
+        this.copiedText = computed(() => {
+            const copied = this.copied();
+            return copied ? BUTTON_TEXT_COPIED : BUTTON_TEXT_COPY;
+        });
     }
     onCopyToClipboardClick() {
         this._buttonClick$.next();
@@ -25,10 +27,10 @@ class ClipboardButtonComponent {
     static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.0", type: ClipboardButtonComponent, isStandalone: true, selector: "markdown-clipboard", ngImport: i0, template: `
     <button
       class="markdown-clipboard-button"
-      [class.copied]="copied$ | async"
+      [class.copied]="copied()"
       (click)="onCopyToClipboardClick()"
-    >{{ copiedText$ | async }}</button>
-  `, isInline: true, dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
+    >{{ copiedText() }}</button>
+  `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
 }
 i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: ClipboardButtonComponent, decorators: [{
             type: Component,
@@ -37,12 +39,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
                     template: `
     <button
       class="markdown-clipboard-button"
-      [class.copied]="copied$ | async"
+      [class.copied]="copied()"
       (click)="onCopyToClipboardClick()"
-    >{{ copiedText$ | async }}</button>
+    >{{ copiedText() }}</button>
   `,
                     changeDetection: ChangeDetectionStrategy.OnPush,
-                    imports: [AsyncPipe],
                 }]
         }] });
 
@@ -222,7 +223,7 @@ class MarkdownService {
             .pipe(map(markdown => this.handleExtension(src, markdown)));
     }
     highlight(element) {
-        if (!isPlatformBrowser(this.platform)) {
+        if (ngServerMode) {
             return;
         }
         if (typeof Prism === 'undefined' || typeof Prism.highlightAllUnder === 'undefined') {
@@ -236,7 +237,7 @@ class MarkdownService {
         Prism.highlightAllUnder(element);
     }
     decodeHtml(html) {
-        if (!isPlatformBrowser(this.platform)) {
+        if (ngServerMode) {
             return html;
         }
         const textarea = document.createElement('textarea');
@@ -302,7 +303,7 @@ class MarkdownService {
             : marked.parse(html, markedOptions);
     }
     parseEmoji(html) {
-        if (!isPlatformBrowser(this.platform)) {
+        if (ngServerMode) {
             return html;
         }
         if (typeof joypixels === 'undefined' || typeof joypixels.shortnameToUnicode === 'undefined') {
@@ -311,7 +312,7 @@ class MarkdownService {
         return joypixels.shortnameToUnicode(html);
     }
     renderKatex(element, options) {
-        if (!isPlatformBrowser(this.platform)) {
+        if (ngServerMode) {
             return;
         }
         if (typeof katex === 'undefined' || typeof renderMathInElement === 'undefined') {
@@ -320,7 +321,7 @@ class MarkdownService {
         renderMathInElement(element, options);
     }
     renderClipboard(element, viewContainerRef, options) {
-        if (!isPlatformBrowser(this.platform)) {
+        if (ngServerMode) {
             return;
         }
         if (typeof ClipboardJS === 'undefined') {
@@ -381,7 +382,7 @@ class MarkdownService {
         }
     }
     renderMermaid(element, options = this.DEFAULT_MERMAID_OPTIONS) {
-        if (!isPlatformBrowser(this.platform)) {
+        if (ngServerMode) {
             return;
         }
         if (typeof mermaid === 'undefined' || typeof mermaid.initialize === 'undefined') {
@@ -773,19 +774,19 @@ class MarkdownModule {
         };
     }
     static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MarkdownModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
-    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.0", ngImport: i0, type: MarkdownModule, imports: [CommonModule, ClipboardButtonComponent,
+    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.0", ngImport: i0, type: MarkdownModule, imports: [ClipboardButtonComponent,
             LanguagePipe,
             MarkdownComponent,
             MarkdownPipe], exports: [ClipboardButtonComponent,
             LanguagePipe,
             MarkdownComponent,
             MarkdownPipe] }); }
-    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MarkdownModule, imports: [CommonModule] }); }
+    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MarkdownModule }); }
 }
 i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: MarkdownModule, decorators: [{
             type: NgModule,
             args: [{
-                    imports: [CommonModule, ...sharedDeclarations],
+                    imports: sharedDeclarations,
                     exports: sharedDeclarations,
                 }]
         }] });

@midzer
Copy link
midzer commented May 30, 2025

@arturovt Thanks, but I don't have this file on my system:

(...)/node_modules/ngx-markdown$ ls
LICENSE  node_modules  package.json  README.md

@jfcere jfcere changed the base branch from master to remove-async-pipe May 31, 2025 01:11
@jfcere
Copy link
Owner
jfcere commented May 31, 2025

Hi @arturovt,

Thanks for the PR. It will be merged into a temporary branch before being merged into the master branch so I can...

  • Merge it with changes for Angular 20
  • Do some minor changes
  • Keep credits from the original PR author

@jfcere jfcere merged commit 333adcc into jfcere:remove-async-pipe May 31, 2025
1 check failed
jfcere added a commit that referenced this pull request May 31, 2025
* refactor: remove `AsyncPipe` to reduce bundle size (#578)

---------

Co-authored-by: Artur <arthurandrosovich@gmail.com>
@arturovt arturovt deleted the refactor/remove-async branch June 22, 2025 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0