[VSCODE] 티스토리 스킨 개발 세팅: 컴파일러 제작
요즘 만들어둔 스킨이 맘에 안들 때 문제있는 부분을 찾아서 만들기가 너무 어려워 아예 처음부터 다시 만드는 경우가 많습니다. 때문에 유지 관리하기 편한 개발환경을 만들기 위한 고민을 시작했습니다.
개발 언어와 기능
기본적으로 티스토리 스킨에는 HTML
, CSS
, javascript
를 사용할 수 있습니다. 이들을 그대로 사용하다보니 수정할거리가 생기면 찾기가 너무 힘들었는데요. 컴파일 과정을 거쳐야 하지만 유지관리에는 훨씬 유리한 SASS(SCSS)
, Typescript
를 사용하기로 했습니다. 추가로 HTML
파일에는 import
태그를 추가해서 테마를 조각단위로 작성한 후, 컴파일을 통해서 하나의 skin.html
로 만드는 기능을 추가하기로 했습니다.
Python 패키지
자주 사용하는 언어가 파이썬(python)이다보니 node.js를 배워서 vscode용 확장기능을 만들기보다는 그냥 파이썬으로 해본 다음에 고민해보기로 했습니다. 추가로 설치가 필요한 패키지는 다음과 같습니다.
- libsass-python: SASS 컴파일 지원
- BeautifulSoup: HTML 문서의 파싱 지원
- Watchdog: 디렉토리, 파일 감시
이 패키지들은 아래 명령으로 설치할 수 있습니다.
pip install libsass
pip install beautifulsoup4
pip install watchdog
사용법
아래 단락의 소스코드를 {프로젝트 루트}/compiler/tt_watch.py
로 저장한경우를 기준으로 작성합니다.
tasks.json
.vscode/tasks.json
은 해당 프로젝트에서 실행할 명령이나 파일작업을 테스크 단위로 실행하고자 할때 사용합니다. 아래 예시문은 제작한 스킨 컴파일러와 타입스크립트 컴파일러를 묶어서 빌드 테스크로 만들어 둔 것입니다.
Ctrl
+Shift
+B
를 눌러 빌드테스크를 한번에 실행할 수 있습니다.
{
"version": "2.0.0",
"tasks": [
{
"label": "Tistory_Watch",
"type": "shell",
"command": "python ./compiler/tt_watch.py"
},
{
"label": "typescript_Watch",
"type": "typescript",
"tsconfig": "tsconfig.json",
"option": "watch",
"problemMatcher": [
"$tsc-watch"
]
},
{
"label": "Build",
"dependsOn": [
"typescript_Watch",
"Tistory_Watch"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
tt_config.json
제작한 스킨 컴파일러의 속성을 설정하는 파일입니다. 이 설정파일이 없는 경우 컴파일러는 기본값으로 채워진 설정파일을 만듭니다. 기본값은 아래와 같습니다.
{
"out_dir": "dist",
"html": {
"dir": "_html",
"main": "main.html",
"out": "skin.html"
},
"sass": {
"dir": "_sass",
"main": "main.scss",
"out": "theme.min.css"
}
}
"out_dir"
출력파일의 디렉토리"html"
,"sass"
: 언어 설정"dir"
: 작업 디렉토리"main"
: 컴파일 대상 파일의 이름"out"
: 출력할 파일의 이름
html including 기능
{% include "{스킨 조각}.html" %}
을 사용해 해당 위치에 스킨 조각파일의 내용을 불러옵니다.
_html/main.html
<html>
<head></head>
<body>
{% include "body.html"%}
</body>
</html>
_html/body.html
<div>body</div>
위 파일을 컴파일 한 결과는 다음과 같습니다.
dist/skin.html
<html>
<head></head>
<body>
<div>body</div>
</body>
</html>
소스코드
import time, re, json, os
import sass
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from bs4 import BeautifulSoup
default_config = {
"out_dir": "dist",
"sass": {
"dir": "_sass",
"main": "main.scss",
"out": "theme.min.css"
},
"html": {
"dir": "_html",
"main": "main.html",
"out": "skin.html"
}
}
config_file_name = "tt_config.json"
include_tag_rex = r'\{\%[ ]*?include[ ]+?\"(?P<src>.+?)\"[ ]*?\%\}'
class EventHandler(FileSystemEventHandler):
def on_any_event(self, event):
with open(config_file_name, 'r', encoding="utf8") as f:
config.update(json.loads(f.read()))
out_dir = os.path.join('./', config['out_dir'])
out_sass = os.path.join(out_dir, config['sass']['out'])
out_html = os.path.join(out_dir, config['html']['out'])
base_sass = os.path.join('./', config['sass']['dir'])
base_html = os.path.join('./', config['html']['dir'])
main_sass = os.path.join(base_sass, config['sass']['main'])
main_html = os.path.join(base_html, config['html']['main'])
if (re.search(config['out_dir'], event.src_path)):
return 0
print(f'{event.event_type} : {event.src_path}')
if (not os.path.exists(out_dir)):
os.mkdir(out_dir)
try:
sass_str = sass.compile(
filename=main_sass, output_style='compressed',include_paths=base_sass)
except:
sass_str = ''
if (sass_str):
with open(out_sass, 'w', encoding='utf8') as file_out_sass:
file_out_sass.write(sass_str)
if (os.path.exists(main_html)):
with open(main_html, 'r', encoding='utf8') as file_base_html:
html_str = file_base_html.read()
m = re.search(include_tag_rex, html_str)
while m:
html_str = html_str.replace(
m.group(), self._get_html_part(base_html, m.group('src')))
m = re.search(include_tag_rex, html_str)
with open(out_html, 'w', encoding='utf8') as f:
soup = BeautifulSoup(html_str, 'html.parser')
f.write(soup.prettify())
def _get_html_part(self, root, src):
try:
with open(root + src, 'r', encoding='utf8') as f:
return f.read()
except:
print(f'not exist: {root + src}')
return ''
if __name__ == "__main__":
config = default_config
if(os.path.exists(config_file_name)):
with open(config_file_name, 'r', encoding="utf8") as f:
config.update(json.loads(f.read()))
else:
with open(config_file_name, 'w', encoding="utf8") as outfile:
json.dump(default_config, outfile, sort_keys=True,
indent=2, separators=(',', ': '))
event_handler = EventHandler()
observer = Observer()
observer.schedule(event_handler, path="./", recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
'프로그래밍 > 웹 프로그래밍' 카테고리의 다른 글
티스토리 반응형 스킨: Minimal-Somad v0.3.0 (0) | 2019.05.07 |
---|---|
[SASS/SCSS] 티스토리 본문 스타일 (0) | 2019.05.02 |
가장 빠른 TeX 수식 변환기, KaTeX 사용하기 (0) | 2019.04.29 |
블로그에 소스코드 하이라이팅 기능 넣기 (0) | 2019.04.13 |
jQuery: 티스토리 마크다운을 지원하는 목차 생성 스크립트 (0) | 2019.04.08 |
댓글