typescript-webpack으로 빌드하기

들어가기

어쩌다보니 typescript sdk를 사용할 일이 있었다.

내가 문제는 typescript를 잘 모른다는 것이다. ㅋㅋㅋ

angular 때문에 말은 많이 들었지만, 이거 신기한 녀석이다.

typescript로 만든 소스를 tsc를 이용해서 build를 하면 그 결과가 javascript 소스가 된다.

여기서 build할때 이 빌드 결과물을 es3으로 빌드할지 아님 es5, es6로 빌드할지 결정 할 수도 있다.

기본적으로 tsc(typescript 컴파일러)로 빌드를 하지만 webpack으로도 빌드가 가능하다.

이번 글에서는 간단한 typescript 코드와 그것을 webpack으로 빌드해서 하나의 js파일로 만들어 html에서 호출하는 것을 해보려한다.

정확하 typescript와 webpack을 공부한게 아니라 엉성한것을 감안하길 바란다.

node 프로젝트 만들고 typescript 소스작성

npm init으로 node 프로젝트를 생성한다.

내가 생성한 package.json은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"name": "tsc-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"transpile": "tsc",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"es6-shim": "^0.35.5",
"path": "^0.12.7",
"webpack": "^4.29.6"
},
"devDependencies": {
"@types/node": "^11.11.0",
"ts-loader": "^5.3.3",
"typescript": "^3.3.3333",
"webpack-cli": "^3.2.3"
}
}

사실 위 package.jsonnpm 디펜던시 관리만 하게 될 것이다.

빌드는 wepack으로 할 것이다.

위 파일을가지고 npm install 명령어를 이용해서 모듈을 설치하자.

프로젝트 구조는 다음과 같다.

AccountService.ts 는 AccountVO.ts를 import해서 사용하고, main.ts 는 AccountService.ts를 inport해서 export 한다.

main.ts를 중심으로 외부에서 사용할 service를 노출시킨다.

main.ts는 일종의 service 컨트롤러 역할을 할 것이다.

이 main.ts를 entry point로 정해서 webpack에서 빌드하게되면 하나의 js파일이 생성되고 이 js파일을 index.html 파일에서 불러와서 main.ts에 등록된 AccountService.ts의 기능을 사용할수 있게 될 것이다.

파일을 하나씩 살펴보자.

/src/domain/AccountVO.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
interface AccountI {

}

export class AccountVO implements AccountI {
private _privateKey : string;
private _publicKey : string;
private _address : string;

constructor(privateKey : string , publicKey : string, address : string){
this._privateKey = privateKey;
this._publicKey = publicKey;
this._address = address;
}

public getPrivateKey() : string {
return this._privateKey;
}

public getPublicKey() : string {
return this._publicKey;
}

public getAddress() : string {
return this._publicKey;
}

}

굳이 인터페이스는 없어도 된다. 공부하느라…

/src/service/AccountServiceVO.ts

1
2
3
4
5
6
7
8
9
10
11
12
13

import {
AccountVO
} from "../domain/AccountVO"

export class AccountService {

public createAccount () : void {
console.log("createAcount called...");
const user1 : AccountVO = new AccountVO("this is private key", "this is public key", "this is address");
}

}

별 내용은 없다 그냥 typescript 소스가 서로 import하면서 엮기는 모습을 보여주고 싶었다.

이렇게 그물처럼 엮인 소스를 webpack으로 빌드해서 하나의 단일 js 파일로 만드는 것이 신기하기 때문이다.

다음은 가장 중요한 main.ts

1
2
3
4
5
6
import {
AccountService
} from "./services/AccountService";

export const _AccountService = new AccountService();
//export const something = new somthing();

webpack이 빌드할 entry point로 가장 중요한 typescript 파일이지만 내용은 별거 없다.

만약 여러개의 service를 등록하고 싶다면, 위 주석처럼 추가로 import해서 등록 하면 된다.

typescript를 빌드할 webpack관련 파일

webpack 관련파일

위 이미지에서 표시된 두개의 파일이 typescript를 빌드할때 사용될 파일이다.

먼저 webpack.config.js 파일을 보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// webpack.config.js
var webpack = require('webpack');
var path = require('path');

module.exports = {
entry: {
'main': './src/main.ts'
},
output: {
//filename: '[name].js',
filename: 'MAIN_TYPESCRIPT_SDK.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'var',
library: 'MAIN_TYPESCRIPT_SDK'
},
mode :'development',
devtool: 'source-map',
module: {
rules: [
{
test: /\.ts$/,
use: ['ts-loader']
}
]
},
resolve : {
//root: __dirname,
modules: [
'node_modules',
//'./src/components'
],
extensions: ['.js', '.ts']
},
node: { fs: 'empty' , net : 'empty', tls : 'empty'} // 웹팩 compile 시 오류 처리
};

여기서 중요한 설정이 몇개 존재한다.

일단 webpack으로 typescript를 build하기 때문에 module에 ts-loader가 등록이 되어있어야 한다.

이 로더가 tsconfig.json을 참조하게 된다. tsconfig.json은 typescript를 어떻게 build할 것인가에 대한 설정이다.

위 파일에서 entry와 output을 주의깊게 봐야 한다.

1
2
3
entry: {
'main': './src/main.ts'
}

main.ts 파일을 entry point로 정한다.

1
2
3
4
5
6
output: {
//filename: '[name].js',
filename: 'MAIN_TYPESCRIPT_SDK.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'var',
library: 'MAIN_TYPESCRIPT_SDK'

main.ts 를 기준으로 main.ts에 import된 모든 ts파일을 같이 빌드해서 하나의 js파일을 만드는데, 그 결과물 파일명은 MAIN_TYPESCRIPT_SDK.js 로 정했다.

그리고 이 파일이 생성되는 위치는 dist 폴더이다.

1
2
libraryTarget: 'var',
library: 'MAIN_TYPESCRIPT_SDK'

그리고 MAIN_TYPESCRIPT_SDK.js 파일에 변수를 하나 내보낼 것인데 변수 var MAIN_TYPESCRIPT_SDK = 빌드된 main.ts 이렇게 정했다.

이제 tsconfig.json 파일을 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"removeComments": true,
"noImplicitAny": false,
"sourceMap": true,
//"outFile": "./build/build.js",
//"sourceRoot": "./src/",
//"rootDir": "./src/",
},
"compileOnSave": true,
"buildOnSave": true
}

이 파일은 typescirpt를 컴파일할때 사용하는 설정 파일 같다.

사실 이부부은 나도 잘 몰라서 뭐라 말을 못하겠다.

다만 빌드 결과물이 es5로 정했다.

webpack으로 typescript 빌드하기

만약 webpack을 global로 설치했다면, 프로젝트 폴더에서 webpack명령어를 입력하면 된다.

나 같은 경우에는 global로 설치하지 않았기 때문에, node_module폴더에 webpack이 숨어있다.

1
node_modules/.bin/webpack

위 명령어를 입력하게 되면 아래처럼 webpack이 typescript를 빌드한다.

webpack 명령어 결과

그럼 dist폴더를 보면 webpack.config.js에서 설정한 것 처럼 js 파일이 생긴다.

dist폴더

js파일 한개가 생성된 것을 확인했다.

html에서 생성된 js파일을 불러와서 typescript에서 선언한 객체를 호출

index.html 파일을 아래처럼 만들었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
<head>
<title>test</title>
<script src="dist/MAIN_TYPESCRIPT_SDK.js"></script>
<script>

window.onload = function () {

console.dir(MAIN_TYPESCRIPT_SDK);
MAIN_TYPESCRIPT_SDK._AccountService.createAccount();

};

</script>

</head>
<body>

</body>
</html>

별거 없다.

webpack.config.js에 설정한대로 생성된 js파일을 src로 가져오고 var로 내보낸 라이브러리 명으로 main.ts에 export한 typescript객체의 메소드를 호출한다.

크롬 브라우저 콘솔창

위처럼 크롬 콘솔에서 잘 호출되는 것을 확인했다.

마무리

휴 어렵다.

타입스크립트도 잘모르고, 특히 지옥같은 웹팩은 더더욱 몰라서 어려웠다.

gradle도 그렇고 webpack도 진짜 설정이 어려운거 같다.

위 소스 github 주소는 아래와 같다.
https://github.com/hanumoka/demo_typescript_webpack

참고자료

https://trustyoo86.github.io/typescript/2018/01/09/typescript-webpack.html

https://medium.com/dailyjs/inserting-variables-into-html-and-javascript-with-webpack-80f33625edc6

https://stackoverflow.com/questions/34357489/calling-webpacked-code-from-outside-html-script-tag
특히 마지막 자료가 많이 도움되었다.