데이터가 필요한 대부분의 Chrome 확장 프로그램은 두 가지 패턴 중 하나에 해당합니다: 외부 API를 호출하거나, 사용자 특정 데이터를 로컬에 작은 양 저장합니다. EntryCheck는 둘 다 하지 않습니다. 190개 이상의 여권/목적지 조합에 대한 비자 요건의 정적 데이터 세트를 확장 프로그램에 직접 포함하고, 모든 조회를 클라이언트 측에서 네트워크 요청 없이 해결합니다.
이 트레이드오프 — 큰 번들, 즉각적인 검색, API 의존성 없음 —은 여행 데이터에 적합한 결정이 되어온다. 그 이유와 작동 방식은 다음과 같다.
왜 정적 데이터가 API보다 낫은가
비자 요건은 자주 변경되지 않습니다. 한 나라는 연중 비자 도착 리스트를 두 번 또는 세 번 업데이트할 수 있습니다. API는 지연 시간을 추가하고 인증을 요구하며, 비행기를 예약하기 전에 사용자가 빠르게 확인하려는 상황에서 네트워크가 없거나 API가 다운되거나 요청 한도를 초과하는 실패 모드를 만들 수 있습니다.
더 현실적으로는 비자 요건에 대한 신뢰할 수 있는 무료 공개 API는 없습니다. 데이터 소스는 정부 웹사이트와 참조 데이터베이스입니다. 실시간 API를 위해 이들을 스크래핑하거나 라이선스하는 것은 속도와 간단함의 가치를 가진 도구에 대해 가치가 없습니다.
확장 프로그램 시작 시 로드되는 로컬 JSON 파일은 모든 것을 피하ます.
데이터 구조
핵심 데이터셋은 두 글자 ISO 여권 코드로 키가 되는 JSON 객체로, 그 다음으로 두 글자 목적지 코드로 구성됩니다:
type VisaStatus =
| 'visa_free'
| 'visa_on_arrival'
| 'e_visa'
| 'visa_required'
| 'not_admitted';
interface EntryRequirement {
status: VisaStatus;
maxStay?: number; // days, undefined if no limit
notes?: string;
}
type VisaMatrix = Record<string, Record<string, EntryRequirement>>;
조회는 단지 두 번의 배열 접근입니다:
function lookup(matrix: VisaMatrix, passport: string, destination: string): EntryRequirement | null {
return matrix[passport]?.[destination] ?? null;
}
행렬 자체는 잘 압축됩니다: visa_free 그리고visa_required는 대부분의 조합을 포함하므로 JSON에는 많은 반복된 구조가 있습니다. Gzipped로 압축하면 전체 데이터셋이 30KB 미만입니다.
WXT와 함께 묶기
행렬은 public/visa-matrix.json에 있습니다. WXT(확장 프레임워크)는 public/ 디렉토리를 출력 루트에 정확히 복사합니다. 배경 서비스 워커는 설치 시 한 번 로드하고 결과를 캐시합니다:
let cachedMatrix: VisaMatrix | null = null;
async function getMatrix(): Promise<VisaMatrix> {
if (cachedMatrix) return cachedMatrix;
const url = chrome.runtime.getURL('visa-matrix.json');
const resp = await fetch(url);
cachedMatrix = await resp.json();
return cachedMatrix;
}
chrome.runtime.getURL는 확장 프로그램의 내부 chrome-extension:// URL로 상대 경로를 변환합니다. 이는 서비스 워커에서 포함된 자산에 접근하는 표준 패턴입니다. MV3에서는 특별한 권한 없이 작동합니다.
Google Flights에서의 콘텐츠 스크립트 주입
검색 팝업은 그 자체로 잘 작동하지만, 더 유용한 기능은 구글 항공권 자동 주입입니다. 사용자가 항공편을 검색하고 페이지에 목적지가 표시될 때, EntryCheck의 콘텐츠 스크립트는 목적지를 감지하고 사용자가 저장한 여권의 요구 사항을 조회한 다음 검색 결과 옆에 배지를 주입합니다.
콘텐츠 스크립트는 URL 파라미터와 페이지 DOM에서 현재 목적지를 읽고, chrome.runtime.sendMessage을 통해 배경으로 검색을 요청한 다음, 인라인으로 작은 배지 컴포넌트를 렌더링합니다.
chrome.runtime.sendMessage(
{ type: 'VISA_LOOKUP', passport: savedPassport, destination: detected },
(response: EntryRequirement | null) => {
if (response) renderBadge(response);
}
);
배경은 이를 받고, 호출합니다getMatrix()를 반환합니다. 첫 번째 로드 후 행렬이 메모리에 있기 때문에, 콘텐츠 스크립트의 관점에서는 응답이 동기식입니다.
유지보수 문제
정적 데이터는 명백한 단점이 하나 있습니다: 그것은 구식이 될 수 있습니다. 제 현재 접근 방식은 확장 버전 업데이트마다 JSON 파일을 업데이트하고 일반 CWS 업데이트로 푸시하는 것입니다. 수동적이지만 관리 가능합니다 - 비자 요건은 충분히 드물게 변경되어 연 4회 검토가 변경 사항의 95%를 커버합니다.
더 자주 업데이트되는 내용(환율, 사업 시간)에 대해서는 이 모델이 작동하지 않고 API가 더 합리적입니다. 비자 요건은 정적이 실제로 이긴 드문 경우입니다.
🔗 Chrome 웹 스토어의 EntryCheck: 설치










