[21/09/19] Junzzi Editor 프로젝트 셋팅 - (2) 타입스크립트 설정 - 트리쉐이킹
Junzzi Editor는 오즈의 제작소 프로젝트에 사용될 에디터 모듈입니다.
타입스크립트
타입스크립트는 자바스크립트의 superset
이며, 동적 타입 언어인 자바스크립트와는 달리 정적 타입 기능을 제공한다. 따라서 컴파일 단에 에러를 추적할 수 있어, 기존의 런타임에서 발견되는 이슈들을 빠른 타임에 해결할 수 있다.
우리 프로젝트 또한 이러한 이점을 가져가기 위해 타입스크립트를 적용하였다. 타입스크립트를 적용하기위해 필요한 사항들을 정리해보았다.
module 설치
타입스크립트 컴파일러인 tsc가 타입스크립트 코드를 자바스크립트 코드로 변환한다. 하지만 웹팩과 동시에 사용하도록 하기위해 ts-loader를 사용한다.
리액트에선 타입스크립트를 위한 타입들을 제공하지 않기 때문에 @types/react @types/react-dom
같은 추가적인 라이브러리의 설치가 필요하다.
npm install typescript ts-loader @types/react @types/react-dom
프로젝트 폴더에 tsconfig.json파일을 작성
tsconfig.json파일은 루트 파일과 프로젝트를 컴파일하는 데 필요한 컴파일러 옵션을 지정합니다.
JavaScript 프로젝트는 jsconfig.json파일을 대신 사용할 수 있습니다. 이 파일은 거의 동일하게 작동하지만 기본적으로 일부 JavaScript 관련 컴파일러 플래그가 활성화되어 있습니다.
tsc
명령어를 사용하여 컴파일 할 때 입력파일을 지정하면 tsconfig.json
은 무시된다. 하지만 입력파일을 지정하지 안흐면 tsconfig.json
은 현재 디렉토리에서 시작하여 상위 디렉토리 체인까지 계속해서 파일을 검색합니다.
compilerOptions
: 컴파일 어떻게 할 것인지.
include
: 컴파일 대상 파일들을 설정한다.
exclude
: 컴파일 하지 않을 경로를 지정한다.
compileOnSave
: 파일을 변경하면 바로 컴파일 할 것인지를 지정한다.
// tsconfig.json
{
"compilerOptions": {
"sourceMap": true,
"target": "es5",
// 내보낸 자바스크립트의 자바스크립트 언어 버전을 설정하고 호환되는 라이브러리 선언을 포함한다.
// Set the JavaScript language version for emitted JavaScript and include compatible library declarations.
"lib": ["dom", "ES2015", "ES2016", "ES2017", "ES2018", "ES2019", "ES2020", "ESNext"],
// 환경에 맞는 타입 정보를 추가.
"allowJs": true, // 자바스크립트 파일이 프로그램의 일부가 되는 것을 허용한다.
"strict": true,
"forceConsistentCasingInFileNames": true,//import하는 파일의 이름이 올바른지 확인
"esModuleInterop": true,
"module": "commonjs",
"jsx": "react",
"allowSyntheticDefaultImports": true,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
},
"outDir": "./dist",
"moduleResolution": "node",
"noImplicitAny": false, // any 타입으로 구현된 표현식 혹은 정의를 에러처리 할 것인가
"isolatedModules": true, // 각 파일을 분리된 모듈로 트랜스파일링할 것인가, 다른 import에 의존하지 않고 각 파일을 안전하게 트랜스파일링한다.
"declaration": false, // d.ts 파일을 생성할 것인가
"removeComments": true, // 컴파일시 주석을 제거할 것인가
"strictFunctionTypes": true, // 함수, 메소드의 인자 타입을 더 정확히 추론할 것인가
"skipLibCheck": true, // 사용하는 라이브러리의 타입 검사를 skip할 것인가
"noImplicitThis": true, // any 타입으로 암시한 this 표현식에 오류를 보고할 것인가
"noFallthroughCasesInSwitch": true, // switch문에서 fallthrough case가 발견되면 에러를 발생시킬 것인가
"noImplicitReturns": true, // void가 아닌 함수가 리턴을 제대로 하지 않는 경우가 있다면 에러 발생
"noEmit": true, // 컴파일러가 js 파일 등 출력 결과물을 만들지 않을 것인가 -> 내보내지 않을 것인가.
"noEmitOnError": true // 에러 발생시 js 소스코드, source map, declaration 등이 생성되지 않는다 -> 내보내지 않는다. 에러 발생시
},
"exclude": ["node_modules"],
"include": ["**/*.ts", "**/*.tsx", "src"]
}
important compilerOptions property
- module
타입스크립트 소스코드가 컴파일 되어 만들어진 es5 자바스크립트 코드는 웹 브라우저와 node js 양쪽에서 모두 동작해야합니다. 하지만 웹 브라우저와 node js는 자바스크립트 엔진이 각기 달라 여러개의 파일로 분할된 자바스크립트 코드 또한 다르게 동작합니다.
자바스크립트 모듈은 웹 브라우저에서는 asynchronous module definition (AMD)로 동작하고, 웹 브라우저가 아닌 환경에서는 Common JS 방식으로 동작합니다."module": "commonjs",
React 모듈(일반적으로 ESM 형식으로 작성된 응용 프로그램에서 사용하고 webpack과 같은 도구로 번들 및 컴파일)을 게시하지만 서버 측 렌더링 환경에서도 사용될 수 있다는 점을 고려해야 합니다. 일반적으로 Node를 사용하므로 라이브러리의 CJS 대응물이 필요할 수 있습니다(ESM 모듈은 실험 플래그 뒤 의 v10 부터 Node 환경에서 지원됨 ).
-
typesRoots
사용하는 서드 파티 라이브러리가 타입을 제공하지 않는다면, 직접 타입을 만들어 주어야하는데, 정의된 타입과 별개로 만들어준 타입을 사용해야한다."typeRoots": ["./node_modules/@types", "./types"],
요즘은
@types
를 지원하지 않는 라이브러리도 d.ts(모듈 내부 타입 정의 파일)을 포함해서 패키지를 배포한다고 한다. -
moduleResolution
웹은 amd, 노드는 commonjs 방식으로 모듈 시스템을 사용합니다.module이 commonjs면 노드에서 작동하는 것을 의미하므로 moduleResoultion 키 값은 node이며 amd면 classic으로 설정합시다.
배운점
module 속성은 웹에서는 amd, nodejs에서는 CJS라고 알고 있었음. 대부분의 리액트 타입스크립트 보일러 플레이트를 보면 module:"commonjs"
라 되어있는데, 이유는 서버사이드렌더링 환경을 고려하기 위해서임
React 모듈(일반적으로 ESM 형식으로 작성된 응용 프로그램에서 사용하고 webpack과 같은 도구로 번들 및 컴파일)을 게시하지만 서버 측 렌더링 환경에서도 사용될 수 있다는 점을 고려해야 합니다. 일반적으로 Node를 사용하므로 라이브러리의 CJS 대응물이 필요할 수 있습니다(ESM 모듈은 실험 플래그 뒤 의 v10 부터 Node 환경에서 지원됨 ).
트리쉐이킹 자바스크립트 애플리케이션이 특정 크기에 도달하면 코드를 모듈로 분리하는 것이 좋습니다. 트리쉐이킹은 실제로 사용되지 않는 코드를 최종파일에서 제거하여 코드 번들을 최적화하는 방법입니다. -> CJS로 트랜스 파일링 하고 있다면 트리쉐이킹은 수행되지 않는다.
다음과 같이 utils 파일에 함수들이 선언되어있다.
export function add(a, b) {
console.log("add");
return a + b;
}
export function minus(a, b) {
console.log("minus");
return a - b;
}
export function multiply(a, b) {
console.log("multiply");
return a * b;
}
export function divide(a, b) {
console.log("divide");
return a / b;
}
메인 스크립트에서 add함수만을 사용한다고 가정할 때
import { add } from "./mathUtils";
add(1, 2);
웹팩을 통해 모듈 번들링을 하여 번들 파일을 생성하면 모든 함수가 다들어있게 된다
트리쉐이킹은 이처럼 모든 함수가 다 있는 것이 아니라, 사용된 함수만 번들 파일에 포함시키는 최적화 방법이다.
트리쉐이킹의 작동방법
트리쉐이킹은 모듈이 정적인 경우에만 작동할 수 있습니다. es6이전에 cjs 모듈은 동적 모듈이었다. 즉, 코드의 조건에 따라 새 모듈을 가져올 수 도 있고 안 가져올수있다.
var myDynamicModule;
if (condition) {
myDynamicModule = require("foo");
} else {
myDynamicModule = require("bar");
}
이러한 CJS의 동적인 특성은 코드가 실제로 실행되기 이전에 어떤 모듈이 필요한지 결정하는 것이 불가능하기 때문에 트리 쉐이킹을 적용할 수 없음.
es6에서는 완전히 정적인 모듈에 대한 새로운 구문이 도입되었다. import 구문을 사용하면 더이상 모듈을 동적으로 가져올 수 없습니다.
// 작동하지 않는 코드
if (condition) {
import foo from "foo";
} else {
import bar from "bar";
}
//전역 범위에서 모든 가져오기를 정의해야 합니다.
import foo from "foo";
import bar from "bar";
if (condition) {
// do stuff with foo
} else {
// do stuff with bar
}
가져오기에 사용되는 모든 코드를 런타임 이전에 결정할 수 있으므로 효과적인 트리 쉐이킹이 가능합니다.
흔들리는 나무를 떨쳐내는 법
Tree shaking, at least webpack's implementation of the feature, is pretty good at eliminating as much unused code as possible. For example, imports that are import-ed but not used are eliminated.
import { add, multiply } from "./mathUtils";
add(1, 2);
위 코드에서 multiply 함수는 최종 번들에서 삭제되어있다.
접근하지 않는 객체의 속성도 제거된다.
export const myInfo = {
name: "Ire Aderinokun",
birthday: "2 March"
}
import { myInfo } from "./myInfo.js";
console.log(myInfo.name);
birthday에는 접근하지 않았으므로 최종 번들로 만들어지지 않는다.
그러나 트리 쉐이킹을 사용한다고 해서 사용되지 않는 코드의 문제가 완전히 해결되는 것은 아닙니다. 다음의 부작용을 갖는다.
부작용은 가져올때 일부 작업을 수행하는 코드이며, 내보내기와는 관련되지 않는다. 부작용의 예는 폴리필이다. 폴리필은 일반적으로 기본 스크립트에서 사용할 내보내기를 제공하지 않고 전체 프로젝트에 추가됩니다. ( 폴리필이란 Promise와 같이 기본적으로 지원하지 않는 이전 브라우저에서 최신 기능을 제공하는데 필요한 코드 )
이 때 트리쉐이킹은 어떤 스크립트가 부작용인지 자동으로 알 수 없어 수동으로 지정해주어야한다.
기본적으로 웹팩을 사용하면 mode : production
을 통해 트리쉐이킹이 가능하다.
특정 파일을 부작용으로 표시하려면 package.json에 다음을 추가해야한다. 사용자에게 권한을 위임한 것으로, Treeshaking의 대상에서 제외된다.
{
...,
"sideEffects": [
// 이 파일은 import 할 때 특정한 동작을 수행하는 코드라 알려야함.
"./src/polyfill.js"
],
...,
}
Ref
-
-
-
-
-
Author And Source
이 문제에 관하여([21/09/19] Junzzi Editor 프로젝트 셋팅 - (2) 타입스크립트 설정 - 트리쉐이킹), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@rat8397/210919-Junzzi-Editor-프로젝트-셋팅-2-타입스크립트-절대경로-eslint-prettier-설정
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Author And Source
이 문제에 관하여([21/09/19] Junzzi Editor 프로젝트 셋팅 - (2) 타입스크립트 설정 - 트리쉐이킹), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@rat8397/210919-Junzzi-Editor-프로젝트-셋팅-2-타입스크립트-절대경로-eslint-prettier-설정저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)