Skip to content

Commit a352097

Browse files
authored
Merge pull request #236 from vinta/chore/explore-ideas
Chore/explore ideas
2 parents b0b329d + 8228532 commit a352097

16 files changed

+1192
-228
lines changed

.claude/TODO.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,28 @@
2525

2626
## In Progress
2727

28-
- [ ] None currently
28+
- [ ] None
2929

3030
## Next Steps
3131

32-
### High Priority - Features
32+
### High Priority
3333

34-
- [ ] Provide a less aggressive approach: `text-autospace` in CSS
35-
- https://developer.chrome.com/blog/css-i18n-features
36-
- https://github.com/sparanoid/chinese-copywriting-guidelines/issues/211
34+
- [ ] Generate different size icons from `icon_1500.svg`
35+
- [ ] Add a button for "Add this url to blacklist" in popup page or context menu
3736

38-
### Medium Priority - Code Quality
37+
### Medium Priority
3938

40-
- [ ] Generate different size icons from `icon_1500.svg`
41-
- [ ] Improve Chrome API error handling with retry logic
42-
- [ ] Create optimized content script bundle to reduce memory footprint
43-
- [ ] Update declarativeContent for action button state
39+
- [ ] No need to perform spacing if there is no CJK in webpages
40+
- See @.claude/researches/detect-cjk-content.md
41+
- [ ] Improve `autoSpacingPage()` performance, especially with a large DOM tree
42+
- See @.claude/researches/performance-optimization.md
43+
- [ ] Add instructions in options page for enabling experimental CSS `text-autospace`
44+
- Guide users to `chrome://flags/#enable-experimental-web-platform-features`
45+
- Auto-detect and use CSS text-autospace when available
46+
- Provide clear benefits explanation (better performance, native spacing)
4447

4548
### Low Priority - Future Enhancements
4649

47-
- [ ] Add "之後不要在這個網頁召喚空格之神了" to popup actions or context menu
48-
- [ ] Add `optional_host_permissions` for user control
4950
- [ ] Use Verified CRX uploads
5051
- [ ] Implement tree-shaking optimizations
5152
- [ ] Publish to JSR (JavaScript Registry)
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# Content Script Memory Optimization
2+
3+
## Current State Analysis
4+
5+
### File Structure
6+
- `vendors/pangu/pangu.umd.js` (18KB uncompressed, 4.2KB gzipped) - Main pangu library
7+
- `dist/content-script.js` (712B uncompressed, 350B gzipped) - Thin wrapper
8+
- **Total**: ~18.7KB uncompressed, ~4.5KB gzipped
9+
10+
### Memory Issues
11+
1. **Always Loaded**: Both files injected on every matching page, regardless of CJK content
12+
2. **Persistent Memory**: Library stays in memory for page lifetime
13+
3. **Continuous Monitoring**: MutationObserver runs indefinitely, even without CJK
14+
4. **Unused Code**: Bundle includes methods never used by content script:
15+
- `spacingNode()`
16+
- `spacingElementById()`
17+
- `spacingElementByClassName()`
18+
- `spacingElementByTagName()`
19+
- `spacingPageTitle()`
20+
- `spacingPageBody()`
21+
22+
## Optimization Strategies
23+
24+
### 1. Lazy Loading with CJK Detection (Highest Impact)
25+
26+
```javascript
27+
// Minimal content-script.js (~500 bytes)
28+
async function initPangu() {
29+
// Quick CJK detection first
30+
if (!document.title.match(/[\u2e80-\u9fff]/) &&
31+
!document.body.textContent.substring(0, 1000).match(/[\u2e80-\u9fff]/)) {
32+
console.log('No CJK content detected, skipping pangu.js load');
33+
return;
34+
}
35+
36+
// Load pangu.js only when needed
37+
const script = document.createElement('script');
38+
script.src = chrome.runtime.getURL('vendors/pangu/pangu.umd.js');
39+
script.onload = () => {
40+
window.pangu.autoSpacingPage();
41+
};
42+
document.head.appendChild(script);
43+
}
44+
45+
initPangu();
46+
```
47+
48+
**Benefits**:
49+
- Saves ~18KB per non-CJK page
50+
- Reduces memory usage on ~90% of Western websites
51+
52+
### 2. Create Minimal Bundle
53+
54+
Build a custom bundle with only required functionality:
55+
56+
```javascript
57+
// pangu-minimal.js
58+
export class PanguMinimal {
59+
constructor() {
60+
// Include only essential regex patterns
61+
this.convertToFullwidthPattern = /.../ // Only patterns actually used
62+
}
63+
64+
// Only include these methods:
65+
spacingText(text) { /* ... */ }
66+
spacingPage() { /* ... */ }
67+
autoSpacingPage() { /* ... */ }
68+
69+
// Remove all other methods
70+
}
71+
```
72+
73+
**Benefits**:
74+
- Estimated 30-40% size reduction
75+
- Faster parsing and initialization
76+
77+
### 3. Smart MutationObserver Management
78+
79+
```javascript
80+
class MemoryOptimizedPangu extends BrowserPangu {
81+
private observer?: MutationObserver;
82+
private inactivityTimer?: number;
83+
private mutationCount = 0;
84+
85+
autoSpacingPage() {
86+
super.autoSpacingPage();
87+
this.startInactivityTimer();
88+
}
89+
90+
private startInactivityTimer() {
91+
// Stop observing after 30 seconds of no mutations
92+
this.inactivityTimer = setTimeout(() => {
93+
this.observer?.disconnect();
94+
console.log('Pangu: Stopped observing due to inactivity');
95+
}, 30000);
96+
}
97+
98+
private onMutation() {
99+
this.mutationCount++;
100+
101+
// Reset timer on activity
102+
clearTimeout(this.inactivityTimer);
103+
this.startInactivityTimer();
104+
105+
// Stop after processing many mutations (likely infinite loop)
106+
if (this.mutationCount > 1000) {
107+
this.observer?.disconnect();
108+
console.log('Pangu: Stopped observing due to excessive mutations');
109+
}
110+
}
111+
}
112+
```
113+
114+
### 4. Dynamic Script Injection via Service Worker
115+
116+
```javascript
117+
// content-script-detector.js (1KB) - Always loaded
118+
function checkAndRequestPangu() {
119+
const quickCheck = document.body.textContent.substring(0, 1000);
120+
if (/[\u2e80-\u9fff]/.test(quickCheck)) {
121+
chrome.runtime.sendMessage({ action: 'injectPangu' });
122+
}
123+
}
124+
125+
// Only check once DOM is ready
126+
if (document.readyState === 'loading') {
127+
document.addEventListener('DOMContentLoaded', checkAndRequestPangu);
128+
} else {
129+
checkAndRequestPangu();
130+
}
131+
132+
// service-worker.js
133+
chrome.runtime.onMessage.addListener((request, sender) => {
134+
if (request.action === 'injectPangu') {
135+
chrome.scripting.executeScript({
136+
target: { tabId: sender.tab.id },
137+
files: ['vendors/pangu/pangu.umd.js', 'content-script-init.js']
138+
});
139+
}
140+
});
141+
```
142+
143+
### 5. Progressive Enhancement
144+
145+
```javascript
146+
// Load different bundles based on page complexity
147+
async function loadPanguProgressive() {
148+
const textNodeCount = document.evaluate(
149+
'//text()', document, null,
150+
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
151+
).snapshotLength;
152+
153+
if (textNodeCount < 100) {
154+
// Load minimal version for simple pages
155+
await loadScript('pangu-minimal.js');
156+
} else if (textNodeCount < 1000) {
157+
// Load standard version
158+
await loadScript('pangu-standard.js');
159+
} else {
160+
// Load optimized version with batching for complex pages
161+
await loadScript('pangu-heavy.js');
162+
}
163+
}
164+
```
165+
166+
### 6. Memory Cleanup on Page Unload
167+
168+
```javascript
169+
// Ensure cleanup on page navigation
170+
window.addEventListener('pagehide', () => {
171+
if (window.pangu?.observer) {
172+
window.pangu.observer.disconnect();
173+
}
174+
window.pangu = null;
175+
}, { once: true });
176+
```
177+
178+
## Implementation Priority
179+
180+
1. **High Priority**: Lazy loading with CJK detection
181+
- Biggest impact, easiest to implement
182+
- Saves memory on majority of non-CJK pages
183+
184+
2. **Medium Priority**: Create minimal bundle
185+
- Requires build process changes
186+
- Good long-term optimization
187+
188+
3. **Medium Priority**: Smart MutationObserver management
189+
- Prevents runaway memory usage
190+
- Improves performance on dynamic pages
191+
192+
4. **Low Priority**: Progressive enhancement
193+
- Complex to implement
194+
- Benefits only specific use cases
195+
196+
## Expected Results
197+
198+
Implementing lazy loading alone would:
199+
- Reduce memory usage by ~18KB on non-CJK pages
200+
- Eliminate unnecessary CPU usage from MutationObserver
201+
- Improve extension performance metrics
202+
- Maintain full functionality for CJK pages
203+
204+
Combined optimizations could achieve:
205+
- 50-70% memory reduction on non-CJK pages
206+
- 30-40% reduction even on CJK pages
207+
- Better performance on low-end devices
208+
- Improved battery life on mobile devices

0 commit comments

Comments
 (0)