시리즈 목차 (4편 연재)
1/4. 구매대행 크롬 확장 — 프로그램 개념 잡기
2/4. 구매대행 크롬 확장 — Svelte 5·MV3 사이드패널 만들기 (현재 글)
3/4. 구매대행 크롬 확장 — 1688 주문·상품 수집과 엑셀 자동화
4/4. 구매대행에 붙이는 관리자 페이지 — 환경설정·통관검증·엑셀 병합
1편에서는 구매대행 확장의 Side Panel · Content Script · Background 역할과 Shadow DOM·접힌 주문 개념을 정리했습니다. 이번 글에서는 그 지도를 코드로 옮깁니다. Svelte 5와 SvelteKit으로 Manifest V3 사이드패널의 구조·통신·빌드를 만듭니다.
Chrome 확장은 웹페이지에 기능을 더하거나 브라우저 경험을 개선하는 강력한 도구입니다. 아래처럼 대상 페이지에 따라 사이드패널 도구가 달라집니다.
대상(1688 구매내역) 페이지

비대상 페이지

예제 코드: 이 글의 골격에 해당하는 핵심 파일은 시리즈 4편에
chromeExtExample.zip으로 첨부합니다. (폴더별 핵심파일만)
(로그인·API·관심상품 제외. 압축을 풀면 아래 구조입니다.)chromeExtExample/ ├── package.json / svelte.config.js / README.md ├── samples/ventigoods.agency.sample.txt ├── scripts/fix-extension-csp.mjs ├── static/manifest.json · background.js · content.js(축약) └── src/routes/+page.svelte완전체 운영 코드는 아니며, MV3 사이드패널·메시지·CSP 패턴을 보는 용도입니다.
주문 스크랩·타배 엑셀 실무는 3편, 관리자·zip 첨부는 4편에서 다룹니다.
0. chromeExtExample.zip 구성 (4편 첨부)
| zip 안 경로 | 역할 |
|---|---|
package.json |
build: vite build && node scripts/fix-extension-csp.mjs (ventiChromeExt 기준) |
svelte.config.js |
adapter-static, appDir: 'app' (원본과 동일) |
static/manifest.json |
MV3, side_panel, 권한 |
static/content.js |
Shadow DOM·Active 버튼·파싱 골격 (축약) |
static/background.js |
사이드패널 오픈, 엑셀 다운로드, 트래킹용 백그라운드 탭 |
scripts/fix-extension-csp.mjs |
빌드 후 인라인 스크립트 분리 (CSP) |
src/routes/+page.svelte |
사이드패널 관제탑 (API 없음) |
samples/ventigoods.agency.sample.txt |
localStorage ventigoods.agency용 # Text 샘플 (3편에서 설명) |
아래 코드 인용 경로는 zip 기준(chromeExtExample/…)입니다.
1. 왜 SvelteKit + adapter-static인가
Chrome 확장의 팝업(popup)이나 사이드패널(side panel)은 정적 HTML 파일을 필요로 합니다. SvelteKit의 adapter-static은 SPA를 build/index.html 형태로 빌드하므로 확장 UI로 적합합니다.
SvelteKit 설정 (svelte.config.js)
import adapter from '@sveltejs/adapter-static';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
appDir: 'app',
alias: {
$prj: 'src/prj',
$lib: 'src/lib',
},
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: undefined,
precompress: false
})
}
};
export default config;
appDir: 'app': SvelteKit 내부 파일을build/app/하위에 생성pages/assets: 'build': 최종 출력은build/폴더fallback: undefined: 단일 엔트리만 생성 (SPA 모드)
이렇게 빌드하면 build/index.html이 확장의 사이드패널 진입점이 됩니다.
2. Manifest V3와 side_panel 설정
Chrome 확장은 manifest.json이 핵심입니다. Manifest V3에서는 side_panel, background.service_worker, content_scripts 등을 선언합니다.
Manifest 예시 (static/manifest.json)
{
"manifest_version": 3,
"name": "Purchase Agency Extension (example)",
"version": "1.0.0",
"description": "1688 구매내역 → 배송대행 엑셀 (공유용 핵심 예제)",
"action": {},
"side_panel": {
"default_path": "index.html"
},
"background": {
"service_worker": "background.js"
},
"permissions": [
"tabs",
"scripting",
"windows",
"downloads",
"sidePanel",
"storage"
],
"host_permissions": [
"*://*.1688.com/*",
"*://air.1688.com/*",
"*://detail.1688.com/*"
],
"content_scripts": [
{
"matches": ["*://*.1688.com/*", "*://detail.1688.com/*"],
"js": ["content.js"],
"run_at": "document_idle"
}
],
"web_accessible_resources": [
{
"resources": ["app/*", "popup-init.js"],
"matches": ["*://*.1688.com/*", "*://detail.1688.com/*"]
}
]
}
주요 포인트:
side_panel.default_path: "index.html": 빌드된 SvelteKit 앱을 사이드패널로 사용background.service_worker: Manifest V3에서는 persistent background page 대신 service worker 사용permissions:tabs,scripting,sidePanel,storage등 필요한 권한 선언content_scripts: 1688 관련 URL에content.js주입web_accessible_resources:app/*(SvelteKit 빌드 산출물) 및popup-init.js를 외부에서 접근 가능하게 설정
3. UI / content script / service worker 역할 분리
Chrome 확장은 세 가지 컨텍스트로 나뉩니다:
3.1. 사이드패널 UI (src/routes/+page.svelte)
Svelte 5의 $state rune을 사용해 반응형 상태를 관리하고, 탭 전환/URL 변경 시 UI를 업데이트합니다. zip에 포함된 +page.svelte는 API·로그인 없는 핵심만 담았습니다.
// chromeExtExample/src/routes/+page.svelte 요지
const TARGET_RULES = [
{
category: 'purchase',
name: '1688 주문 목록',
domains: ['1688.com'],
pathPrefixes: ['/app/ctf-page/trade-order-list/buyer-order-list.html'],
btnCaption: '주문정보 모두 보이기',
buttonSelectors: ['button[data-role="submit-order"]', 'button.submit']
}
];
- 규칙 기반 UI: 현재 탭의 URL을
TARGET_RULES와 매칭해 구매 도구를 표시 - Svelte 5
$state: 값 변경 시 자동 리렌더링
3.2. Content Script (static/content.js)
페이지 DOM에 접근해 데이터를 수집하거나 UI를 조작합니다. zip의 content.js는 원본(~2100줄)을 축약한 골격입니다.
주요 기능:
- DOM 수집:
queryAllDeep으로 Shadow DOM까지 순회 - 메시지 수신:
COUNT_TARGET_BUTTONS/CLICK_TARGET_BUTTON/PARSE_1688_PURCHASES - 트래킹 보완 요청: background에
FETCH_TRACKING_NUMBER위임
관심상품 수집(FETCH_1688_PRODUCT_INFO)은 zip에 넣지 않았습니다.
3.3. Background Service Worker (static/background.js)
백그라운드에서 권한이 필요한 작업(다운로드, 탭 생성 등)을 처리합니다.
chrome.runtime.onInstalled.addListener(() => {
console.log('Venti Extension이 설치되었습니다.');
});
// 확장 아이콘 클릭 시 사이드 패널 열기
chrome.action.onClicked.addListener((tab) => {
chrome.sidePanel.open({ windowId: tab.windowId });
});
주요 기능:
- 엑셀 다운로드:
DOWNLOAD_EXCEL→chrome.downloads.download - 백그라운드 탭:
FETCH_TRACKING_NUMBER로 상세 페이지에서 운송장 추출 후 탭 닫기 - 사이드패널 오픈: 확장 아이콘 클릭 시
chrome.sidePanel.open
4. chrome.tabs.sendMessage와 content 재주입 패턴
사이드패널에서 content script로 메시지를 보낼 때, content script가 아직 주입되지 않았다면 에러가 발생합니다. 이를 대비해 재주입 패턴을 사용합니다. (chromeExtExample/src/routes/+page.svelte의 sendMessageToActiveTab)
// 요지
try {
return await chrome.tabs.sendMessage(tabId, payload);
} catch (error) {
if (String(error.message).includes('Receiving end does not exist')) {
await chrome.scripting.executeScript({ target: { tabId }, files: ['content.js'] });
await sleep(100);
return await chrome.tabs.sendMessage(tabId, payload);
}
throw error;
}
흐름:
chrome.tabs.sendMessage로 메시지 전송 시도- "Receiving end does not exist" 에러 발생 시 →
chrome.scripting.executeScript로 content.js 주입 - 100ms 대기 후 재전송
이 패턴으로 사용자가 확장 아이콘을 클릭한 후 페이지 새로고침 없이도 content script를 사용할 수 있습니다.
5. Background에 권한 작업 위임
Content script는 보안상 일부 Chrome API를 직접 호출할 수 없습니다. 예를 들어 chrome.downloads.download, chrome.tabs.create 등은 background에서만 사용 가능합니다.
엑셀 다운로드 위임 예시
if (message?.type === 'DOWNLOAD_EXCEL') {
(async () => {
try {
const { rows, headers, filename } = message.payload ?? {};
const blob = createExcelBlob(rows, headers);
const dataUrl = (await blobToDataUrl(blob)) ?? '';
chrome.downloads.download(
{
url: dataUrl,
filename: `${filename || 'venti_orders'}.xls`,
saveAs: true
},
(downloadId) => {
if (chrome.runtime.lastError) {
const errorMessage = chrome.runtime.lastError.message;
sendResponse({ ok: false, error: errorMessage });
return;
}
sendResponse({ ok: true, downloadId });
}
);
} catch (error) {
console.error('[background] DOWNLOAD_EXCEL 실패:', error);
sendResponse({ ok: false, error: error instanceof Error ? error.message : String(error) });
}
})();
return true;
}
흐름:
- 사이드패널 →
DOWNLOAD_EXCEL메시지 전송 - Background →
chrome.downloads.download호출 - 응답 →
sendResponse({ ok: true })
6. Chrome CSP와 인라인 스크립트 분리
Chrome 확장의 **Content Security Policy(CSP)**는 인라인 <script> 태그를 금지합니다. SvelteKit 빌드 결과물은 index.html에 인라인 스크립트를 포함하므로, 이를 외부 파일로 분리해야 합니다.
CSP 보정 스크립트 (scripts/fix-extension-csp.mjs)
zip의 chromeExtExample/scripts/fix-extension-csp.mjs 전체가 이 역할을 합니다.
처리 단계:
build/index.html에서<script>...</script>인라인 부분 추출popup-init.js로 저장하고 HTML은<script src="./popup-init.js"></script>로 대체manifest.json에content_security_policy.extension_pages: "script-src 'self'; object-src 'self'"추가web_accessible_resources에popup-init.js등록
빌드 후 자동 실행되도록 package.json에 연결합니다:
{
"scripts": {
"build": "vite build && node scripts/fix-extension-csp.mjs"
}
}
7. 빌드 후 chrome://extensions에 로드하는 방법
zip은
vite.config·전체src등이 없어 그대로 npm run build 되는 완전체는 아닙니다.
다만package.json·svelte.config.js· CSP 스크립트로 빌드 파이프라인은 확인할 수 있습니다.
아래는 실제 확장 프로젝트를 빌드했을 때의 일반적인 로드 절차입니다.
빌드 실행:
npm run build→
build/폴더에index.html,manifest.json,content.js,background.js,popup-init.js등이 생성됩니다.Chrome 확장 개발자 모드 활성화:
chrome://extensions로 이동- 우측 상단 "개발자 모드" 토글 활성화
압축 해제된 확장 프로그램 로드:
- "압축 해제된 확장 프로그램을 로드합니다" 클릭
build/폴더 선택
사이드패널 열기:
- 확장 아이콘 클릭 → 사이드패널이 열림
- 또는
chrome.sidePanel.open({ windowId: ... })을 background에서 호출
디버깅:
- 사이드패널: 우클릭 → "검사" → DevTools 오픈
- Background:
chrome://extensions→ "서비스 워커" 링크 클릭 - Content script: 페이지에서 F12 → Console에서 로그 확인
8. 다음 편 예고: 구매대행 item 처리
이번 글에서는 Chrome 확장의 구조·통신·빌드와 chromeExtExample.zip 골격을 다뤘습니다. zip 파일은 시리즈 4편에 첨부합니다. 3편에서는 1688 주문→엑셀 파이프라인을, 4편에서는 홈페이지 관리자(ENV·PCC·병합)를 이어서 올립니다.
- 1688 주문 item: Shadow DOM 수집, 날짜 필터, Excel 매핑
- 접힌 주문·운송장 보완: Active 버튼, 백그라운드 탭
- 환경설정 JSON: HS CODE·통관번호 정규화
최종적으로는 아래와 같은 배송대행용 엑셀을 자동 생성합니다.

👉 다음 편 예고: 구매대행 크롬 확장 — 1688 주문·상품 수집과 엑셀 자동화
👉 이후: 구매대행에 붙이는 관리자 페이지 — 환경설정·통관검증·엑셀 병합
개념이 아직 흐리다면 1편: 구매대행 크롬 확장 프로그램 개념 잡기를 먼저 다시 읽어 보세요.
참고 자료
이 글이 도움이 되었다면, Chrome 확장 개발에 도전해 보세요. Svelte의 간결함과 SvelteKit의 정적 빌드는 확장 UI를 만드는 데 최적입니다.
만들어야 할 뭔가가 있다면 집중하세요. (집중은 매일 매일 같은 생각을 하는 것입니다.)


주파수 소통방 (0)
로딩 중...