JavaScript 스타일 가이드

대부분의 JavaScript 스타일 지침을 관리하기 위해 Airbnb JavaScript Style Guide 및 그에 따르는 린터를 사용합니다.

Airbnb에서 설정한 스타일 가이드 외에도 몇 가지 특정 규칙이 있습니다.

note
yarn run lint:eslint:all 또는 yarn run lint:eslint $PATH_TO_FILE를 실행하여 ESLint를 로컬에서 실행할 수 있습니다.

forEach 피하기

데이터를 변형할 때 forEach를 피하십시오. 데이터를 변형할 때는 forEach 대신 map, reduce 또는 filter를 사용하십시오. 이는 함수 내에서의 변이를 최소화하여 Airbnb 스타일 가이드와 일치합니다.

// 안 좋은 예
users.forEach((user, index) => {
  user.id = index;
});

// 좋은 예
const usersWithId = users.map((user, index) => {
  return Object.assign({}, user, { id: index });
});

매개변수 개수 제한

함수 또는 메소드의 매개변수가 3개를 초과하면 대신 객체를 매개변수로 사용하십시오.

// 안 좋은 예
function a(p1, p2, p3, p4) {
  // ...
};

// 좋은 예
function a({ p1, p2, p3, p4 }) {
  // ...
};

DOM 이벤트를 처리하기 위해 클래스 피하기

클래스의 유일한 목적이 DOM 이벤트를 바인딩하고 콜백을 처리하는 것이라면 함수를 사용하는 것이 좋습니다.

// 안 좋은 예
class myClass {
  constructor(config) {
    this.config = config;
  }
  
  init() {
    document.addEventListener('click', () => {});
  }
}

// 좋은 예
const myFunction = () => {
  document.addEventListener('click', () => {
    // 여기서 콜백 처리
  });
}

생성자에 요소 컨테이너 전달

클래스가 DOM을 조작하는 경우 요소 컨테이너를 매개변수로 받아들입니다. 이것이 유지보수하기에 더 좋고 성능적으로 우수합니다.

// 안 좋은 예
class a {
  constructor() {
    document.querySelector('.b');
  }
}

// 좋은 예
class a {
  constructor(options) {
    options.container.querySelector('.b');
  }
}

문자열을 정수로 변환

문자열을 정수로 변환할 때 Number를 사용하는 것이 의미론적이고 더 가독성이 좋습니다. 둘 다 허용되지만 Number가 약간의 유지보수상 이점이 있습니다.

경고: parseInt진수 인수를 포함해야 합니다.

// 안 좋은 예 (진수 인수 누락)
parseInt('10');

// 좋은 예
parseInt("106", 10);

// 좋은 예
Number("106");
// 안 좋은 예 (진수 인수 누락)
things.map(parseInt);

// 좋은 예
things.map(Number);
note
문자열이 정수가 아닌 경우(예: 소수점을 포함하는 경우) parseInt를 사용하지 마십시오. 대신 Number 또는 parseFloat를 고려하십시오.

CSS 선택자 - js- 접두어 사용

CSS 클래스가 요소에 대한 참조로만 JavaScript에서 사용된다면 클래스 이름에 js- 접두어를 붙이세요.

// 안 좋은 예
<button class="add-user"></button>

// 좋은 예
<button class="js-add-user"></button>

ES 모듈 구문

대부분의 JavaScript 파일에 대해 ES 모듈 구문을 사용하여 모듈에서 가져오거나 내보내세요. 이름이 지정된 내보내기를 선호하십시오. 이는 이름의 일관성을 높이게 합니다.

// 안 좋은 예 (예외 사항이 있음, 아래 참조)
export default SomeClass;
import SomeClass from 'file';

// 좋은 예
export { SomeClass };
import { SomeClass } from 'file';

기본 내보내기를 사용하는 것은 특정한 상황에서 허용됩니다:

  • Vue 단일 파일 컴포넌트 (SFC)
  • Vuex 뮤테이션 파일

자세한 정보는 RFC 20을 참조하세요.

CommonJS 모듈 구문

우리의 Node 구성은 CommonJS 모듈 구문을 요구합니다. 이름이 지정된 내보내기를 선호하세요.

// 안 좋은 예
module.exports = SomeClass;
const SomeClass = require('./some_class');

// 좋은 예
module.exports = { SomeClass };
const { SomeClass } = require('./some_class');

모듈에 대한 절대 vs 상대 경로

가져오는 모듈이 두 단계 이하인 경우 상대 경로를 사용하세요.

// 안 좋은 예
import GitLabStyleGuide from '~/guides/GitLabStyleGuide';

// 좋은 예
import GitLabStyleGuide from '../GitLabStyleGuide';

가져오는 모듈이 두 단계 이상인 경우 대신 절대 경로를 사용하세요:

// 안 좋은 예
import GitLabStyleGuide from '../../../guides/GitLabStyleGuide';

// 좋은 예
import GitLabStyleGuide from '~/GitLabStyleGuide';

또한 전역 네임스페이스에 추가하지 마십시오.

페이지 이외의 모듈에서 DOMContentLoaded 사용하지 않기

가져온 모듈은 로드될 때마다 동일하게 작동해야 합니다. DOMContentLoaded 이벤트는 webpack에서 동적으로 로드되는 /pages/* 디렉터리에 로드되는 모듈에서만 허용됩니다.

XSS 피하기

콘텐츠를 설정하기 위해 innerHTML, append() 또는 html()을 사용하지 마십시오. 이로 인해 많은 취약점이 발생할 수 있습니다.

ESLint

ESLint 동작은 도구 가이드에서 찾을 수 있습니다.

IIFEs

즉시 호출 함수 표현(IIFEs) 사용을 피하세요. 많은 예에서 파일이 IIFEs로 둘러싸인 것이 있지만 Sprockets에서 webpack으로의 전환 이후로 더 이상 필요하지 않습니다. 더 이상 사용하지 마세요.

전역 네임스페이스

전역 네임스페이스에 추가하지 마세요.

// 안 좋은 예
window.MyClass = class { /* ... */ };

// 좋은 
export default class MyClass { /* ... */ }

부작용

최상위 부작용

export를 포함하는 모든 스크립트에서 최상위 부작용을 금지합니다:

// 안 좋은 예
export default class MyClass { /* ... */ }

document.addEventListener("DOMContentLoaded", function(event) {
  new MyClass();
}

생성자에서 부작용 피하기

constructor에서 비동기 호출, API 요청 또는 DOM 조작을 피하세요. 대신 별도의 함수로 이동하세요. 이렇게 하면 테스트를 작성하기 쉬워지고 단일 책임 원칙을 위반하는 것을 피할 수 있습니다.

// 안 좋은 예
class myClass {
  constructor(config) {
    this.config = config;
    axios.get(this.config.endpoint)
  }
}

// 좋은 예
class myClass {
  constructor(config) {
    this.config = config;
  }
  
  makeRequest() {
    axios.get(this.config.endpoint)
  }
}
const instance = new myClass();
instance.makeRequest();

순수 함수 및 데이터 변형

많은 작은 순수 함수를 작성하고 변이가 발생하는 곳을 최소화하세요.

// 안 좋은 예
const values = {foo: 1};

function impureFunction(items) {
  const bar = 1;
  
  items.foo = items.a * bar + 2;
  
  return items.a;
}

const c = impureFunction(values);

// 좋은 예
var values = {foo: 1};

function pureFunction (foo) {
  var bar = 1;
  
  foo = foo * bar + 2;
  
  return foo;
}

var c = pureFunction(values.foo);

상수를 기본형으로 내보내기

일관성 있는 이름 확인을 위해 상수를 일반적인 네임스페이스와 함께 기본형으로 내보내는 것이 좋습니다. 이는 런타임에 실수로 undefined를 방지하고 번들 크기를 줄이는 데 도움이 됩니다.

반복 기능이 필요한 경우만 상수를 컬렉션(배열 또는 객체)로 내보내세요.

// 안 좋은 예
export const VARIANT = {
  WARNING: 'warning',
  ERROR: 'error',
};

// 좋은 예
export const VARIANT_WARNING = 'warning';
export const VARIANT_ERROR = 'error';

// 좋은 예, 상수를 반복해야 하는 경우
export const VARIANTS = [VARIANT_WARNING, VARIANT_ERROR];

오류 처리

서버에서 500을 반환하는 내부 서버 오류의 경우 일반 오류 메시지를 반환해야 합니다.

백엔드에서 오류가 발생할 때, 해당 오류는 사용자에게 표시하기 적합해야 합니다.

만약 어떤 이유로 인해 그것이 어렵다면, 마지막 수단으로 접두어가 붙은 특정 오류 메시지를 선택할 수 있습니다:

  1. 백엔드는 표시될 오류 메시지에 접두어를 붙이도록 해야 합니다:

    Gitlab::Utils::ErrorMessage.to_user_facing('예시 사용자 대상 오류 메시지')
    
  2. app/assets/javascripts/lib/utils/error_message.js에 포함된 오류 메시지 유틸리티 함수를 사용하세요.

이 유틸리티는 두 개의 매개변수를 받습니다: 서버 응답에서 받은 오류 객체와 기본 오류 메시지입니다. 유틸리티는 오류 객체의 메시지를 분석하여 해당 메시지가 사용자에게 표시될 것인지 여부를 나타내는 접두사를 확인합니다. 메시지가 사용자에게 표시될 경우 해당 메시지를 그대로 반환하고, 그렇지 않은 경우 매개변수로 전달된 기본 오류 메시지를 반환합니다.

import { parseErrorMessage } from '~/lib/utils/error_message';

onError(error) {
  const errorMessage = parseErrorMessage(error, genericErrorText);
}

이 접두사를 API 응답에 사용해서는 안 됩니다. 대신 REST API 또는 GraphQL 가이드의 지침을 따라 오류 객체를 처리하세요.