-
Notifications
You must be signed in to change notification settings - Fork 2
Feature(extension): 익스텐션 윈도우 체류시간 측정 작업 #82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
Walkthrough크롬 확장 프로그램의 기능 확장과 구조 개선이 이루어졌습니다. manifest 권한이 확대되고, App 및 ModalPop 컴포넌트가 상태 기반으로 개선되었으며, background 스크립트가 추가되어 메시지 및 알림 처리를 담당합니다. 개발 환경 및 빌드 설정도 일부 수정되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App(Component)
participant ModalPop(Component)
participant ChromeAPI
participant Background
User->>App: 확장 프로그램 실행
App->>ChromeAPI: 활성 탭 정보 요청
ChromeAPI-->>App: 활성 탭 URL 반환
App->>ModalPop: urlInfo prop 전달
User->>ModalPop: 저장하기 버튼 클릭
ModalPop->>ChromeAPI: SAVE_BOOKMARK 메시지 전송
ChromeAPI->>Background: 메시지 전달
Background->>ChromeAPI: 알림(Notification) 생성
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (3)
apps/extension/src/popup.tsx (2)
2-2: React 네임스페이스 임포트가 실제로 사용되지 않습니다
createRoot로 렌더링하는 JSX 구문은 최신 JSX 런타임(jsx: "react-jsx") 설정이라면React객체를 참조하지 않습니다.
따라서import * as React from 'react';는 번들에 불필요한 네임스페이스를 추가하고 ESLint 규칙( no-unused-vars )에도 저촉될 수 있습니다.-import * as React from 'react'; +// React 17 이전 런타임을 사용하는 경우에만 필요 +// import React from 'react';사용 중인 TS 컴파일 옵션을 한 번 확인해 주세요. 최신 런타임이라면 임포트를 완전히 제거해도 됩니다.
8-12: 루트 엘리먼트 null 처리 간결화 제안null 검사를 분기하지 않고 널 단언으로 처리하면 코드가 더 간결해집니다. 팝업 HTML에
#root가 없으면 애초에 런타임 오류가 발생하므로, 개발 단계에서 빨리 실패(fail-fast)하게 하는 것도 한 방법입니다.-const rootEl = document.getElementById('root'); -if (rootEl) { - createRoot(rootEl).render(<App />); -} else { - console.error('❌ root element not found!'); -} +const rootEl = document.getElementById('root')!; +createRoot(rootEl).render(<App />);버전 관리 정책에 따라 선택적으로 반영해 주세요.
apps/extension/src/App.tsx (1)
15-15: console.log 메시지를 영어로 변경하는 것을 권장합니다.일관성을 위해 로그 메시지를 영어로 작성하는 것이 좋습니다.
다음과 같이 변경하는 것을 권장합니다:
- console.log('📌 URL:', activeTab.url); + console.log('📌 Current URL:', activeTab.url); - console.log('저장'); + console.log('Bookmark saved');Also applies to: 18-18
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
apps/extension/package.json(1 hunks)apps/extension/public/manifest.json(2 hunks)apps/extension/src/App.tsx(1 hunks)apps/extension/src/background.ts(1 hunks)apps/extension/src/components/modalPop/ModalPop.tsx(2 hunks)apps/extension/src/content.ts(1 hunks)apps/extension/src/popup.tsx(1 hunks)apps/extension/vite.config.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
apps/extension/src/popup.tsx (2)
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#30
File: apps/extension/src/components/InfoBox/InfoBox.tsx:10-11
Timestamp: 2025-07-08T11:47:27.279Z
Learning: In React TypeScript components, prefer semantic prop names with union types over abstract version numbers. For example, use `size: 'small' | 'large'` instead of `version: 1 | 2` for better code readability, type safety, and extensibility.
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#30
File: apps/extension/src/App.tsx:10-21
Timestamp: 2025-07-08T11:47:10.642Z
Learning: In apps/extension/src/App.tsx, the InfoBox component currently uses a hardcoded external URL for the icon prop as a temporary static placeholder. The plan is to replace this with dynamic favicon extraction from bookmarked websites in future iterations.
apps/extension/public/manifest.json (1)
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#30
File: apps/extension/src/App.tsx:10-21
Timestamp: 2025-07-08T11:47:10.642Z
Learning: In apps/extension/src/App.tsx, the InfoBox component currently uses a hardcoded external URL for the icon prop as a temporary static placeholder. The plan is to replace this with dynamic favicon extraction from bookmarked websites in future iterations.
apps/extension/src/App.tsx (1)
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#30
File: apps/extension/src/App.tsx:10-21
Timestamp: 2025-07-08T11:47:10.642Z
Learning: In apps/extension/src/App.tsx, the InfoBox component currently uses a hardcoded external URL for the icon prop as a temporary static placeholder. The plan is to replace this with dynamic favicon extraction from bookmarked websites in future iterations.
apps/extension/src/components/modalPop/ModalPop.tsx (2)
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#30
File: apps/extension/src/App.tsx:10-21
Timestamp: 2025-07-08T11:47:10.642Z
Learning: In apps/extension/src/App.tsx, the InfoBox component currently uses a hardcoded external URL for the icon prop as a temporary static placeholder. The plan is to replace this with dynamic favicon extraction from bookmarked websites in future iterations.
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#43
File: apps/client/src/shared/components/ui/cards/BookmarkCard.tsx:0-0
Timestamp: 2025-07-11T20:47:15.009Z
Learning: React 컴포넌트에서 button 요소를 사용할 때는 항상 type 속성을 명시적으로 지정해야 합니다. 일반적인 클릭 버튼의 경우 type="button"을, 폼 제출 버튼의 경우 type="submit"을 명시해야 합니다. 이렇게 해야 의도하지 않은 폼 제출 동작을 방지할 수 있습니다.
🔇 Additional comments (10)
apps/extension/src/content.ts (1)
1-1: 단순한 메시지 변경으로 문제없음콘솔 로그 메시지 변경이 적절합니다.
apps/extension/package.json (1)
45-45: 크롬 확장 프로그램 빌드를 위한 적절한 의존성 추가vite-plugin-chrome-extension 플러그인 추가가 적절합니다.
apps/extension/vite.config.ts (1)
30-30: 올바른 파일 확장자 수정백그라운드 스크립트 경로를 .ts로 수정한 것이 적절합니다.
apps/extension/src/components/modalPop/ModalPop.tsx (1)
12-14: 인터페이스 정의는 적절함ModalPopProps 인터페이스 정의가 적절합니다.
apps/extension/public/manifest.json (3)
6-6: "tabs" 권한 추가를 승인합니다.App.tsx에서 활성 탭을 쿼리하는 기능에 필요한 권한이 올바르게 추가되었습니다.
25-25: content_scripts 매칭 범위 검토 결과apps/extension/src/content.ts를 확인한 결과, content script는 단순히
console.log('Hello from content!')만 수행하므로 보안·성능상 즉각적인 문제는 없습니다.
다만, 향후 실제 사용 목적에 맞춰 아래 사항을 검토하시길 권장드립니다.
- apps/extension/public/manifest.json의
"matches": ["<all_urls>"]를
실제 필요한 URL 패턴(ex.https://example.com/*)으로 좁히기
7-7: host_permissions 최소 범위 사용 검토 요청manifest.json의
"host_permissions": ["<all_urls>"]는 보안상 권한이 너무 광범위합니다.
코드 분석 결과 네트워크 호출(fetch/XHR)이나 프로그래매틱 스크립트 주입(chrome.scripting.executeScript 또는 chrome.tabs.executeScript) 사용 흔적이 없으며, content_scripts 역시 모든 URL("<all_urls>")에만 선언되어 있습니다.따라서 아래를 검토해 주세요:
- apps/extension/public/manifest.json
- host_permissions: 실제 동작에 필요한 최소 도메인 패턴(예:
https://your-domain.com/*)만 허용하도록 수정- content_scripts.matches: 필요 도메인으로 동기화
- 프로그래매틱 스크립트 주입 API 사용 여부 확인
chrome.scripting.executeScript또는chrome.tabs.executeScript호출이 없다면 host_permissions 항목 제거 검토apps/extension/src/App.tsx (3)
5-5: React hooks import를 승인합니다.useState와 useEffect가 올바르게 import되었습니다.
8-8: URL 상태 초기화를 승인합니다.빈 문자열로 초기화하는 것이 적절합니다.
23-29: UI 구조가 적절합니다.현재 URL을 표시하고 ModalPop에 전달하는 구조가 잘 구성되어 있습니다.
| chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { | ||
| if (message.type === 'PAGE_DURATION') { | ||
| const { url, duration } = message.payload; | ||
| console.log(`🌐 ${url} 체류시간: ${duration}초`); | ||
|
|
||
| // optionally alert | ||
| chrome.notifications.create({ | ||
| type: 'basic', | ||
| iconUrl: 'icon48.png', | ||
| title: '체류시간 측정', | ||
| message: `${new URL(url).hostname}에서 ${duration}초 머물렀어요!`, | ||
| }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
에러 처리 및 입력 검증 추가 필요
메시지 핸들러에서 다음 사항들이 개선되어야 합니다:
- URL 파싱 시 에러 처리
- 메시지 payload 구조 검증
- chrome.notifications.create 에러 처리
다음과 같이 개선하는 것을 권장합니다:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'PAGE_DURATION') {
- const { url, duration } = message.payload;
+ const { url, duration } = message.payload || {};
+
+ if (!url || !duration) {
+ console.error('Invalid payload structure');
+ return;
+ }
+
console.log(`🌐 ${url} 체류시간: ${duration}초`);
// optionally alert
- chrome.notifications.create({
- type: 'basic',
- iconUrl: 'icon48.png',
- title: '체류시간 측정',
- message: `${new URL(url).hostname}에서 ${duration}초 머물렀어요!`,
- });
+ try {
+ const hostname = new URL(url).hostname;
+ chrome.notifications.create({
+ type: 'basic',
+ iconUrl: 'icon48.png',
+ title: '체류시간 측정',
+ message: `${hostname}에서 ${duration}초 머물렀어요!`,
+ });
+ } catch (error) {
+ console.error('Failed to create notification:', error);
+ }
}
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { | |
| if (message.type === 'PAGE_DURATION') { | |
| const { url, duration } = message.payload; | |
| console.log(`🌐 ${url} 체류시간: ${duration}초`); | |
| // optionally alert | |
| chrome.notifications.create({ | |
| type: 'basic', | |
| iconUrl: 'icon48.png', | |
| title: '체류시간 측정', | |
| message: `${new URL(url).hostname}에서 ${duration}초 머물렀어요!`, | |
| }); | |
| } | |
| }); | |
| chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { | |
| if (message.type === 'PAGE_DURATION') { | |
| const { url, duration } = message.payload || {}; | |
| if (!url || !duration) { | |
| console.error('Invalid payload structure'); | |
| return; | |
| } | |
| console.log(`🌐 ${url} 체류시간: ${duration}초`); | |
| // optionally alert | |
| try { | |
| const hostname = new URL(url).hostname; | |
| chrome.notifications.create({ | |
| type: 'basic', | |
| iconUrl: 'icon48.png', | |
| title: '체류시간 측정', | |
| message: `${hostname}에서 ${duration}초 머물렀어요!`, | |
| }); | |
| } catch (error) { | |
| console.error('Failed to create notification:', error); | |
| } | |
| } | |
| }); |
🤖 Prompt for AI Agents
In apps/extension/src/background.ts lines 2 to 15, the message handler lacks
error handling and input validation. Add checks to verify that message.payload
exists and contains valid url and duration fields before processing. Wrap the
URL parsing in a try-catch block to handle invalid URLs gracefully. Also,
provide a callback or promise handling for chrome.notifications.create to catch
and log any errors during notification creation.
| interface ModalPopProps { | ||
| urlInfo?: string; | ||
| } | ||
| const ModalPop = (urlInfo: ModalPopProps) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
매개변수 구조분해 문법 오류 수정 필요
함수 매개변수에서 props 구조분해가 잘못되었습니다.
다음과 같이 수정해야 합니다:
-const ModalPop = (urlInfo: ModalPopProps) => {
+const ModalPop = ({ urlInfo }: ModalPopProps) => {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const ModalPop = (urlInfo: ModalPopProps) => { | |
| const ModalPop = ({ urlInfo }: ModalPopProps) => { |
🤖 Prompt for AI Agents
In apps/extension/src/components/modalPop/ModalPop.tsx at line 15, the function
parameter uses incorrect destructuring syntax for props. Change the parameter
from a single object to destructured props by replacing "urlInfo: ModalPopProps"
with "{ urlInfo }: ModalPopProps" to correctly extract urlInfo from the props
object.
| const handleSave = () => { | ||
| chrome.runtime.sendMessage( | ||
| { | ||
| type: 'SAVE_BOOKMARK', | ||
| payload: { | ||
| url: { urlInfo }, | ||
| }, | ||
| }, | ||
| (response) => { | ||
| console.log('✅ 응답 받음:', response); | ||
| } | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
에러 처리 및 payload 구조 개선 필요
handleSave 함수에서 다음 사항들이 개선되어야 합니다:
- payload 구조가 잘못됨
- 에러 처리 부재
다음과 같이 개선하는 것을 권장합니다:
const handleSave = () => {
chrome.runtime.sendMessage(
{
type: 'SAVE_BOOKMARK',
payload: {
- url: { urlInfo },
+ url: urlInfo,
},
},
(response) => {
- console.log('✅ 응답 받음:', response);
+ if (chrome.runtime.lastError) {
+ console.error('메시지 전송 실패:', chrome.runtime.lastError);
+ } else {
+ console.log('✅ 응답 받음:', response);
+ }
}
);
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleSave = () => { | |
| chrome.runtime.sendMessage( | |
| { | |
| type: 'SAVE_BOOKMARK', | |
| payload: { | |
| url: { urlInfo }, | |
| }, | |
| }, | |
| (response) => { | |
| console.log('✅ 응답 받음:', response); | |
| } | |
| ); | |
| }; | |
| const handleSave = () => { | |
| chrome.runtime.sendMessage( | |
| { | |
| type: 'SAVE_BOOKMARK', | |
| payload: { | |
| url: urlInfo, | |
| }, | |
| }, | |
| (response) => { | |
| if (chrome.runtime.lastError) { | |
| console.error('메시지 전송 실패:', chrome.runtime.lastError); | |
| } else { | |
| console.log('✅ 응답 받음:', response); | |
| } | |
| } | |
| ); | |
| }; |
🤖 Prompt for AI Agents
In apps/extension/src/components/modalPop/ModalPop.tsx around lines 16 to 28,
the handleSave function has an incorrect payload structure and lacks error
handling. Fix the payload by removing the unnecessary nested object around
urlInfo so that payload directly contains the url value. Add error handling in
the callback of chrome.runtime.sendMessage to check for runtime.lastError and
handle it appropriately, such as logging or user notification.
| <CommonBtn | ||
| text="저장하기" | ||
| size="large" | ||
| type="green" | ||
| onClick={handleSave} | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
버튼 타입 속성 추가 필요
리트리빙된 학습 내용에 따르면, React 컴포넌트에서 button 요소에는 항상 type 속성을 명시해야 합니다.
CommonBtn 컴포넌트에 type="button" 속성을 추가하는 것을 권장합니다:
<CommonBtn
+ type="button"
text="저장하기"
size="large"
type="green"
onClick={handleSave}
/>참고: 만약 CommonBtn 컴포넌트가 내부적으로 button 요소를 렌더링한다면, 해당 컴포넌트에서 type 속성을 처리하도록 해야 합니다.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/extension/src/components/modalPop/ModalPop.tsx around lines 105 to 110,
the CommonBtn component lacks an explicit button type attribute, which can cause
unintended form submissions. Add a type="button" prop to the CommonBtn usage
here. Also verify that the CommonBtn component correctly passes this type prop
to the underlying button element it renders.
| <div> | ||
| <h1 className="text-lg font-bold">📎 북마크 저장!</h1> | ||
| <p className="mt-2 break-words text-sm">{url}</p> | ||
| <ModalPop urlInfo={url} />; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSX 구문 오류를 수정해주세요.
JSX 요소 뒤에 세미콜론이 잘못 위치했습니다.
다음과 같이 수정해주세요:
- <ModalPop urlInfo={url} />;
+ <ModalPop urlInfo={url} />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <ModalPop urlInfo={url} />; | |
| <ModalPop urlInfo={url} /> |
🤖 Prompt for AI Agents
In apps/extension/src/App.tsx at line 27, remove the semicolon immediately
following the JSX element <ModalPop urlInfo={url} /> as it is a syntax error in
JSX. The JSX element should be written without a trailing semicolon.
| useEffect(() => { | ||
| chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { | ||
| const activeTab = tabs[0]; | ||
| if (activeTab?.url) { | ||
| setUrl(activeTab.url); | ||
| console.log('📌 URL:', activeTab.url); | ||
|
|
||
| chrome.storage.local.set({ bookmarkedUrl: activeTab.url }, () => { | ||
| console.log('저장'); | ||
| }); | ||
| } | ||
| }); | ||
| }, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
에러 핸들링 추가를 권장합니다.
chrome.tabs.query와 chrome.storage.local.set 작업에 에러 핸들링이 필요합니다.
다음과 같이 에러 핸들링을 추가하는 것을 권장합니다:
useEffect(() => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const activeTab = tabs[0];
if (activeTab?.url) {
setUrl(activeTab.url);
console.log('📌 URL:', activeTab.url);
- chrome.storage.local.set({ bookmarkedUrl: activeTab.url }, () => {
- console.log('저장');
- });
+ chrome.storage.local.set({ bookmarkedUrl: activeTab.url }, () => {
+ if (chrome.runtime.lastError) {
+ console.error('저장 실패:', chrome.runtime.lastError);
+ } else {
+ console.log('저장 완료');
+ }
+ });
}
});
}, []);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { | |
| const activeTab = tabs[0]; | |
| if (activeTab?.url) { | |
| setUrl(activeTab.url); | |
| console.log('📌 URL:', activeTab.url); | |
| chrome.storage.local.set({ bookmarkedUrl: activeTab.url }, () => { | |
| console.log('저장'); | |
| }); | |
| } | |
| }); | |
| }, []); | |
| useEffect(() => { | |
| chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { | |
| const activeTab = tabs[0]; | |
| if (activeTab?.url) { | |
| setUrl(activeTab.url); | |
| console.log('📌 URL:', activeTab.url); | |
| chrome.storage.local.set({ bookmarkedUrl: activeTab.url }, () => { | |
| if (chrome.runtime.lastError) { | |
| console.error('저장 실패:', chrome.runtime.lastError); | |
| } else { | |
| console.log('저장 완료'); | |
| } | |
| }); | |
| } | |
| }); | |
| }, []); |
🤖 Prompt for AI Agents
In apps/extension/src/App.tsx around lines 10 to 22, the chrome.tabs.query and
chrome.storage.local.set calls lack error handling. To fix this, add checks for
errors in their callbacks by inspecting chrome.runtime.lastError and handle or
log any errors appropriately. This will ensure that any issues during these
asynchronous operations are caught and managed gracefully.
karnelll
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전체적으로 구조가 잘 정리되어 있어 읽기 편했고, 디자인 시스템 컴포넌트를 활용해 UI를 깔끔하게 구성해주신 점이 좋았어요!! 간단한 코멘트만 확인 부탁드립니다 :) 고생하셨어요👍
| chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { | ||
| if (message.type === 'PAGE_DURATION') { | ||
| const { url, duration } = message.payload; | ||
| console.log(`🌐 ${url} 체류시간: ${duration}초`); | ||
|
|
||
| // optionally alert | ||
| chrome.notifications.create({ | ||
| type: 'basic', | ||
| iconUrl: 'icon48.png', | ||
| title: '체류시간 측정', | ||
| message: `${new URL(url).hostname}에서 ${duration}초 머물렀어요!`, | ||
| }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
타입을 별도 파일로 분리해두면 재사용성과 안정성이 높아지고, IDE 자동완성도 더 잘 작동해서 분리해두면 좋을 것 같습니다!
현재 메시지 핸들러에서 전달받는 메시지에 타입이 명시되어 있지 않아 런타임 에러도 방지할 수 있어요 👍
// types/messages.ts
export interface PageDurationMessage {
type: 'PAGE_DURATION';
payload: {
url: string;
duration: number;
};
}
export type ExtensionMessage = PageDurationMessage;// background.ts
import type { ExtensionMessage } from '@/types/messages';
chrome.runtime.onMessage.addListener(
(message: ExtensionMessage, sender, sendResponse) => {
if (message.type === 'PAGE_DURATION') {
const { url, duration } = message.payload;
// 안전하게 로직 처리 가능
}
}
);| interface ModalPopProps { | ||
| urlInfo?: string; | ||
| } | ||
| const ModalPop = (urlInfo: ModalPopProps) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 urlInfo에 대한 유효성 검사가 없어, 간단하게 !urlInfo 체크와 try/catch로 new URL(urlInfo) 정도의 방어처리만 추가해두면 안정성이 높아질 것 같습니다!😀
📌 Related Issues
✅ 체크 리스트
📄 Tasks
⭐ PR Point (To Reviewer)
📷 Screenshot
Summary by CodeRabbit
신규 기능
버그 수정
개선 사항
기타