Skip to main content

인포메이트 2주차 공유(브라우저)

· 21 min read

인포메이트 2주차 공유(브라우저) 모음입니다.

아니 왜 로컬에서는 잘 되는데 사파리는 안되는거지? - 윤해진
Cache-Control, Expires를 빠뜨리면 브라우저에서 무슨 일이 일어날까? - 김하나
브라우저가 숨기는 디버깅 비밀! 이런 트릭들 알고 계셨나요? - 곽승주

아니 왜 로컬에서는 잘 되는데 사파리는 안되는거지? - 윤해진

intro

개발을 할 때 보통 크롬을 사용해 작업을 하게 됩니다. 그때는 아무 문제가 없었던 기능 혹 css가 사파리나 다른 브라우저에서는 깨지는 경우가 생기곤 합니다. 따라서 해당 개념과 연관 지어 크로스 브라우징에 대해 글을 작성해 보았습니다!

크로스 브라우징이란?

  • 다양한 브라우저 속에서도 서로 호환이 가능한 상호 호환성을 의미합니다.

어느 한쪽에 최적화되지 않고, 공통 요소를 사용하여 웹 페이지를 제작하는 기법으로 동등한 수준의 정보, 기능 접근에 초점을 맞추는 것입니다.

예를 들어 제가 많이 겪어보았던 것은 css와 관련되어 chrome에서는 정상적인 페이지가 safari에서만 width가 맞춰지지 않아 화면 x축으로 스크롤이 되던 경험이 있습니다.

그 외에도

  • 작동하지 않은 HTML5, Javascript 코드가 존재
  • 해석하지 못하는 CSS 코드 존재
  • 브라우저 버그들이 존재
  • 브라우저 자체적인 CSS 스타일

위 경우처럼 같은 코드여도 사용자가 접근하는 브라우저마다 다른 결과물을 보인다는 것은 사용성에 있어 매우 좋지 않은 것이라고 모두 느끼실 겁니다.

왜 일어나는 것일까?

  • 이유는 OS가 다르고, 브라우저마다 ‘렌더링 엔진’이 다르기 때문입니다.

이 말은 즉 결국 동일하게 안 만드는 것이 아니라 애초부터 동일하게 만드는 것은 ‘불가능한 일’이라고도 할 수 있겠습니다.

  • 렌더링 엔진: 화면에 텍스트와 이미지 등을 그리는 SW. HTML 을 요청하면 요청에 따른 적절한 파싱 하여 화면에 표시합니다.

그렇다면 어떻게 처리하지?

  • can i use (웹 사이트) https://caniuse.com/?search=grid 위 페이지는 브라우저마다의 css 사용 및 호환 가능 여부를 알려주는 고마운 페이지입니다. 예로 gird라는 속성의 각 브라우저의 호환 가능 여부를 알아보고 싶을 때 해당 사이트에 검색을 하면 다양한 브라우저에서 해당 속성이 사용 가능한지 보기 쉽게 나타냅니다.
  • 모질라 MDN (웹 사이트) https://developer.mozilla.org/ko/ 개발을 하며 정말 많이 들어가 보는 페이지 중 하나일 MDN에서도 브라우저 호환성을 확인할 수 있습니다. 검색한 키워드 내용의 최하단에 브라우저 별 호환 관련 정보가 정리되어 있어 찾고자 하는 속성을 검색 후 아래에서 특이하게 적용이 안되는 브라우저가 있는지 확인해 볼 수 있습니다.
  • CSS 초기화 ‘웹 브라우저'마다 default 값으로 스타일이 적용되어 있습니다. 따라서 브라우저마다의 기본 스타일을 없앰으로 초깃값을을 동일하게 하여 지면을 평평하게 만드는 작업을 통해 이후 개발에 차질이 없게 하는 것으로 크로스 브라우징을 예방할 수 있습니다.

💻브라우저 별 벤더프리픽스 (이런것도 있어요!)

웹 브라우저 공급자가 새로운 실험적인 기능을 제공할 때 이전 버전의 웹 브라우저에 그 사실을 알려주기 위해 사용하는 접두사(prefix)를 의미. ⇒ CSS에 새로운 속성을 추가하기 전 임시적으로 접두어를 사용하는 것.

  • 크롬, 사파리 : -webkit-
  • 파이어폭스 : moz- (mozila 라는 단체가 파이어폭스를 만들었기 때문에)
  • 오페라 : -o-
  • 익스플로러 : -ms-
background: red;   <!-- gradient 속성을 지원하지 않는 모든 브라우저를 위한 코드 -->
background: -webkit-linear-gradient(red, yellow); <!-- 크롬과 사파리 4.0 이상을 위한 코드 -->
background: -moz-linear-gradient(red, yellow); <!-- 파이어폭스 3.6 이상을 위한 코드 -->
background: -ms-linear-gradient(red, yellow); <!-- 익스플로러 10.0 이상을 위한 코드 -->
background: -o-linear-gradient(red, yellow); <!-- 오페라 10.0 이상을 위한 코드 -->
background: linear-gradient(red, yellow); <!-- CSS 표준 문법 코드 -->

Cache-Control, Expires를 빠뜨리면 브라우저에서 무슨 일이 일어날까? - 김하나

http 캐시를 적극적으로 설정하고 제어함으로써 웹 성능을 높일 수 있다는 사실을 알고 계신가요?

현재 우리 프론트엔드 트랙에서 캐시 설정을 직접 다루지는 않습니다. 그렇지만 앞으로의 웹 성능과 이해를 위해 다양한 생명 주기를 가지는 캐시를 다루는 방법에 대해 아는것은 꼭 필요합니다.

그런데 브라우저 캐시 관련 헤더인 Cache-Control , Exprires 를 빠뜨리면 무슨 일이 일어날까요? 또한 브라우저 캐시 설정이 왜 중요할까요?

웹 캐시

  • 실제 작업을 하며 빌드된 사항이 적용이 안될때 캐시 삭제해라 강한 새로고침 해라 등등의 말을 들은 적이 있을 겁니다.(cc. 최원빈님) 이것들도 브라우저 캐시와 관련된 사항이라고 볼 수 있죠.
  • 클라이언트는 서버로부터 HTTP 요청을 통해 필요한 리소스 (HTML, CSS, JS, 이미지 등)를 불러옵니다. 네트워크를 통해 이 과정을 수행하는건 느리고 비용이 많이 듭니다.
  • 여기서 발생할 수 있는 불필요한 네트워크 재요청을 방지하기 위해 웹 캐싱을 사용합니다.
  • Cache-Control Expries 등과 같은 우리가 자주 봐온 헤더는 캐시 동작과 관련된 헤더로, 서버의 비용을 줄이고 클라이언트의 성능을 향상시키는 데 유용하게 사용됩니다.

Cache-Control, Expires 헤더를 기입하지 않은 경우

  • 누군가 의도했든 의도하지 않았든 Cache-Control Expires 헤더 모두 기입하지 않은 경우, 브라우저는 어떻게 동작할까요?
  • 대표적인 브라우저인 크롬의 캐시 동작을 살펴보기 위해 Chromium의 코드를 확인해보았습니다.
HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const {
FreshnessLifetimes lifetimes;
if (HasHeaderValue("cache-control", "no-cache") ||
HasHeaderValue("cache-control", "no-store") ||
HasHeaderValue("pragma", "no-cache")) {
return lifetimes;
}
...
if ((response_code_ == net::HTTP_OK ||
response_code_ == net::HTTP_NON_AUTHORITATIVE_INFORMATION ||
response_code_ == net::HTTP_PARTIAL_CONTENT) &&
!must_revalidate) {
// TODO(darin): Implement a smarter heuristic.
Time last_modified_value;
if (GetLastModifiedValue(&last_modified_value)) {
// The last-modified value can be a date in the future!
if (last_modified_value <= date_value) {
lifetimes.freshness = (date_value - last_modified_value) / 10; //여기!
return lifetimes;
}
}
}
  • Chromium의 http_response_headers.cc 를 살펴보니 freshness(유효성)이 (date_value - last_modfied_value) / 10 로 할당되는 것 같습니다.
  • 이는 Date와 LastModified의 차이값의 10분의 1로 추정하여 유효성(freshness) 계산을 한다는 것입니다. MDN 문서를 보니 heuristic 이라는 동작으로 캐시 헤더를 지정하지 않으면 웹 스팩을 기반으로 대략적으로 캐시 작동을 합니다.

그럼 캐시도 알아서 동작하니 문제가 없는걸까?

휴리스틱 캐시는 문제가 많이 생겨날 수 있습니다. 컨텐츠 배포를 했더라도 웹 배포후 특정 기기에서 이전 캐시 된 콘텐츠가 노출될 수 있고, 변경사항이 실제로 적용되는데 더 많은 시간이 걸릴 수 있습니다.

간단한 해결책으로는 사용자가 캐시를 비워 리소스를 새로 가져오도록 하는 것 입니다.

실제 개발자 창을 열고 새로고침 버튼을 우클릭하면 ‘캐시 비우기 및 강력 새로고침’ 을 선택할 수 있습니다.

그러나 근본적으로 캐싱에 관한 문제가 발생하면 명시적으로 헤더를 설정하여 캐시 문제를 해결해주는게 좋다고 생각합니다. 캐시 유효시간을 사용하여 정확한 시간에 업데이트를 보장하는 방법을 써보면 좋을것같습니다.

실제 토스에서는 html은 배포 주기에 체크되어야 하는 리소스이기 때문에 Cache-Control 값으로 max-age=0, s-maxage=31536000 을 설정한다고 합니다. 그러나 JavaScript 나 CSS 파일은 프론트엔드 웹 서비스를 빌드할 때마다 새로 변경사항이 적용될 수 있도록 임의 버전 번호를 부여해 설정합니다.

⇒ 만약 토스의 캐시 설정에 대해 더 자세히 알고싶다면 여기를 클릭

요약

  1. 브라우저 캐시 설정을 따로 하지 않을 경우 크롬, 사파리 등의 브라우저는 알아서 캐시 동작을 해줍니다.
  2. 자동으로 캐시 설정이 된다는건 문제가 발생할 수 있는 지점이기 때문에 이를 확인해주는것이 중요합니다.
  3. 각각의 특성에 따라 캐시를 섬세히 제어함으로 안전하고 빠르게 HTTP 리소스를 로드할 수 있으며, 트래픽 비용을 절감할 수 있습니다.

참고자료

브라우저가 숨기는 디버깅 비밀! 이런 트릭들 알고 계셨나요? - 곽승주

Intro

브라우저의 디버거를 최대한 활용하기 위한 유용하지만 뻔하지 않은 방법들입니다. 개발자 도구에 대한 기본 이해를 가지고 있다고 가정합니다.

조건부 중단점 활용

로그 지점 / 추적 지점

조건부 중단점에서 console.log를 사용하거나 로그 지점을 사용할 수 있습니다. 로그 지점은 실행을 일시 중지하지 않고 콘솔에 기록하는 중단점입니다.

영상 참고

1. 감시 창(Watch pane)

감시 창에서 console.log를 사용할 수도 있습니다. 예를 들어, 디버거에서 앱이 중단될 때마다 localStorage의 스냅샷을 덤프하고 싶다면 console.table(loaclStorage) 감지를 생성할 수 있습니다.

이미지

2. 호출 스택 추적

console.trace를 사용하여 코드를 실행하면 호출되는 라인을 확인할 수 있습니다.

이미지

프로그램 동작 변경하기

프로그램 동작에 사이드 이펙트가 있는 표현식을 사용하면 브라우저에서 바로 프로그램 동작을 변경할 수 있습니다.

예를 들어 getPerson 함수의 매개변수를 재정의할 수 있습니다. 재정의 시 id=1true로 평가되므로 이 조건부 중단점은 디버거를 일시 중지합니다. 이를 방지하려면 표현식에 false를 추가하면 됩니다.

영상 참고

시간 측정

무언가를 실행하는 데 걸리는 시간을 빠르고 간단하게 측정하고 싶다면 조건부 중단점에서 콘솔 타이밍 API를 사용할 수 있습니다. 시작 지점에 console.time(’label’) 조건으로 중단점을 설정하고 종료 지점에 console.timeEnd(’label’) 조건으로 중단점을 설정하면 됩니다.

영상 참고

함수의 항수(Arity) 활용

1. 인자 개수에 따른 중단

예를 들어, 현재 함수가 3개의 인수로 호출될 때만 일시 중지할 때입니다. argument.callee.length===3

이미지

2. 항수 불일치 시 중단

현재 함수가 잘못된 인수 개수로 호출될 때만 일시 중지합니다. (arguments.callee.length) != arguments.length

이미지

함수 호출부의 버그를 찾을 때 유용합니다.

시간 활용

1. 페이지 로드 스킵

페이지 로드 후 5초 동안 어떠한 중단점에도 일시 중지하지 않기 performance.now() > 5000

중단점을 설정하고 싶지만 초기 페이지 로드 후 실행을 일시 중지하는 데만 관심이 있는 경우에 유용합니다.

2. N초 스킵하기

다음 5초 이내에 중단점에 도달하면 실행을 일시 중지하지 않고, 그 이후에는 언제든지 일시 중지합니다. window.baseline = window.baseline || Date.now(), (Date.now() - window.baseline) > 5000

원하는 경우 언제든지 콘솔에서 카운터를 재설정합니다. window.baseline=Date.now()

CSS 사용

계산된 CSS 값에 따라 일시 중지하기(예: document.body의 배경색이 빨간색일 때만 일시 중지): window.getComputedStyle(document.body).backgroundColor === “rgb(255,0,0)”

짝수 호출만

줄이 짝수 번 실행될 때마다 일시 중지: window.counter = window.counter || 0, window.counter % 2 === 0

절대 중단시키지 않기

크롬에서 “Never Pause Here”을 선택하면 false인 조건부 중단점을 생성합니다. 이를 통해 디버거는 이 라인에서 절대 일시 중지되지 않습니다.

XHR 중단점에서 한 줄을 제외하거나, 예외가 발생했을 때 이를 무시하고 싶을 때 유용합니다.

프로퍼티 읽기 디버깅

객체가 있고 그 객체에서 프로퍼티를 읽을 때마다 알고 싶다면 debugger 호출과 함께 객체 getter를 사용하세요. 어떤 설정 옵션을 전달할 때 그 옵션이 어떻게 사용되는지 보고 싶을 때 유용합니다.

copy() 활용

copy() 콘솔 API를 사용하면 문자열을 잘라내지 않고도 브라우저에서 관심이 있는 정보를 클립보드로 바로 복사할 수 있습니다.

  • 현재 DOM 스냅샷: copy(document.documentElement.outerHTML)
  • localStorage 덤프: copy(localStorage)

HTML / CSS 디버깅

JS 비활성화 상태에서 DOM 검사하기

DOM 인스펙터에서 crtl+\를 누르면 JS 실행을 언제든 멈춥니다. 이를 통해 JS가 DOM을 변형하거나 이벤트(예: 마우스 오버)로 인해 DOM이 변경될 염려 없이 DOM의 스냅샷을 검사할 수 있습니다.

찾기 어려운 요소 검사

조건부로만 표시되는 DOM 요소를 검사하고 싶다고 가정해 보겠습니다. 해당 요소를 검사하려면 마우스를 해당 요소로 이동해야 하는데, 마우스를 이동하려고 하면 해당 요소가 사라집니다.

영상 참고

setTimeout(function() {debugger; }, 5000); 이렇게 하면 5초 동안 UI를 트리거할 수 있으며, 5초 타이머가 끝나면 JS 실행이 일시 중지되고 요소가 사라지지 않습니다.

영상 참고

현재 선택된 요소 참조

콘솔에서 $0은 요소 인스펙터에서 현재 선택된 요소를 자동으로 참조합니다.

이전 요소

크롬엣지에서는 $1로 마지막으로 검사한 요소, $2로 그 이전 요소 등에 접근할 수 있습니다.

이벤트 리스너 가져오기

크롬에서는 현재 선택된 요소의 모든 이벤트 리스너를 조사할 수 있습니다: getEventListener($0)

요약

브라우저(주로 크롬)에는 정말 무수히 활용 가능한 디버깅 트릭들이 있습니다. 기본적인 중단점 사용 외에 다양한 중단 조건을 걸어 중단 여부를 결정할 수 있는 방법이나 중단점을 사용하여 요소 값을 알아내기 어려운 경우 등에서 디버깅하는 방법과 같이 디버거를 최대한 활용해 디버깅할 수 있습니다. 나중에 “이럴 땐 어떻게 디버깅하지”라는 생각이 드실 때 한 번씩 확인해 보면 좋을 것 같습니다.