개발
개발 가이드
영어만 편집하세요; 번역은 전파됩니다
문서는 website/docs(영어) 아래에서만 업데이트하세요. website/i18n/<locale>/… 아래의 번역물은 생성되므로 수동으로 편집하지 마세요. 번역 작업(예: make translate_web_docs_batch)을 사용해 현지화 콘텐츠를 새로 고치세요.
사전 준비 사항
- Node.js 22+ 및 npm(Node 22로 테스트됨)
- Thunderbird 128 ESR 이상(수동 테스트용)
프로젝트 레이아웃(상위 수준)
- 루트: 패키징 스크립트
distribution_zip_packer.sh, 문서, 스크린샷 sources/: 메인 애드온 코드(백그라운드, 옵션/팝업 UI, 매니페스트, 아이콘)tests/: Vitest 스위트website/: Docusaurus 문서(website/i18n/de/...아래에 i18n 포함)
설치 및 도구
- 루트 의존성 설치:
npm ci - 문서(선택):
cd website && npm ci - 타깃 확인:
make help
실시간 개발(web‑ext run)
- Firefox Desktop에서 빠른 루프(UI 스모크 테스트 전용):
npx web-ext run --source-dir sources --target=firefox-desktop- Thunderbird에서 실행(MailExtensions에는 이 방식 권장):
npx web-ext run --source-dir sources --start-url about:addons --firefox-binary "$(command -v thunderbird || echo /path/to/thunderbird)"- 팁:
- Thunderbird의 오류 콘솔을 열어 두세요(도구 → 개발자 도구 → 오류 콘솔).
- MV3 이벤트 페이지는 유휴 시 일시 중단됩니다. 코드 변경 후 애드온을 다시 로드하거나 web‑ext 자동 재로드를 사용하세요.
- 일부 Firefox 전용 동작은 다를 수 있습니다. API 동등성 확보를 위해 항상 Thunderbird에서 확인하세요.
- Thunderbird 바이너리 경로(예시):
- Linux:
thunderbird(예:/usr/bin/thunderbird) - macOS:
/Applications/Thunderbird.app/Contents/MacOS/thunderbird - Windows:
"C:\\Program Files\\Mozilla Thunderbird\\thunderbird.exe" - 프로필 분리: 일상 설정에 영향을 주지 않도록 개발에는 별도의 Thunderbird 프로필을 사용하세요.
Make 타깃(알파벳순)
Makefile은 일반적인 개발 흐름을 표준화합니다. 모든 타깃의 한 줄 요약은 언제든 make help을(를) 실행해 확인하세요.
팁: 타깃 없이 make을(를) 실행하면 간단한 Whiptail 메뉴가 열려 타깃을 선택할 수 있습니다.
| Target | 한 줄 설명 |
|---|---|
clean | 로컬 빌드/미리보기 산출물 제거(tmp/, web-local-preview/, website/build/). |
commit | 포맷팅, 테스트(i18n 포함) 실행, 변경 로그 업데이트, 커밋 및 푸시. |
eslint | 플랫 구성(npm run -s lint:eslint)으로 ESLint 실행. |
help | 모든 타깃을 한 줄 설명과 함께 나열(정렬됨). |
lint | sources/에서 web‑ext lint(임시 매니페스트; ZIP 무시; 비치명적). |
menu | 대화형 메뉴로 타깃과 선택적 인자를 선택. |
pack | ATN 및 LOCAL ZIP 빌드(린터 실행; 패커 스크립트 호출). |
prettier | 저장소를 제자리 포맷(변경 사항 기록). |
prettier_check | Prettier 체크 모드(쓰기 없음); 재포맷이 필요하면 실패. |
prettier_write | prettier의 별칭. |
test | Prettier(쓰기), ESLint, 그 다음 Vitest(구성 시 커버리지). |
test_i18n | i18n 전용 테스트: 애드온 플레이스홀더/동등성 + 웹사이트 동등성. |
translate_app | translation_app의 별칭. |
translation_app | sources/_locales/en/messages.json에서 앱 UI 문 자열 번역. |
translate_web_docs_batch | OpenAI 배치 API로 웹사이트 문서 번역(권장). |
translate_web_docs_sync | 동기식으로 웹사이트 문서 번역(레거시, 배치 아님). |
translate_web_index | translation_web_index의 별칭. |
translation_web_index | 홈페이지/네비게이션 바/푸터 UI 번역(website/i18n/en/code.json → .../<lang>/code.json). |
web_build | 문서를 website/build로 빌드(--locales / BUILD_LOCALES 지원). |
web_build_linkcheck | 오프라인 안전 링크 검사(원격 HTTP[S] 건너뜀). |
web_build_local_preview | 로컬 gh‑pages 미리보기; 8080–8090에서 자동 제공; 선택적 테스트/링크 검사. |
web_push_github | website/build를 gh-pages 브랜치로 푸시. |
옵션 문법
- 옵션을 전달하려면
make <command> OPTS="…"을(를) 사용하세요(따옴표 권장). 아래 각 타깃은 사용 예를 보여줍니다.
--
로케일 빌드 팁
- 일부 로케일만 빌드:
BUILD_LOCALES="en de"을(를) 설정하거나OPTS="--locales en,de"을(를) 웹 타깃에 전달하세요. - 특정 로케일 미리보기:
http://localhost:<port>/Thunderbird-Reply-with-Attachments/de/.
빌드 및 패키징
- ZIP 빌드:
make pack - 리포지토리 루트에 ATN 및 LOCAL ZIP을 생성합니다(산출물을 수동으로 편집하지 마세요)
- 팁: 패키징 전에
sources/manifest_ATN.json와sources/manifest_LOCAL.json두 곳의 버전을 업데이트하세요 - 수동 설치(개발): Thunderbird → 도구 → 부가 기능 및 테마 → 톱니바퀴 → 파일에서 부가 기능 설치… → 빌드된 ZIP 선택
테스트
- 전체 스위트:
make test(Vitest) - 커버리지(선택):
npm i -D @vitest/coverage-v8make test를 실행; HTML 보고서는coverage/index.html를 엽니다- i18n 전용:
make test_i18n(UI 키/플레이스홀더/타이틀 + 웹사이트의 로케일별 문서 동등성(id/title/sidebar_label 검사 포함))
디버깅 및 로그
- 오류 콘솔: 도구 → 개발자 도구 → 오류 콘솔
- 런타임에 상세 로그 전환:
- 활성화:
messenger.storage.local.set({ debug: true }) - 비활성화:
messenger.storage.local.set({ debug: false }) - 답장을 작성/전송하는 동안 로그가 표시됩니다
문서(웹사이트)
- 개발 서버:
cd website && npm run start - 정적 사이트 빌드:
cd website && npm run build - Make 동등 명령(알파벳순):
make web_build,make web_build_linkcheck,make web_build_local_preview,make web_push_github - 사용 예:
- 영어만, 테스트/링크 검사 생략, 푸시 안 함:
make web_build_local_preview OPTS="--locales en --no-test --no-link-check --dry-run" - 모든 로케일, 테스트/링크 검사 포함, 이후 푸시:
make web_build_local_preview && make web_push_github - 게시 전, 오프라인 안전 링크 검사를 실행하세요:
make web_build_linkcheck. - i18n: 영어는
website/docs/*.md에, 독일어 번역은website/i18n/de/docusaurus-plugin-content-docs/current/*.md에 있습니다 - 검색: CI에서 Algolia DocSearch 환경 변수가 설정되어 있으면(
DOCSEARCH_APP_ID,DOCSEARCH_API_KEY,DOCSEARCH_INDEX_NAME), 사이트는 Algolia 검색을 사용합니다. 그렇지 않으면 로컬 검색으로 폴백합니다. 홈페이지에서/또는Ctrl+K를 눌러 검색 상자를 여세요.
기부 리디렉트 경로
website/src/pages/donate.js- 경로:
/donate(및/<locale>/donate) - 동작:
- 현재 라우트에 로케일이 있으면(예:
/de/donate), 해당 로케일을 사용 - 그렇지 않으면
navigator.languages과(와) 구성된 로케일을 비교해 최적 일치를 선택; 기본 로케일로 폴백 - 리디렉트 대상:
en→/docs/donation- 기타 →
/<locale>/docs/donation - 적절한 baseUrl 처리를 위해
useBaseUrl사용 - 폴백으로 메타 리프레시 +
noscript링크 포함
미리보기 팁
- Node 미리보기를 정상 종료:
Local server started후에 출력되는http://localhost:<port>/__stop를 엽니다. - MDX/JSX에서 이미지가 로드되지 않으면 사이트
baseUrl을(를) 준수하도록useBaseUrl('/img/...')를 사용하세요. - 미리보기가 먼저 시작되며, 링크 검사는 그 이후 비차단으로 실행됩니다(깨 진 외부 링크는 미리보기를 중단하지 않음).
- 예시 미리보기 URL:
http://localhost:<port>/Thunderbird-Reply-with-Attachments/("Local server started" 이후에 출력됨). - 링크 검사에서의 외부 링크: 일부 외부 사이트(예: addons.thunderbird.net)는 자동 크롤러를 차단하여 링크 검사에서 403이 표시될 수 있습니다. 미리보기는 여전히 시작되며, 이는 무시해도 안전합니다.
웹사이트 번역
번역 가능한 항목
- 웹사이트 UI만: 홈페이지, 네비게이션 바, 푸터 및 기타 UI 문자열. 문서 콘텐츠는 현재 영어 전용입니다.
편집 위치
website/i18n/<locale>/code.json를 편집(en를 참고).{year},{slash},{ctrl},{k},{code1}같은 플레이스홀더는 변경하지 마세요.
파일 생성 또는 새로 고침
- 모든 로케일에 대해 누락된 스텁 생성:
npm --prefix website run i18n:stubs - 영어에서 스텁 덮어쓰기(새 문자열 추가 후):
npm --prefix website run i18n:stubs:force - 단일 로케일용 대안:
npx --prefix website docusaurus write-translations --locale <locale>
홈페이지/네비게이션 바/푸터 UI 문자열 번역(OpenAI)
- 자격 증명 1회 설정(쉘 또는 .env):
export OPENAI_API_KEY=sk-...- 선택 사항:
export OPENAI_MODEL=gpt-4o-mini - 원샷(모든 로 케일, en 제외):
make translate_web_index - 특정 로케일로 제한:
make translate_web_index OPTS="--locales de,fr" - 기존 값 덮어쓰기:
make translate_web_index OPTS="--force"
검증 및 재시도
- 번역 스크립트는 JSON 구조를 검증하고, 중괄호 플레이스홀더를 보존하며, URL이 변경되지 않도록 보장합니다.
- 검증 실패 시 기존 값을 유지하기 전에 피드백과 함께 최대 2회 재시도합니다.
내 로케일 미리보기
- 개발 서버:
npm --prefix website run start http://localhost:3000/<locale>/Thunderbird-Reply-with-Attachments/방문
제출
- 편집된
code.json파일로 PR을 열어주세요. 변경 사항은 집중적으로 유지하고 가능하면 빠른 스크린샷을 포함하세요.
보안 및 구성 팁
sources/manifest.json를 커밋하지 마세요(빌드에서 일시적으로 생성됨)- 업데이트 채널을 유지하려면
browser_specific_settings.gecko.id을(를) 안정적으로 유지하세요
설정 지속성
- 저장소: 모든 사용자 설정은
storage.local에 저장되며 애드온 업데이트 간에 유지됩니다. - 설치: 키가 엄격히 누락(undefined)된 경우에만 기본값이 적용됩니다.
- 업데이트: 마이그레이션은 누락된 키만 채우며 기존 값은 절대 덮어쓰지 않습니다.
- 스키마 마커:
settingsVersion(현재1). - 키와 기본값:
blacklistPatterns: string[]→['*intern*', '*secret*', '*passwor*']confirmBeforeAdd: boolean→falseconfirmDefaultChoice: 'yes'|'no'→'yes'warnOnBlacklistExcluded: boolean→true- 코드:
sources/background.js→initializeOrMigrateSettings()및SCHEMA_VERSION참조.
개발 워크플로(새 설정 추가)
sources/background.js에서SCHEMA_VERSION를 증가시키세요.initializeOrMigrateSettings()의DEFAULTS객체에 새 키와 기본값을 추가하세요.- 기본값 시드 시 "undefined인 경우에만" 규칙을 사용하고 기존 값을 덮어쓰지 마세요.
- 설정이 사용자에게 표시된다면
sources/options.js에 연결하고 지역화 문자열을 추가하세요. - 테스트 추가/조정(
tests/background.settings.migration.test.js참조).
수동 테스트 팁
- 새 설치 시뮬레이션: 확장 프로그램의 데이터 디렉터리를 지우거나 새 프로필로 시작하세요.
- 업데이트 시뮬레이션:
storage.local에서settingsVersion를0로 설정하고 다시 로드하세요. 기존 값은 변경되지 않고 누락 된 키만 추가되는지 확인하세요.
문제 해결
- Thunderbird가 128 ESR 이상인지 확인
- 런타임 문제에는 오류 콘솔 사용
- 저장된 설정이 제대로 적용되지 않는 것 같다면 Thunderbird를 재시작한 뒤 다시 시도하세요. (Thunderbird는 세션 간 상태를 캐시할 수 있으며, 재시작하면 최신 설정이 로드됩니다.)
CI 및 커버리지
- GitHub Actions(
CI — Tests)는 커버리지 임계값(라인/함수/분기/문장 85%)으로 vitest를 실행합니다. 임계값을 충족하지 못하면 작업이 실패합니다. - 워크플로는 HTML 보고서를 포함한 아티팩트
coverage-html를 업로드합니다. 실행 페이지에서 다운로드하세요(Actions → 최신 실행 → Artifacts).
기여
- 브랜치/커밋/PR 지침은 CONTRIBUTING.md를 참고하세요
- 팁: 일상 프로필에 영향을 주지 않도록 테스트용 별도 Thunderbird 개발 프로필을 만드세요.