Summary
•
dayjs 라이브러리 를 사용하는 함수 → formatted와 관련된 모든 곳에서 다음과 같은 에러가 일어남.
•
TypeError: o is not a function
Impact
•
확인된 곳으로는 메인페이지와 회원가입 페이지에서 해당 에러로 인해 화면 로딩이 되지 않았음.
Solution
const dayjs = require('dayjs');
TypeScript
복사
위 코드를 아래 처럼 변경함.
import dayjs from 'dayjs';
TypeScript
복사
Dectection
•
QA께 전달 받음
Lesson Learned
잘 된 일
•
require 와 import 의 차이에 대해서 알게됨.
잘 안 된 일
•
로컬에서 는 정상작동하나 배포후 개발서버와 상용서버에서만 해당 에러가 일어났기 때문에 정확한 원인분석을 하지 못함.
운이 좋았던 일
•
정확하지는 않지만 미세하게나마 require와 import 의 차이를 알고 있었고 '해당 문제가 원인이지 않을까?' 라는 추측성이 적중함.
CommonJs, AMD, ES6 Module
•
require 와 import 에 대해서 비교해 보기 위해서는 우선 CommonJs와 AMD(Asynchronous Module Definition), ES6 내장모듈과 같은 자바스크립트의 모듈 시스템에 대해 알고 있어야 합니다.
•
자바스크립트 ES5는 모듈이라는 개념이 부족하여 각 모듈(또는 파일)간의 의존성 처리에 제한이 있었습니다.
•
고전적인 웹 프로젝트에서 자바스크립트를 사용하는 방법을 살펴보면, HTML 파일내부에 <script> 태그를 삽입하여 모듈을 로드하고 있습니다.
•
하지만 이런 방식은 한가지 문제가 있는데, 자바스크립트 파일(또는 모듈)끼리 서로 모듈을 공유하는데 제약이 없다는 점입니다. 그 이유는 <script> 태그로 로드된 모듈은 모두 window 객체의 속성이기 때문에 서로 다른 파일에 위치하면서도 모든 객체를 공유할 수 있기 때문입니다.
•
각 자바스크립트 파일이 독립적으로 존재하지 못해 발생하는 여러 문제들(예를들어 다른 파일에서 같은 이름의 변수를 사용하는 경우) 때문에 하나의 모듈로 관리하기위한 다양한 패턴(모듈패턴, 즉시실행함수 등)을 사용하여 의존성을 관리할 수 밖에 없었습니다.
이를 해결하기 위한 수단으로 모듈이라는 개념을 도입하여 정의한 방법(또는 표준)이 CommonJs 와 AMD 입니다. 이 둘은 내부적으로 모듈 서로 간의 의존성(로드)이 지원되지 않는 상태로 만들어졌는데, ES6 에 이르러 언어 내부적으로 자바스크립트 모듈 의존성을 지원하게 되었습니다(import, export).
모듈정의 방식의 혼용
ES6 모듈은 기본적으로 CommonJs 와 AMD 모듈을 혼용해서 사용할 수 있습니다. 모듈을 가져오는 부분에 require 와 import 를 같이 쓰더라도 문제없이 동작하죠.
import 는 ES6 문법이라 ES5를 사용하는 브라우저에서는 지원하지 않지만 babel 과 같은 트랜스파일러가 해결해줄수 있습니다. AMD 는 생략하고 ES6 와 CommonJs 를 비교하여 설명해보겠습니다.
모듈을 정의한다는 것은 다른 모듈에서 사용할 수 있도록 하나의 모듈로써 노출하겠다는 의미다.
모듈 정의하기 (export)
ES6
// 모듈 전체를 export, 파일내 한번만 사용가능하다.
var module = {};
export default module
// 모든 속성을 export
export *;
// 함수를 직접 export
export function moduleFunc() {};
var property = "some property";
export {property};
TypeScript
복사
CommonJs
// 모듈 전체를 export
module.exports = module
// 모든 속성을 export
// (아시는 분 알려주세요)
// 함수를 직접 export
exports.moduleFunc = function() {}
TypeScript
복사
모듈 가져오기 (import)
ES6
// 모듈 전체를 import
import module
import module as myModule
// 모든 속성 import
import * from module
// 특정 멤버(함수 등)만 import
import {moduleFunc, moduleFunc2} from module
TypeScript
복사
CommonJs
// 모듈 전체를 import
var module = require('./someModule.js')
// 모든 속성 import
// (위의 module 객체에 모든 속성이 담아져 온다.)
// 특정 멤버(함수 등)만 import, 위의 module을 이용한다.
module.moduleFunc
TypeScript
복사
결론
•
리액트에는 바벨과 같은 트랜스파일링 모듈이 내장되어 있기 때문에 주저없이 ES6(import)를 사용합니다.
•
실제로, CommonJS(require)와 ES6(import) 혼용하는것도 가능하다고는 하지만, 대부분의 커뮤니티에서는 가급적이면 통일되게 사용하는 것이 좋다고 주장하고 있으며, 실제로 에러를 유발할수도 있다고 하였고 저희 서비스가 해당 원인이 되었습니다.
•
팀장께서는 require는 NodeJS에서 사용하는 방법이고, import는 JavaScript에서 이용하는 방법이라고 설명해주셨습니다.