[ cs스터디 7/24 ] 타입스크립트와 웹팩

inguk·2023년 7월 24일
0

CS스터디

목록 보기
3/4
post-thumbnail
post-custom-banner

7월 24일(월) cs스터디에서 진행한 내용을 기록해보려고합니다 !
테스트, 웹팩 , 타입스크립트 등 리액트관련 전반적인 지식을 공부했습니다
정리하면서 기존에 암기했던 내용보다 조금 더 축약해서 정리해보려고 노력중입니다 !

테스트란?

어플리케이션이 요구사항에 맞게 동작하는지를 검증하는 행위입니다

테스트의 예는 어떤 것들이 있나요?

  • DB에 데이터를 입력하는 API를 개발
    (ex : 개발 > API 호출 > DB값 검증 )
  • 디자인 시안에 맞게 HTML/CSS를 작성 후 브라우저 렌더링된 결과를 확인
  • 새로운 기능 추가를 위해 리팩토링 후 확인작업
  • 버그가 발생해 기존함수 수정 후 실행결과 확인
  • 개발이 마무리 테스트된 어플리케이션을 실제 환경에 배포

테스트의 중요성은?

개발자는 작성한 프로그램의 퀄리티에 대한 책임이 있습니다.
자동화된 테스트를 작성해두지 않으면, 어플리케이션이 복잡해질 수록 테스트 비용이 증가합니다.
개발 기간이나 인력 등이 한정되어 있기 때문에, 테스트를 소홀히 하게 되는 경우가 있는데 이럴 경우 QA 와의 커뮤니케이션 비용이 늘어나, 업무의 효율이 떨어질 수 있습니다.

테스트의 종류

단위(Unit) 테스트

  • 모듈(함수/클래스) 단위의 테스트
  • 작성 비용이 적게 들고 실행 속도가 빠름
  • 실패했을 때 문제가 생긴 부분을 비교적 정확하게 파악할 수 있음
  • 상호테스트가 안되기때문에 통합확인이 힘듬

통합(Integration) 테스트

  • 주로 단위 테스트보다 큰 범위의 테스트를 의미
  • 개별 모듈(함수/클래스)들이 연결되어 제대로 상호작용하는지를 테스트
  • 단위 테스트에 비해 실패 시 문제가 생긴 부분을 정확히 파악하기가 어려움

E2E(End to End) 테스트

  • 실제 사용자가 사용하는 것과 같은 조건에서 전체 시스템을 테스트
  • 단위/통합 테스트에 비해 작성이 어렵고 실행 속도가 비교적 느림
  • API 서버, DB 등의 외부 서비스들을 모두 사용하여 통합된 시스템을 테스트

business logic

먼저, 로직이란 어떤 프로그램을 만들 때의 논리적인 흐름을 이야기합니다
그중에서도 비즈니스 로직(도메인 로직/ 애플리케이션 로직)이란 프로그램의 핵심 로직을 뜻합니다.
어떻게 데이터가 생성되고 저장되고 수정되는지를 정의한 것이 비즈니스 로직이라고 할 수 있습니다.

회원가입으로 예를 들어본다면
클라이언트는 회원가입 폼에 양식을 입력하고 회원가입 버튼을 누르면 회원가입이 진행됩니다
이같은 로직중 중복찾기기능 중 비즈니스 로직이란?

  1. 회원이 작성한 아이디 값을 저장
  2. 회원정보가 있는 데이터베이스 연결
  3. 데이터베이스에 회원이 작성한 아이디 값이 있는지 중복검사
  4. 회원의 아이디가 이미 있는지 없는지 여부를 데이터화 하여 저장
  5. 데이터베이스 연결 끊기
  6. View 영역에게 가공된 데이터 전달

해당 논리적인 흐름이 중복찾기 기능중에 비즈니스 로직이됩니다 !

Snippet

스니펫은 작은 조각을 뜻한다. 지정한 접두어를 입력하면 템플릿이 입력되는 식이다.
요즘 활용되는 왠만한 코드편집기, IDE 등은 code snippet 단위로 ’템플릿’을 만들어 써먹을 수 있게 되어있다.

VS Code 의 확장 프로그램 활용 - Reactjs code snippets / Tabnine AI

웹팩의 구성요소

웹팩이란 최신 프런트엔드 프레임워크에서 가장 많이 사용되는 모듈 번들러입니다.
모듈 번들러란 웹 애플리케이션을 구성하는 자원(HTML, CSS, Javscript, Images 등)을 모두 각각의 모듈로 보고
이를 조합해서 병합된 하나의 결과물을 만드는 도구를 의미합니다.

웹팩 사용 시에 이점

  1. 파일 단위의 자바스크립트 모듈 관리의 필요성이 강조되어 개발됨
  2. 웹 개발 작업 자동화 도구
  3. 웹 애플리케이션의 빠른 로딩 속도와 높은 성능

모듈이란 프로그래밍 관점에서 특정 기능을 갖는 작은 코드 단위를 의미합니다.
자바스크립트로 치면 아래와 같은 코드가 모듈입니다.

math.js
const sum = (a, b) => { return a + b;}
export { sum };

이 math.js 파일은 아래의 기능을 갖고 있는 모듈입니다.

  • 두 숫자의 합을 구하는 sum() 함수

이처럼 하나의 의미있는 파일로 관리하면 모듈이 됩니다.
웹팩에서 지칭하는 모듈이라는 개념은 위와 같이 자바스크립트 모듈에만 국한되지 않고 웹 애플리케이션을 구성하는 모든 자원을 의미합니다.
웹 애플리케이션을 제작하려면 HTML, CSS, Javascript, Images, Font 등 많은 파일들이 필요하죠. 이같은 파일들이 모두 모듈입니다.

모듈 번들링이란?

아래 그림과 같이 웹 애플리케이션을 구성하는 몇십, 몇백개의 자원들을 하나의 파일로 병합 및 압축 해주는 동작을 모듈 번들링이라고 합니다.
파일들의 연관된 관계를 파악하여 파일들을 하나의 파일로 압축시켜주는 과정을 번들링 과정이라 합니다.

바벨이란?

바벨은 자바스크립트에서 지원하는 최신 문법 (ES6, ES7, ES8, ES9, …) 들을 최대한 많은 브라우저 환경에서 호환이 가능하도록 변환해주는(트랜스파일링해주는) 언어입니다.

바벨 변환

바벨을 사용하면 거대한 변화가 생기기 시작한 기점인 ES6 (ECMAScript 2015) 이후의 문법을 브라우저에서 범용적으로 사용되는 문법 단계로 변환해줄 수 있습니다.

// Babel Input: ES2015 arrow function[1, 2, 3].map((n) => n + 1);
// Babel Output: ES5 equivalent[1, 2, 3].map(function (n) {  return n + 1;});

트랜스파일은 한언어로 작성된 소스코드를 비슷한 수준의 추상화를 가진 다른 언어로 변환하는 것을 말합니다
예를들어, es6 -> es5를 변환하는 경우와 c++->c로 변환하는 경우를 예로 들수있습니다 !

웹팩의 주요 속성 4가지

  1. entry
  2. output
  3. loader
  4. plugin

entry

entry 속성은 웹팩에서 웹 자원을 변환하기 위해 필요한 최초 진입점이자 자바스크립트 파일 경로입니다.

빌드를 할 대상 파일의 위치라고 볼 수 있습니다

// webpack.config.js
module.exports = {  entry: "./src/index.js",};

entry 속성에 지정된 파일에는 웹 애플리케이션의 전반적인 구조와 내용이 담겨져 있어야 합니다.
웹팩이 해당 파일을 가지고 웹 애플리케이션에서 사용되는 모듈들의 연관 관계를 이해하고 분석하기 때문에
애플리케이션을 동작시킬 수 있는 내용들이 담겨져 있어야 합니다.

// webpack.config.js
    import LoginView from "./LoginView.js";
    import HomeView from "./HomeView.js";
    import PostView from "./PostView.js";
    function initApp() {  LoginView.init();  HomeView.init();  PostView.init();}
    initApp();

싱글 페이지 애플리케이션으로 작성된 index.js를 예로 들어보겠습니다. 3개의 컴포넌트를 index.js에 불러와서 실행을 하고있는 구조입니다.

사용자의 로그인 화면, 로그인 후 진입하는 메인 화면, 그리고 게시글을 작성하는 화면 등 웹 서비스에 필요한 화면들이 모두 index.js 파일에서 불려져 사용되고 있기 때문에 웹팩을 실행하면 해당 파일들의 내용까지 해석하여 파일을 빌드해줄 것입니다.

output

output 속성은 웹팩을 돌리고 난 결과물의 파일 경로를 의미합니다.

// webpack.config.js
module.exports = {  output: {    filename: "bundle.js",  },};

앞에서 배운 entry 속성과는 다르게 객체 형태로 옵션들을 추가해야 합니다.

최소한 filename은 지정해줘야 하며 일반적으로 아래와 같이 path 속성을 함께 정의합니다.

// webpack.config.js
var path = require("path");
module.exports = {  output: {    filename: "bundle.js",    
path: path.resolve(__dirname, "./dist"),  },};
  • filename 속성은 웹팩으로 빌드(번들링)한 파일의 이름을 의미합니다.
  • path 속성은 해당 파일의 경로를 의미합니다.
  • path 속성에서 사용된 path.resolve() 코드는 인자로 넘어온 경로들을 조합하여 유효한 파일 경로를 만들어주는 Node.js API입니다.

따라서 dist 라는 폴더 안에 있는 bundle.js라는 파일 이름으로 엔트리에 들어온 파일을 빌드(번들링)하여 결과물로 가져올 것입니다.

loader

로더는 웹팩이 웹 애플리케이션을 해석할 때 자바스크립트 파일이 아닌 웹 자원(HTML, CSS, Images, 폰트 등)들을 빌드 시에,
자바스크립트의 output(산출물) 파일에 포함될 수 있도록 도와주는 속성입니다.

// webpack.config.js
module.exports = {  module: {    rules: [],  },};

엔트리나 아웃풋 속성과는 다르게 module라는 이름을 사용합니다.

plugin

우리가 설정한 output인 bundle.js에 css 파일을 같이 번들링하는 것이 아닌 별도의 css 파일로 만들어주기는 것이 플러그인의 기능입니다
해당 적용이 완료된 후에 빌드를 하면 다음과 같이 번들링 시에 css 파일이 별도로 분리된 것을 볼 수 있습니다
플러그인(plugin)은 웹팩의 기본적인 동작에 추가적인 기능을 제공하는 속성입니다.
로더랑 비교하면 로더는 파일을 해석하고 변환하는 과정에 관여하는 반면, 플러그인은 해당 결과물의 형태를 바꾸는 역할을 한다고 보면 됩니다.
플러그인은 아래와 같이 선언합니다.

// webpack.config.js
module.exports = {  plugins: [],};

플러그인의 배열에는 생성자 함수로 생성한 객체 인스턴스만 추가될 수 있습니다.

// webpack.config.js
var webpack = require("webpack");
var HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = { 
  plugins: [new HtmlWebpackPlugin(), new webpack.ProgressPlugin()],};

타입과 인터페이스

타입스크립트를 왜 쓰나요?

타입을 먼저 지정하고 선언함으로써, 프로그래밍 단계, HTTP 통신을 통한 데이터를 주고받는 과정에서 생기는 데이터를
안전하게 주고 받을 수 있고 타입에 관련된 프로토타입 메서드를 손쉽게 찾아 쓸 수 있다는 가장 큰 장점입니다 또, 정적 타이핑을 지원하며
자바스크립트의 경우 동적 타이핑이기에 자바스크립트 엔진에 의해 자동으로 해석되기 작성자의 의도에 따라 데이터의
타입이 불분명해질 수 있는데 이같은 점을 방지할 수 있는것이 타입스크립트의 장점입니다

타입이 없을 때

타입이 있을 때

타입과 인터페이스의 차이

타입과 인터페이스는 모두 객체의 타입의 이름을 지정하는 방법들 중 하나이다

// interfaceinterface 
PeopleInterface {  name: string;  age: number;}
const me1: PeopleInterface = {  name: "yc",  age: 34,};

하지만 일정 부분에 있어서 타입과 인터페이스는 차이점이 존재한다

  1. 확장하는 방법

인터페이스는 extends 키워드를 사용하여 확장이 가능하고, 타입은 & 연산자를 통해 확장이 가능하다

// interfaceinterface People
Interface {  name: string;  age: number;}
interface StudentInterface extends PeopleInterface {  school: string;}
  1. 선언적 확장

인터페이스는 동일한 이름을 통해 재정의함으로써 선언적 확장이 가능하지만, 타입은 불가능하다

// interfaceinterface
Window {  title: string;}interface Window {  ts: TypeScriptAPI;}
// 같은 interface 명으로 Window를 다시 만든다면, 자동으로 확장이 된다.

여러 타입 혹은 인터페이스를 병합할 때 (& or extends), 인터페이스는 속성간의 충돌을 해결하기 위해 단순한 객체 타입을 만든다.

인터페이스는 오로지 객체의 타입을 만들기 위한 것이기 때문이다.

타입은 재귀적으로 순회하면서 속성을 병합하는데, 이 경우에 일부 never가 나오면서 제대로 머지되지 않을 수 있다. 인터페이스와는 다르게 타입에는 원시 타입이 올 수도 있으므로, 충돌이 나서 병합이 안되는 경우가 발생한다.

객체에만 쓰는 용도라면 interface를 사용하는 것이 좋을 것이다.

  1. 변환시 제거

타입과 인터페이스의 또 다른 차이점은 생성된 자바스크립트 코드에서 인터페이스가 제거되는 반면 타입은 제거되지 않는다는 것이다. 타입스크립트를 빌드할 경우, 해당 코드를 자바스크립트로 번들링하게 되는데, 이때 인터페이스의 경우 자바스크립트로 넘어가며 제거되지만, 타입의 경우 그대로 남아 있는다.

즉, TypeScript 코드에서 인터페이스를 사용하는 경우 브라우저나 서버에서 실제로 실행되는 JavaScript 코드에는 인터페이스가 존재하지 않습니다.

인터페이스와 타입은 객체의 모양을 정의하는 데 모두 사용되지만,

  • 인터페이스는 더 유연하고, 확장 과정에서 확장되거나 제거될 수 있는 반면
  • 타입은 덜 유연하고, 확장될 수 없으며 생성된 자바스크립트 코드에 남아 있습니다

인터페이스는 자신의 이름을 중복 선언하여 extends 키워드를 사용하지 않더라도 확장이 가능하지만,
타입의 경우 중복 선언을 통해 확장할 수 없다. (& 연산자를 사용하여 확장해야 한다)

제네릭이란?

제네릭은 클래스, 함수, 인터페이스 등을 다양한 타입으로 재사용가능하게 해주는 문법입니다

function getSize(arr: number[] | string[] | boolean[]): number {  return arr.length;}
const arr = [1, 2, 3];getSize(arr); 
// 3const arr2 = ["a", "b", "c"];getSize(arr2); // 3const arr3 = [true, false, true];getSize(arr3); // 3

위와 같이 한가지 함수에서 다양한 타입의 데이터를 받아줘야한다고 가정할 때 올바른 타입을 지정하기 위해서는 타입을 확장시켜줘야 합니다.

이런 상황에서 제네릭을 사용하여 함수의 매개변수에 대한 타입 <T>를 명시해줌으로써 다양한 타입에 대응하는 함수를 만들어줄 수 있습니다.

function getSize<T>(arr: T[]): number {  return arr.length;}
const arr = [1, 2, 3];getSize<number>(arr); 
// 3const arr2 = ["a", "b", "c"];getSize<string>(arr2); // 3
profile
Frontend
post-custom-banner

0개의 댓글