'@types' 시리즈장고에 TypeScript와 SCSS 도입하기

배진오

@baealex

소비적인 일보단 생산적인 일을 좋아합니다.

결론부터 말하면

스태틱 파일이 포함된 디렉터리를 순회하며 자동으로 tsjsscsscss로 트랜스파일을 해주는 코드를 작성하였다.


왜 도입하게 되었나

블렉스에서 프론트엔드 기술은 순도 100% JSCSS다. JS의 경우 최대한 하위호환을 유지하기 위해서 ES5 문법으로 코딩하고 있었는데 최근에서야 백틱이 ES6에 추가된 문법이라는 것을 알게 되었다. 🤔

var number = 5;
var mixed = `내가 가장 좋아하는 숫자는 ${number}다.`;

위 문법에서 사용된 문자가 백틱인데 상당히 충격이었다. 대부분의 경우 위와같이 코드를 작성했기 때문이다. 이후 모든 걸 내려놓고 ES6 문법을 사용중이다. 또한 jQuery를 남발했던 예전의 나와 jQuery를 사용하지 않으려는 지금의 내가 쌓아 온 코드들까지 뒤죽박죽 코드에 진절머리나기 시작했다.


TypeScript

그러다 내 눈엔 타입스크립트가 들어왔다. 자유도가 무척이나 높은 JavaScript에 비해 TypeScript는 좀 빡빡한 느낌을 줬다. 또한 문법이 다른 언어들과 비슷하게 직교성도 높았고 ES5로 컴파일이 가능하다는 점 하나로 도입할 가치가 충분했다.

=> TypeScript

// 초기화와 동시에 값을 할당할 경우에는 타입을 안써도 상관없다.
let num: number = 5;
let mention: string = `내가 가장 좋아하는 숫자는 ${num}다.`;

=> ES5

// 컴파일 후 아래와 같이 변환된다.
var num = 5;
var mention = "내가 가장 좋아하는 숫자는" + num + "다.";

타입스크립트를 적용한 뒤 내 목표는 단 하나다. VSCode에서 단 하나의 빨간줄도 보이지 않는 것. @types/jQuery를 추가하지 않는 이상 jQuery$는 빨간줄로 표시된다. jQuery 고마웠어... 이제 보내줄게...


SCSS

부수적으로 타입스크립트를 도입하는 동시에 SCSS도 도입하고 싶었다. 나는 SCSS를 상당히 좋아한다. @mixin, @include와 같은 문법을 자주 사용하는 건 아니지만 블럭 단위로 스타일시트를 작성한다는 것만으로 정말 훌륭한 라이브러리다.

.blex-write-component input {
    ...style...
}
.blex-write-component input:foucs {
    ...style...
}
.blex-write-component textarea {
    ...style...
}
.blex-write-component .preview {
    ...style...
}

위와같은 문법을

.blex-write-component {
    input {
        ...style...
        :focus {
            ...style...
        }
    }
    textarea {
        ...style...
    }
    .preview {
        ...style...
    }
}

위처럼 작성할 수 있다. 확실히 보기에도 편하고 코딩하기도 좋다. 요즘은 늘어나는 스타일시트에 무언가를 추가하기가 두려워지는데 그럼에도 도입하지 않았던 이유는 당연 장고에서 쿨하게 SCSS를 도입하는 방법을 몰랐기 때문이다. 스태틱 파일을 장고로 배포하고 있었다면 여러 꼼수를 부릴 수 있었겠지만 별도의 서버로 운용중이라 미뤄왔다. 하지만 언제까지나 미룰수는 없는 노릇. 트랜스파일링을 하더라도 빠르게 도입하고 싶어졌다.


Transpile with Python

일단 언어의 통일을 위해서 파이썬으로 트랜스파일링을 시도하고자 하였다. 사용하고자 한 라이브러리는 아래 두가지.

이들을 활용하여 완벽한 코드를 만들 수 있으리라 생각했는데 TypeScript의 변환이 좀 이상했다. 리포에서 예시로 보여준 결과와 달리 보여졌으며 실행이 불가했다.


Transpile with Node

결론은 역시 프론트엔드와 관련된 모든 것은 Node가 짱짱이다.

npm i typescript
npm i node-sass

아주 깔끔하게 작동했다. 필자의 프로젝트에 프론트엔드 파일들은 한 폴더에 몰려있으므로 이 폴더를 순회하며 자동으로 tsjsscsscss로 트랜스파일을 해주는 코드를 작성하였다. Python에는 디렉터리를 순회하는 walk라는 함수가 있기에 Node에도 있지 않을까 생각했지만 헛된 생각이었다. 😅

const fs = require('fs');
const path = require('path');

const ts = require('typescript');
const sass = require('node-sass');

function walk(dir) {
    fs.readdir(dir, (err, filenames) => {
        filenames.forEach((filename) => {
            fs.stat(path.join(dir, filename), (err, stat) => {
                if(stat.isDirectory()) {
                    walk(path.join(dir, filename));
                } else {
                    const filePath = path.join(dir, filename);
                    const ext = filePath.split('.').slice(-1).toString();
                    if(ext === 'ts') {
                        fs.readFile(filePath, 'utf8', (err, source) => {
                            const result = ts.transpileModule(source, {
                                compilerOptions:{
                                    module: ts.ModuleKind.CommonJS
                                }
                            });
                            fs.writeFile(filePath.slice(0, -2) + 'js', result.outputText, (err) => {
                                err && console.log(err);
                            });
                        });
                    } else if(ext === 'scss' || ext === 'sass') {
                        fs.readFile(filePath, 'utf8', (err, source) => {
                            const result = sass.renderSync({
                                data: source,
                                outputStyle: 'compressed'
                            });
                            fs.writeFile(filePath.slice(0, -4) + 'css', result.css, (err) => {
                                err && console.log(err);
                            });
                        });
                    }
                }
            });
        });
    });
}

const targetDrectory = './assets';
walk(targetDrectory);

다만 문제라고 해야할지... 오류가 분명 있음에도 컴파일도 매우 잘된다. IDE에서도 확장자가 .ts 임에도 TypeScript의 문법을 강제하지 않는 느낌도 들었고? 이 부분에 대해선 TypeScript에 대해서 더 공부해 봐야 할 듯하다.

😥 작성된 댓글이 없습니다!
댓글을 작성하기 위해 로그인이 필요합니다.