Skip to content

Instantly share code, notes, and snippets.

@bang9
Last active April 22, 2024 11:49
Show Gist options
  • Save bang9/3b723dd7d6833d5025049862e9dbadf9 to your computer and use it in GitHub Desktop.
Save bang9/3b723dd7d6833d5025049862e9dbadf9 to your computer and use it in GitHub Desktop.
article

크롬에서 소스파일 업데이트 하여 디버깅하기.md

라이브러리를 개발하다보면 minified 된 코드를 디버깅해야만 하는 상황이 아주 가끔 생긴다. 사용자의 환경을 통째로 떼오고 싶지만, 그럴 수 없기때문에 재현을 위해서는 고객의 환경(사이트)에서 직접 테스트를 해보는것이 좋다.

재현을 하면서, 단순히 minified 된 코드를 살펴보는것을 넘어서, 직접 코드를 수정하여 로그까지 찍어본다면 더 좋을것 같은데 어떻게 할 수 있을까?

바로 Chrome 에서 지원하는 콘텐츠 override 기능을 사용하면 된다. (링크)

바로 살펴보자!


사이트 접속

우선 사이트에 접속하여 개발자 도구를 오픈하면 Sources 탭을 볼 수 있다. 그리고 좌측에 나타나는 Page 를 누르면, 현재 보고있는 페이지가 어떤 파일들을 서빙하여 돌아가고 있는지 볼 수 있다.

override

여기서 편집할 소스 혹은 파일을 우클릭한다. 네트워크 리소스(api 응답)에 대한 편집도 가능하다.

file resource network resource

클릭하면 상단에, 현재 리소스 파일을 저장하여 편집할 디렉토리를 선택하라고 알림이 나타난다.

경로를 지정하면 크롬에서 해당 경로에 대한 완전한 액세스를 요청한다. (파일 읽고 쓰기를 위해서)

지정을 하게 되면 Sources > Overrides 탭이 나타나게 되고, 여기서 리소스들을 편집하고 덮어쓸 수 있다. overrides 된 리소스들은 내 로컬에 있는 파일들이고, 브라우저가 실제 요청대신 이 파일들로 처리를 하게 된다.

실제 경로로 가보면 파일들이 저장되어 생성된걸 확인할 수 있다.


테스트

이제 코드를 편집하고 Command+S 등으로 저장을 하게 되면, 바로 로컬 파일에까지 저장이 된다.

그리고 새로고침하여 리소스를 다시 불러오면, 이런식으로 삽입한 코드들이 잘 실행되는걸 볼 수 있다.

JS 라이브러리 개발에서 살아남기

SDK 는 다양한 환경에서 돌아간다

자바스크립트는 브라우저 이외에도 아주 다양한 종류의 런타임(혹은 엔진) 위에서 돌아갈 수 있다. 그리고 각각은 스스로의 환경에 최적화 되어있기 때문에, 모두 제 각각이다. 자유분방한 언어의 특성으로 인해서 빌트인된 객체들의 편집이나 주입도 가능하기때문에, 이렇게 예측이 어려운 환경 위에서 돌아가는 코드를 작성해야 할때는 사이드 이펙트로부터 벗어나기 위해 고려해봄직한 요소들이 있다.

환경 찾기

JavaScript 로 작성된 SDK 는 다양한 환경에서 실행될 수 있기 때문에, 자세한 정보를 수집하거나 올바른 코드만을 실행하도록 예외 처리를 해주기 위해서 환경을 알아내는 작업들이 종종 필요하다. 만약 document 가 없는 환경에서 document 의 함수를 호출하게 되면 에러가 발생한다.

하나의 예시로 글로벌 스코프를 생각해볼 수 있는데, 브라우저에서만 사용되는 document 가 그 중 하나이다. 브라우저 환경인지 파악하기 위해서는 typeof document !== 'undefined' 같은 방식으로, 특정 환경에만 존재하는 객체가 존재하는지 체크를 할 수 있다.

하지만 우리가 염두해야 할 것은, 이 글로벌 스코프는 언제든지 오염이 될 수 있다는 점이다.

// Node.js
const isBrowser = () => (typeof document !== 'undefined')

isBrowser(); // false
document = {};
isBrowser(); // true

때문에 단순히 객체가 존재하는지 체크를 하는것에서 더 나아가서, 구체적으로 체크할 수 있는 방법이 있다면 사용하는것이 좋다. 예를 들면, React-Native 와 환경에서는 별도로 환경을 체크할 수 있는 플래그를 navigator.product 에 주입해주고 있다.

const isReactNative = () => (typeof navigator !== 'undefined' && navigator.product == 'ReactNative');

다시 한번 말하지만, SDK 가 사용되는 환경은 우리가 특정할 수 없기 때문에, 가장 최악의 상황을 가정하여 구체적인것만 사용하여 체크하는것이 좋다. 예를 들면 React-Native 환경에서 document 객체를 글로벌에 선언해놓고 사용하는 케이스도 있기때문에, document 등에 대한 체크는 하지 않고 React-Native 에서 제공해주는 플래그만을 체크하는것이 유리하고, 문제가 생기더라도 책임으로부터 어느정도 자유로워 질 수 있다(...)

빌트인 객체 오염

위에서 언급한 글로벌 스코프의 오염 이외에도, 빌트인 객체 또한 오염이 될 수 있다. 빌트인 객체란 언어에서 자체적으로 제공을 해줘야 하는 특별한 객체들을 의미한다. 예를 들면 Array 같은 객체가 대표적이다.

일반적으로 추천되지는 않지만, 편의를 위해서 다음과 같은 방식으로 확장을 하고 사용하는 경우들이 있다.

Array.prototype.sum = function() {
  return this.filter(it => typeof it === 'number').reduce((a,b) => (a+b), 0);
}

[1,2,3,'4'].sum(); // 6

일반적으로는 이미 존재하는걸 임의로 편집하는게 아니라 추가하는 것은 큰 문제가 되지 않겠다고 생각을 하지만, for ... in 문법을 사용할 때 문제가 생길 수 있다.

for...in 은 다른 반복문들과 다르게 스스로의 요소와 상속받은 요소들의 키까지 포함해서 순회를 하기 때문에, 빌트인 객체로부터 상속받은 prototype enumerable 프로퍼티가 있다면 뜬금없이 등장을 하게 된다.

Array.prototype.jsIsAmazing = function jsIsAmazing() {
  return this;
}

const arr = [1,2,3,4];
for (const i in arr) {
  console.log(arr[i]);
}
// 1
// 2
// 3
// 4
// f jsIsAmazing() { return this; }  누구세요??

이를 회피하기 위해서는 수행하기 전에 hasOwn/hasOwnProperty 등으로 객체 자신의 것인지 ownership 을 확인해주면 된다. (아니면 for...in 이 아닌 다른 반복문을 쓰거나)

Array.prototype.jsIsAmazing = function jsIsAmazing() {
  return this;
}

const arr = [1,2,3,4];
for (const i in arr) {
  if (Object.hasOwn(arr, i)) console.log(arr[i]);
}

// 1
// 2
// 3
// 4

참고 링크: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties

*만약 빌트인 객체의 프로토 타입을 확장시키고 싶다면 Object.defineProperty 를 사용하여 non-enumerable 로 만들어주자.

Object.defineProperty(Array.prototype, 'jsIsAmazing', {
  value: function() {
    return this;
  }
})

const arr = [1,2,3,4];
for (const i in arr) {
  console.log(arr[i]);
}
// 1
// 2
// 3
// 4

네이밍 관련 주의사항

일반적으로 마주할일이 없기는 한데, 만약 SDK 가 글로벌 스코프에 객체들을 할당을 하고 사용하는 방식이라면 네이밍에 주의하여야 한다. 하나의 예시로 paper.js 에서 사용하던 Symbol 객체가 글로벌 스코프의 Symbol 과 이름이 같아서 변경한 케이스가 있다.

paperjs/paper.js#1964 https://github.com/paperjs/paper.js/commit/bc2729683c2c9de992000f3a76f8882b13e00af0

객체 이름을 지을때는 빌트인 혹은 예약어에 쓰일법한 단어를 사용하기 보다는, 길고(?) 구체적인 이름을 짓자. 아니면 프로젝트의 약자를 prefix 로 붙이는것도 하나의 방법이다.

@AhyoungRyu
Copy link

👍 👍 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment