refactor(markdown): konsolidasi polyfill nodeCompat & hapus dependency dompurify
- CLN-01: Verifikasi dan konsolidasi polyfill worker_threads.markAsUncloneable ke helper nodeCompat.ts - CLN-01: Dokumentasi mekanisme require-time (node-polyfill.cjs) vs import-time (nodeCompat.ts) - CLN-02: Hapus dependency dompurify dan @types/dompurify yang tidak terpakai dari package.json - Verifikasi seluruh test suite (13 test files, 165 tests) tetap 100% lulus
This commit is contained in:
parent
2d557df061
commit
9087a77096
|
|
@ -1,4 +1,11 @@
|
||||||
// Polyfill markAsUncloneable on node:worker_threads for Node 20 runtime compatibility (undici/jsdom)
|
/**
|
||||||
|
* Polyfill worker_threads.markAsUncloneable untuk Node 20 runtime compatibility (undici/jsdom).
|
||||||
|
*
|
||||||
|
* Catatan:
|
||||||
|
* File CJS ini dimuat via NODE_OPTIONS="--require /app/node-polyfill.cjs" di Docker runner
|
||||||
|
* (require-time sebelum entrypoint Node dievaluasi).
|
||||||
|
* Untuk penggunaan import-time di TypeScript/ESM, lihat src/lib/services/markdown/nodeCompat.ts.
|
||||||
|
*/
|
||||||
try {
|
try {
|
||||||
const wt = require('node:worker_threads');
|
const wt = require('node:worker_threads');
|
||||||
if (wt && typeof wt.markAsUncloneable === 'undefined') {
|
if (wt && typeof wt.markAsUncloneable === 'undefined') {
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,7 @@
|
||||||
"@codemirror/lang-markdown": "^6.3.0",
|
"@codemirror/lang-markdown": "^6.3.0",
|
||||||
"@codemirror/lang-python": "^6.1.0",
|
"@codemirror/lang-python": "^6.1.0",
|
||||||
"@codemirror/theme-one-dark": "^6.1.0",
|
"@codemirror/theme-one-dark": "^6.1.0",
|
||||||
"@types/dompurify": "^3.0.5",
|
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"dompurify": "^3.4.14",
|
|
||||||
"highlight.js": "^11.11.0",
|
"highlight.js": "^11.11.0",
|
||||||
"isomorphic-dompurify": "^3.23.0",
|
"isomorphic-dompurify": "^3.23.0",
|
||||||
"katex": "^0.16.9",
|
"katex": "^0.16.9",
|
||||||
|
|
@ -1575,15 +1573,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/dompurify": {
|
|
||||||
"version": "3.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz",
|
|
||||||
"integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/trusted-types": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.9",
|
"version": "1.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
|
||||||
|
|
@ -1619,6 +1608,7 @@
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/expect": {
|
"node_modules/@vitest/expect": {
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,7 @@
|
||||||
"@codemirror/lang-markdown": "^6.3.0",
|
"@codemirror/lang-markdown": "^6.3.0",
|
||||||
"@codemirror/lang-python": "^6.1.0",
|
"@codemirror/lang-python": "^6.1.0",
|
||||||
"@codemirror/theme-one-dark": "^6.1.0",
|
"@codemirror/theme-one-dark": "^6.1.0",
|
||||||
"@types/dompurify": "^3.0.5",
|
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"dompurify": "^3.4.14",
|
|
||||||
"highlight.js": "^11.11.0",
|
"highlight.js": "^11.11.0",
|
||||||
"isomorphic-dompurify": "^3.23.0",
|
"isomorphic-dompurify": "^3.23.0",
|
||||||
"katex": "^0.16.9",
|
"katex": "^0.16.9",
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,8 @@
|
||||||
* elemes-ts network namespace, so the backend lives on localhost.
|
* elemes-ts network namespace, so the backend lives on localhost.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Polyfill markAsUncloneable on node:worker_threads for Node 20 runtime compatibility (undici/jsdom)
|
import { patchWorkerThreadsCompat } from '$lib/services/markdown/nodeCompat';
|
||||||
try {
|
patchWorkerThreadsCompat();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
const wt = require('node:worker_threads');
|
|
||||||
if (wt && typeof wt.markAsUncloneable === 'undefined') {
|
|
||||||
wt.markAsUncloneable = () => {};
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
import type { Handle } from '@sveltejs/kit';
|
import type { Handle } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* Polyfill worker_threads.markAsUncloneable untuk kompatibilitas Node 20
|
||||||
|
* dengan isomorphic-dompurify/jsdom/undici.
|
||||||
|
*
|
||||||
|
* Root Cause:
|
||||||
|
* isomorphic-dompurify@3.23.0 -> jsdom@30.0.1 -> undici@8.10.0 memanggil
|
||||||
|
* `markAsUncloneable` dari `node:worker_threads`. Pada Node 20 runtime (v20.20.2),
|
||||||
|
* method ini belum ada (ditambahkan pada Node 22+), menyebabkan
|
||||||
|
* `TypeError: webidl.util.markAsUncloneable is not a function` saat SSR.
|
||||||
|
*
|
||||||
|
* Catatan:
|
||||||
|
* File ini adalah helper TypeScript/ESM (import-time). Terdapat juga salinan CJS di
|
||||||
|
* `frontend/node-polyfill.cjs` yang digunakan khusus untuk `NODE_OPTIONS="--require ..."`
|
||||||
|
* pada Docker container (require-time sebelum entrypoint Node).
|
||||||
|
*
|
||||||
|
* TODO: hapus polyfill ini kalau isomorphic-dompurify/jsdom sudah rilis versi
|
||||||
|
* yang kompatibel penuh dengan Node 20 tanpa markAsUncloneable, atau base image
|
||||||
|
* Docker sudah di-upgrade ke Node 22+.
|
||||||
|
*/
|
||||||
|
export function patchWorkerThreadsCompat(): void {
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
const wt = require('node:worker_threads');
|
||||||
|
if (wt && typeof wt.markAsUncloneable === 'undefined') {
|
||||||
|
wt.markAsUncloneable = () => {};
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore - bukan environment Node (misal di browser runtime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,5 @@
|
||||||
// Polyfill markAsUncloneable on node:worker_threads for Node 20 runtime compatibility (undici/jsdom)
|
import { patchWorkerThreadsCompat } from './nodeCompat';
|
||||||
try {
|
patchWorkerThreadsCompat();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
const wt = require('node:worker_threads');
|
|
||||||
if (wt && typeof wt.markAsUncloneable === 'undefined') {
|
|
||||||
wt.markAsUncloneable = () => {};
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
import DOMPurify from 'isomorphic-dompurify';
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue