Markdown syntax highliting glitch
Overview:
The changes refactor the integration of Prism.js for syntax highlighting, moving from a dynamic, lazy-loading approach to static imports. This enhances Server-Side Rendering (SSR) compatibility, simplifies the highlighting logic, and introduces a new, highly customized theme based on prism-okaidia.css
to improve the visual presentation of code blocks.
Explanation:
1. Global Styling & Theme Overhaul (angular.json
, src/styles.scss
, message-bubble.component.ts
)
- Theme Switch: The
angular.json
file now includesnode_modules/prismjs/themes/prism-okaidia.css
in the globalstyles
array. This means the application will now use the Okaidia theme as its base for code highlighting. This change is mirrored insrc/styles.scss
, where the previousprism.css
import is replaced byprism-okaidia.css
. - Centralized & Customizable Styling: The extensive custom CSS rules in
src/styles.scss
are introduced to override and enhance the Okaidia theme. This includes new CSS variables for colors (e.g.,--prism-background
,--prism-keyword
), font family adjustments (like adding 'Fira Code' for ligatures), and fine-tuning spacing and borders. This approach centralizes the styling for Prism.js, making it easier to manage and modify. - Component Styling Removal: Correspondingly, the inline
<style>
block inmessage-bubble.component.ts
has had itspre
andcode
specific styling removed. This is because the globalprism-okaidia.css
and the custom overrides instyles.scss
now handle the base styling for code blocks, reducing redundancy and improving modularity.
2. Simplified Highlighting Logic (message-bubble.component.ts
)
- Synchronous Highlighting: The
highlightCode
method inMessageBubbleComponent
is no longerasync
and directly callsthis.prismService.highlightElement
. The loop iterating overcodeBlocks
no longer usesawait
. This change is a direct result of thePrismService
no longer performing asynchronous loading of Prism.js (see next point). - Immediate Highlighting on Markdown Ready: The
onMarkdownReady
lifecycle hook now callsthis.highlightCode()
directly, removing thesetTimeout(..., 0)
wrapper. This suggests thatngx-markdown
's event now reliably fires after the markdown content has been rendered into the DOM, making immediate synchronous highlighting possible without deferring to the next tick.
3. Prism.js Service Refactor & SSR Compatibility (prism.service.ts
)
- Static Imports: The
PrismService
has been fundamentally changed. The previous dynamicloadPrism()
andloadLanguageComponents()
methods, which usedawait import()
to lazy-load Prism.js and its language components at runtime, have been removed. Instead, Prism core (import 'prismjs';
) and a specific set of commonly used language components (e.g.,prism-typescript
,prism-javascript
,prism-json
) are now directly imported at the top of theprism.service.ts
file. This means Prism.js and its languages are bundled with the application at compile time.- Implication: This simplifies the service and ensures Prism is immediately available, but it increases the initial bundle size slightly as Prism and all imported languages are always included.
- SSR Compatibility: The service now injects
PLATFORM_ID
and usesisPlatformBrowser
from@angular/common
. All calls toPrism.highlightElement
andPrism.highlightAll
are guarded byif (this.isBrowser)
. This is a critical improvement for Server-Side Rendering (SSR) support, as Prism.js is a client-side library that relies on browser DOM APIs. By performing these checks, the application prevents errors when attempting to render on the server, ensuring a smoother universal rendering experience. - Synchronous Methods: The
highlightElement
andhighlightAll
methods are now synchronous, reflecting the fact that Prism is already loaded and available due to the static imports.
4. Dependency Downgrades (package.json
, package-lock.json
)
- Minor version downgrades for
marked
,ngx-markdown
,prismjs
, and@types/prismjs
are observed. For example,prismjs
was downgraded from^1.30.0
to^1.29.0
. While generally minor, downgrades are less common than upgrades and usually indicate a specific compatibility issue or a deliberate choice to align with a known stable version of these libraries within the project's ecosystem.
Best Practices:
- SSR Awareness: Using
PLATFORM_ID
andisPlatformBrowser
is a standard and crucial best practice for ensuring client-side libraries function correctly and avoid errors in an Angular Universal (SSR) environment. - Modular Styling: Centralizing third-party library styles in global stylesheets and using CSS variables for theming promotes maintainability and easier theme management.
- Readiness for External Libraries: The change in
onMarkdownReady
fromsetTimeout
to direct call indicates improved understanding or guarantees of the timing of DOM readiness fromngx-markdown
, leading to more robust and immediate code highlighting.
Suggestions:
- Document Dependency Downgrades: For the minor version downgrades of
marked
,ngx-markdown
,prismjs
, and@types/prismjs
, it would be beneficial to add a comment in the commit message or project documentation explaining the reason. This prevents future developers from re-introducing potential issues by upgrading back to those specific versions. - Consider Granularity of Prism Imports: While static imports simplify the service, if this application were to grow significantly and only a few specific code languages were consistently highlighted, a more granular import approach (e.g., loading only
prism-typescript
if only TS code is expected) could further optimize bundle size. However, for a chat application that might display various code types, the current broad import list is practical.