Skip to content

bugoverdose/mini-chrome

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mini Chrome

Chromium에 사용자 인터페이스(UI)를 추가한 구글 크롬 클론 코딩 프로젝트

데모

데모

상태 관리 (State Management)

  • 메인 프로세스에서 싱글톤 패턴으로 전역 상태 관리

    • 앱 실행 시점에 초기화되는 데이터
  • windows : 모든 Window 인스턴스. 각 윈도우에는 현재 실행 중인 BrowserWindow 인스턴스와 tabs 정보 등이 함께 관리됨.

    • id : browserWindow.id를 uid로 사용. 프로세스 간 통신을 위해 일치시키는 것이 용이함.
    • tabs : 특정 윈도우의 모든 Tab 인스턴스. 하나의 Tab 인스턴스에는 하나의 BrowserView 인스턴스와 tabId 정보가 함께 관리됨.
  • tabId : 하나의 탭이 생성될 때마다 1씩 증가. 각 탭의 uid로 배정되는 숫자 데이터.

데이터베이스

  • 로컬 머신에 JSON 파일로 저장하고 읽는 데이터 (custom-database.json)

  • 즐겨찾기 데이터는 favorites key에 배열로 저장

    • 개별 즐겨찾기 데이터 구조: ({ title, url, favicon })

IPC(프로세스 간 통신) 로직 핵심 요약

  • 특정 윈도우의 헤더 프로세스에서 메인 프로세스에 해당 윈도우 제거, 최소화, 최대화 토글 요청

  • 특정 윈도우의 헤더 프로세스에서 메인 프로세스에 tabs 정보를 요청하고, 데이터를 응답받아 화면의 html 태그 추가 및 내용 수정

  • 특정 윈도우의 뷰 프로세스에서 메인 프로세스에 개발자 도구 열기, 탭 제거 등의 요청하고, 메인 프로세스는 헤더 프로세스 혹은 해당 뷰 프로세스로 응답

구현할 기능 목록 (우테코 스타일)

윈도우

  • 앱 실행시, 맥에서 아이콘 클릭시 새 윈도우 생성

  • 창이 생성되면 생성된 창에 focus되도록 명시

    • 앱 실행시, 생성된 창에 focus시키고, 새 탭인 경우 omnibox에 초점이 오도록 설정
  • 창에 focus가 들어온 경우 창(browser window)으로 간 focus를 헤더(browser view)로 그대로 이동시키기 (개발자 입장에서는 포함 관계지만, 실질적으로 서로 별개의 프로세스)

    • 새 탭인 경우 화면의 어디를 클릭했던지와 무관하게, 무조건 omnibox로 초점이 오도록 설정

    • 새 탭이 아니라면 마지막으로 있던 위치에 초점 가도록 내버려두기

    • focus 탭 정보 업데이트 : 다른 창에서의 작업으로 즐겨찾기 정보가 변했을 수 있기 때문에 필요.

  • blur된(focus를 잃은) 윈도우는 deactivate시키기 (창이 1개일 때도 포함)

    • 헤더의 상단 부분의 배경색 회색으로

    • 모든 헤더의 버튼들 회색으로(traffic lights & view utils)

    • focus 다시 얻으면 원상복구

  • 페이지 뷰 내에서 새 창을 여는 경우 (링크를 shift + 클릭, target="_blank" 속성의 anchor 클릭 등), 디폴트 윈도우가 아닌 커스텀 윈도우를 생성하고 렌더링하도록

    • 디버깅: 순환참조 문제 때문에 app에 등록. 페이지 뷰만이 아니라 모든 web contents에 설정됨. (리소스 낭비)

헤더

헤더 배경

  • 마우스로 텍스트 부분만 따로 선택할 수 없도록 설정

  • 헤더 내 스크롤 생성 방지

  • 더블클릭시 toggle maximize

    • event delegation으로 다른 버튼들 더블클릭된 경우에는 동작하지 않도록 명시

신호등 컨트롤러

  • 윈도우든 맥이든 맥의 traffic lights 기능 그대로 구현

    • 화면 닫기
    • 화면 최소화
    • 전체화면 모드 토글
  • 특정 버튼을 누르고 있으면 해당 버튼만 살짝 어둡게 색상 변경

  • 특정 버튼 누른 상태로 마우스 이동시, 드래그되지 않도록 설정

  • 특정 버튼에 마우스 hover시 클릭했을 때 발생할 이벤트에 대한 설명 표시

  • focus되지 않은 윈도우에서는 세 버튼 모두 회색으로 설정

  • hover했을 때 관련 아이콘 보여주기 (보류)

  • title 속성으로 클릭하면 발생할 이벤트 설명 보여주기

  • 현재 윈도우에 존재하는 모든 view들에 대한 간략한 정보 표시

    • favicon
    • 디폴트 favicon
    • title 태그
  • 특정 탭에 마우스 hover시 탭에 대한 정보 출력

    • title 태그
    • url 정보
  • 새 탭 생성 기능 구현

    • 새 탭 생성 시점에 뷰 프로세스 갈아끼우기
    • 새 탭 생성 시점에 input에 키보드 자동 focus
    • 새 탭(=현재 화면에 보여지는 탭)은 다르게 보이도록 (focus)
    • 새 탭 생성시, 메인 프로세스로부터 응답받을 때까지 로딩 상태. 탭 영역 클릭 방지.
  • 기존 탭 삭제 기능 구현

    • 현재 focus된 탭을 닫는 경우 옆의 탭으로 focus 이동 + 페이지도 이동
  • 탭 클릭을 통해 화면에 보여주는 탭 변경

    • 현재 화면에 대응되는 탭은 다르게 보이도록 (focus)
  • 드래그 앤 드롭 기능 구현

    • 탭들 사이에서 좌우 이동시, 탭들의 순서 변경
    • 탭들의 영역을 벗어나는 경우 새로운 윈도우 생성
  • 반응형 디자인 구현

    • 탭의 최소 width는 창 닫는 버튼 크기
    • focus된 탭은 창 닫는 x 버튼을 위로
    • z-index: focus되지 않은 탭은 favicon + title을 위로
    • 탭의 개수가 너무 많으면 새 탭 생성 버튼이 위로 오도록

omnibox

  • input에 focus된 상태에서는 border를 파란색으로

  • input에 url 입력하여 해당 탭에 페이지 로드

  • url 대신 키워드 입력하는 경우 구글 검색으로 이동

  • 로드된 페이지의 title로 해당 탭 업데이트

  • 엔터 누르면 곧바로 omnibox에서 unfocus되어 동일한 url 반복 입력 방지 - blur()

  • 현재 view에 표시되는 주소가 변한 경우 omnibox에 해당 url 출력

    • url 입력에 따른 변화
    • 페이지 내 이동에 따른 변화
  • omnibox에 자체적으로 입력만 하고 전송하지 않은 데이터도 그대로 저장 (보류)

  • https:// 부분은 보이지 않도록 설정

view utils

  • 뒤로 버튼 구현

    • 뒤로 못 가는 경우 버튼 클릭 방지 및 어둡게
  • 앞으로 버튼 구현

    • 앞으로 못 가는 경우 버튼 클릭 방지 및 어둡게
  • 뒤로/앞으로 가는 경우 탭의 정보와 뒤로/앞으로 갈 수 있는지의 여부 업데이트

  • 새로고침/중지 버튼 구현

    • 로딩 중일 때는 중지 버튼으로 임시 변화
    • 로딩 종료 후 새로고침 버튼으로 다시 변화
  • title 속성으로 클릭하면 발생할 이벤트 설명 보여주기

favorites

  • 해당 데스크탑 내부에 자체적으로 즐겨찾기 목록 저장

    • 폴더 형식으로 즐겨찾기 목록 구조화
  • omnibox 내에 별 모양 아이콘을 통해 즐겨찾기 여부 확인 가능

  • 각 url에 대해 별 모양 토글하여 즐겨찾기 추가 및 제거

    • title 속성으로 클릭하면 발생할 이벤트 설명 보여주기

페이지

새 탭 화면

  • 새 창 생성 시점에 생성되는 탭에 url이 없는 경우에 보이는 디폴트 화면

  • 새 탭 생성 시점에 url이 없는 경우에만 보이는 디폴트 화면

  • 새 탭의 화면 내부에서 즐겨찾기 목록 보이도록

    • 즐겨찾기 favicon을 로드 실패하는 경우, 새 탭, 연결 실패한 경우의 아이콘인 경우 무조건 디폴트 아이콘을 보여주도록

    • 각 즐겨찾기 항목 클릭시, 현재 탭은 해당 url로 이동

  • title 속성으로 클릭하면 발생할 이벤트 설명 보여주기

  • 새 탭의 화면 내부에서 즐겨찾기 목록 수정 기능

    • 즐겨찾기 title 수정
    • 즐겨찾기 제거
    • 드래그 앤 드롭으로 즐겨찾기 목록 순서 수정

연결 실패 화면

  • 입력된 url로 페이지 로드 실패시, 실패 화면으로 이동

    • 실패화면에 omnibox에 입력한 url 정보와 에러 코드 출력
      • URI 디코딩을 통해 한국어 검색어 등 대응
    • 실패화면의 title에는 omnibox에 입력했던 검색어 그대로 출력
      • URI 디코딩을 통해 한국어 검색어 등 대응
    • favicon은 별도로 생성

뷰 페이지 context menu

  • 화면 내에서 우클릭시 기본 도구

    • 새 탭 열기
    • 새 창 열기
    • 개발자 도구 열기 기능
    • 새로고침
    • 뒤로
    • 앞으로
  • a 태그 우클릭시 링크 관련 도구

    • 새 탭에서 열기 기능
    • 새 창에서 열기 기능
    • 링크 주소 복사 기능

단축키

  • 최종적으로 Menu으로 마이그레이션

  • 개발자 도구 토글 : 현재 focus된 창에서 열린 탭의 View에 개발자 도구를 열고 닫기

    • 맥 : COMMAND+OPTION+I

    • 윈도우 : Ctrl+Shift+I

    • 공통 : F12

    • header : 개발자 도구 열릴 수 없도록 방지

    • 새 탭과 연결 실패 화면도 그냥 개발자 도구 열 수 있도록 설정. 굳이 막을 이유도 없고, 뒤로/앞으로 가는 경우 열려있던 개발자도구를 닫는 등 별도의 작업이 필요함.

  • 탭 닫기 : focus된 창의 focus된 탭을 닫고 다른 탭으로 focus를 이동시키는 단축키

    • 맥 : COMMAND+W
    • 윈도우 : CTRL+W
    • 마지막 탭이면 현재 창 닫고 다른 창으로 이동하도록 기존 api 그대로 사용
  • 새로고침, 뒤로가기, 앞으로가기, 로드 중지 등

  • 일단 event.preventDefault 설정하지 말고 디폴트 설정 그대로 사용

    • TAB으로 focus된 화면 내의 조작 가능한 영역들(anchor, input, etc) 순회

    • 선택된 a 태그를 엔터 입력으로 클릭

    • 텍스트 선택 후 잘라내기/복사/붙여넣기

  • 단축키: 구현 방법들과 각자의 특성

    1. global shortcut : 운영체제에 단축키 등록.

      • 문제점: 해당 앱이 선택되지 않은 상황에서도 실행됨. 다른 앱에 설정된 단축키를 덮어쓰게 됨.

      • 응용: 운영체제에 global shortcut을 등록하고 제거하는 작업을 앱에 초점이 들어오고 나갈 때마다 반복

        app.on('focus', registerAllGlobalShortcuts())
        app.on('blur', globalShortcut.unregisterAll())
      
    2. menu : 해당 앱에 초점이 맞춰진 상황에서만 실행 가능한 단축키 등록 가능. (권장사항)

      • 초점이 맞추어진 browserWindow를 변수로 받아 작업 가능.
      • 맥에서는 앱 외부의 상단의 메뉴를 클릭하여 단축키 목록 조회 및 실행 가능.
      • 윈도우와 리눅스에서는 목록을 숨길 수 있음.
    3. 로드되는 파일 자체에 renderer로 이벤트리스너 추가: 가장 구체적인 방법.

    4. webcontents에 사용자 입력에 대한 이벤트리스너 등록

      • 주의. 창에 등록되는 것이 아니라 특정 webcontents에 focus가 간 상태에서만 동작. browserWindow에 초점이 간 경우, browserView에 등록된 단축키는 동작하지 않음.

      • 주의: fn 없이 F1~F12 등의 function key를 실행할 수 있도록 운영체제가 설정된 경우 function key 입력 인식 불가능. (Mac)

      // 모든 webcontents에 동일한 단축키 등록하는 예제
      app.on('web-contents-created', function (event, wc) {
        wc.on('before-input-event', function (event, input) {
          if (input.key === 'x' && input.ctrl && !input.alt && !input.meta && !input.shift) {
            // Do something for Ctrl-X
            event.preventDefault()
          }
        })
      })
      

디버그

  • windowId 필요 : 2번째 창을 여는 경우 ipcRenderer 중복 등록 문제 발생

  • 탭을 무한 생성하고 focus tab을 제거하는 경우, 다음 focus tab id로 자기 자신을 선택하는 버그 - 구조 뜯어고칠 때 수정 누락됨

  • 네트워크 불안정에 대한 예외처리 화면 추가

  • webContents.openDevTools()를 통해 개발자도구를 여는 경우 SyntaxError: Unexpected end of JSON input 경고문 출력

  • favicon 로드 실패에 대한 예외처리 필요

    • 디폴트 탭 favicon을 대신 보여주기
    • 이에 따라 복수의 favicon이 생성될 수 있는 상황 디버깅: 1개의 favicon만 존재하도록 cleanse
    • favicon 로딩을 실패한 프로세스에서 omnibox에 url을 입력하는 경우, 앱 전체가 다운되는 문제
  • 모든 기능에 대한 기기 호환성 체크 필요

  • 더블 클릭 방지 : loading 여부에 따라 잠시 동안 조작 불가능하도록

  • 메인 프로세스에서는 당연히 focusTabIdx 대신 focusTabId를 관리

  • 이미 focus된 탭 클릭하는 경우 토글하는 것으로 간주하지 말기. 무의미한 재렌더링으로 인한 성능 저하.

  • cover up ugly border left of focus tab

About

Google Chrome clone coding (feat. Electron)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published