"News article 가리키면 ClipDeck 이 headline, byline, body 빼냄 — 광고 없음, related post 없음, 쿠키 배너 없음. Lesson 2 가 Mozilla 의 Readability.js 를 content script 에 wire 해서 '전체 article 저장' 이 single 버튼 됨."
Readability.js, 솔직하게
github.com/mozilla/readability 가 Firefox 의 Reader Mode 동작시키는 JavaScript library. 같은 engine, MPL-licensed, 사용에 Firefox 필요 없음. Shape:
- Input: cloned
document.document직접 전달 안 함 — Readability 가 받은 tree mutate, user 가 읽는 page mutate 원치 않음. - Output:
{ title, byline, dir, content, textContent, length, excerpt, siteName, lang }.content가 sanitized HTML;textContent가 plain text. - 비용: 약 50 KB minified. Content script 에 fit. Typical article parse 에 50–100 ms 정도 추가.
Vendor vs Bundle
ClipDeck 와 Readability ship 하는 두 합리적 방법:
- Vendor: GitHub release 에서
Readability.js다운,clipdeck/vendor/Readability.js에 drop,content_scripts.js배열에content.jsBEFORE 선언. Library 가 globalReadability노출. 단순. Auditable. - Bundle:
npm install @mozilla/readability, TS/JS source 에서 import, esbuild/Rollup 로 single content.js 로 bundle. 장기적으로 더 깔끔. Tree-shaking 이나 TypeScript 원하면 필수.
ClipDeck v1 vendor. Track 8 에서 bundling 으로 이동.
Cloning trick
표준 주문:
const documentClone = document.cloneNode(true);
const reader = new Readability(documentClone);
const article = reader.parse();
document.cloneNode(true) 가 deep copy 생성. Readability 가 article 아니라고 판단하는 모든 것 (nav, sidebar, footer, comment, 광고) 을 그 node 들 clone 에서 물리적 제거. User 의 page 안 만짐.
Result read
흔한 field:
title— article title, 정리됨. 종종document.title이 가지는 site-name suffix 빠짐.byline— author. Best-effort; 작은 블로그에선 종종 null.content— sanitized HTML. Extension iframe 에 렌더 안전; user 의 page 에 inject 전엔 여전히 DOMPurify 같은 sanitizer 통과.textContent—content의 plain text 버전. 깔끔한 text 저장 원하면 ClipDeck 에 이거; heading/paragraph 구조 보존 원하면content.length—textContent의 글자 수. 추출 sanity-check 에 유용 (매우 짧음 = 아마 실패).excerpt— 첫 문단 정도. Preview 에 좋음.siteName,lang,dir— metadata.
reader.parse() 가 null 반환하면 Readability 가 page 가 article-shape 아니라고 결정 (너무 짧음, 너무 어수선, 명확한 main content 없음). Selection 있으면 그것으로 fallback, 아니면 page title + URL 로 context.
ClipDeck 'Save Full Article' action
Selection-save 와 별도 trigger 로 wire:
- Popup 버튼: "Save full article from this page."
- 키보드 단축키 option (free combo 있으면).
contexts: ['page']가진 context menu item: "Save this page to ClipDeck."
Handler 가 content script 에 {type: 'readArticle'} 로 메시지; content script 가 Readability 돌리고 article object 반환; SW 가 article 텍스트, flag isArticle: true, URL + title 가진 clip 만듬 — selection clip 과 같은 shape, body 만 더 많음.
Performance note
Readability 가 대부분 page 에서 십 밀리초 단위, 거대한 거 (긴 Wikipedia article, 보관된 forum thread) 엔 몇 백 ms 까지. Content script 의 main thread 안에서 돌리기; user 안 알아챔. Parse 동안 page responsive 유지 필요하면 Web Worker 에 offload 가능하지만, click 당 one-shot 엔 overkill.