Babel의 Import 성능 개선 PR이 7.6.0 버전에 포함됐습니다. 👏
Babel을 최신 버전으로 업데이트하시면 추가 작업 없이도 React Native의 초기 실행 속도가 개선되는데요. 어떤 작업이 있었는지 이야기해볼게요. 별 내용 없지만 재미있게 봐주세요.
React Native 플랫폼 위에서 우리가 작성한 코드는 Babel과 Metro를 거쳐 하나의 큰 자바스크립트 파일(번들)로 만들어집니다. 불현듯 이 파일이 어떻게 만들어졌는지 들여다보고 싶어지는 날이 있어요. 의도한 것과는 다르게 변환된 코드를 찾고 그 이유를 유츄하는 과정이 꽤 흥미롭기 때문인데요. 여러분도 한 번씩 해보세요.
프로젝트 루트 디렉터리에서 아래처럼 react-native bundle
명령을 실행하면 Babel로 트랜스 파일링 된 코드들을 Metro가 index.android.js
파일로 번들링 하게 됩니다.
$ mkdir android/app/src/main/assets
$ react-native bundle --platform android --dev true --entry-file index.js --bundle-output android/app/src/main/assets/index.android.js --assets-dest android/app/src/main/res/
import React, { PureComponent } from 'react';
컴포넌트 파일을 만들 때 템플릿처럼 사용하는 코드인데요. wildcard 방식의 import가 React Native에서는 아래처럼 변환됩니다.
var _interopRequireWildcard = _$$_REQUIRE(_dependencyMap[1], "@babel/runtime/helpers/interopRequireWildcard");
var _react = _interopRequireWildcard(_$$_REQUIRE(_dependencyMap[7], "react"));
@babel/runtime/helpers/interopRequireWildcard.js 코드는 아래와 같고요.
function _interopRequireWildcard(obj) {
if (obj && obj.__esModule) {
return obj;
} else {
var newObj = {};
if (obj != null) {
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};
if (desc.get || desc.set) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
}
newObj["default"] = obj;
return newObj;
}
}
module.exports = _interopRequireWildcard;
react
모듈은 ES 형식의 모듈이 아니기 때문에 else 절의 로직을 타게 되는데 여기서 문제가 호출마다 for 루프를 돌면서 프로퍼티를 체크하고 새롭게 만든 newObj 객체에 값을 넣어 반환한다는 거죠. react
의 경우 29번의 루프를 돌게 되는데 1,000개의 컴포넌트를 사용하면 29,000번 루프가 실행되는데 이건 너무 비효율적인 것 같아요.
모듈마다 for 루프를 거쳐 만들어진 최종 객체를 캐시 처리하면 1,000개의 컴포넌트를 사용해도 react
모듈 관련해서는 최초 29번의 루프 순회만 발생합니다. import를 처리하기 위한 비용이 zero에 가까워졌다고 보셔도 됩니다. 이제 조금 효율적으로 보이네요 :)
아래 처럼 변경이 됐어요.