[safe-html-react-parser] Replace isomorphic-dompurify with custom implementation supporting flexible DOM libraries#203
Conversation
… wrapper Replace isomorphic-dompurify dependency with a custom implementation using dompurify + jsdom directly for better control and optimization. Changes: - Add src/utils/dompurify.ts with OptimizedDOMPurify class - Implement LRU cache (default 100 entries) for sanitized HTML - Add periodic JSDOM instance recreation (default every 1000 calls) - Update dependencies: isomorphic-dompurify → dompurify + jsdom Benefits: - Better memory management with configurable cache and recreation interval - Improved performance through result caching - More control over server-side sanitization behavior
…support (jsdom, happy-dom, linkeddom)
✅ Changeset detectedLatest commit: 3a166d5
If no version change is needed, please add The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
|
NPM Packages📦 @naverpay/safe-html-react-parserTotal Sizes: 4.57 kB Total Changes: +2.99 kB (+190%) 🔍 (Size Increased)
🧩 Dependency Changes
powered by: naverpay size-action |
Replace isomorphic-dompurify with a custom implementation that supports flexible DOM libraries.
|
/canary-publish |
|
No changed files exist under the . path, no packages have been deployed. |
|
? |
I’m sorry, this is my fault. Please take a look at this: #204 😓 |
|
/canary-publish |
Published Canary Packages |
|
Oh, I saw this issue late. Thank you!! |
|
/canary-publish |
Published Canary Packages |
There was a problem hiding this comment.
How about serializing the Node to use it as a key? It seems like if there are different objects with the same content, they would be referenced by different keys. If that’s what you intended, please disregard this message.
| if (global.gc && typeof global.gc === 'function') { | ||
| global.gc() | ||
| } |
There was a problem hiding this comment.
You’re only planning to use it when the –expose-gc option is available, right?
There was a problem hiding this comment.
That's correct. The use of global.gc() is only intended for server-side environments where the --expose-gc option is available. This is mainly to support scenarios where the package is used on the server, especially since it's open source and may be integrated in various environments.
| function getSanitizer(options?: SanitizerOptions) { | ||
| if (!instance) { | ||
| instance = new OptimizedDOMPurify(options) | ||
| } | ||
| return instance | ||
| } |
There was a problem hiding this comment.
Using a singleton object, it seems you won’t be able to use different settings within a single application.
There was a problem hiding this comment.
That's correct. The current implementation uses a singleton, so only one global configuration is supported per process.
This design was chosen to minimize memory usage and complexity (as written in the description), especially for server-side scenarios. If there’s a need to support multiple configurations at the same time, I'm open to considering multi-instance support in the future.
|
Thanks for the great review! Merging 🚀 |

Related Issue
#202
Summary
Replace
isomorphic-dompurifydependency with a custom DOMPurify implementation that supports user-chosen DOM libraries (jsdom, happy-dom, or linkedom) for better flexibility and performance optimization.Motivation
isomorphic-dompurifyhas limited flexibility and no built-in memory managementChanges
src/utils/dompurify.tswithOptimizedDOMPurifyclassjsdom- most complete, heavier (for maximum compatibility)happy-dom- fast, lighter, recommended for balanced performancelinkedom- fastest, minimal footprint (for performance-critical apps)jsdomto optionalpeerDependencieshappy-domandlinkedomas optionalpeerDependenciesdompurifyandhtml-react-parserin main dependencieswindow(no configuration needed)configureDOMPurify()or per-call optionsdomPurifyOptionstoSafeParseOptionsfor per-call configurationconfigureDOMPurify()functionMigration Guide
For server-side rendering, install one of the DOM implementations:
Then configure at app initialization:
Or use per-call options:
Performance Benefits