ํ’€์Šคํƒ ์›น๐ŸŒ ๊ฐœ๋ฐœ์ž ์ง€๋ง์ƒ ๐Ÿง‘๐Ÿฝโ€๐Ÿ’ป
โž• ์ธ๊ณต์ง€๋Šฅ ๊ด€์‹ฌ ๐Ÿค–


Categories


Recent views

  • 1
  • 2
  • 3
  • 4
  • 5

Subbrain ๊ฐœ๋ฐœ๊ธฐ - Ruby&Jekyll

  1. ๊ฐœ์š”
    • ๊ฐœ๋ฐœ ๊ธฐ๋Šฅ
    • ํšŒ๊ณ 

    Subbrain ๊ฐœ๋ฐœ๊ธฐ - Ruby & Jekyll

    ๊ฐœ์š”

    Ruby๋Š” ๊ฐ€๋…์„ฑ๊ณผ ์ƒ์‚ฐ์„ฑ์— ์น˜์ค‘ํ•œ ๊ณ ์ˆ˜์ค€ ์ธํ„ฐํ”„๋ฆฌํ„ฐ ์–ธ์–ด๋กœ, ํ•จ์ˆ˜ํ˜•, ์ ˆ์ฐจํ˜•, ๊ฐ์ฒดํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ง€์›ํ•˜๋ฉฐ, ์›น ํ”„๋ ˆ์ž„์›Œํฌ์ธ ruby on rails ๊ฐ€ ์œ ๋ช…ํ•˜๋‹ค

    Jekyll์€ ์ž‘์„ฑํ•œ ๋ฌธ์„œ ํŒŒ์ผ๋“ค์„ ๊ฐ„๋‹จํžˆ ์ •์  ๋ธ”๋กœ๊ทธ ์‚ฌ์ดํŠธ๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” Ruby์™€ Gem ๊ธฐ๋ฐ˜ ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ ํˆด์ด๋‹ค. ์ฃผ๋กœ github page์™€ ์—ฐ๋™๋˜์–ด ๊ฐœ๋ฐœ์ž ๋ธ”๋กœ๊ทธ๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค.

    ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ณ  ๊ฐ„๋‹จํ•˜๋ฉฐ, ์€๊ทผํžˆ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋ธ”๋กœ๊ทธ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜์—ฌ, ๊ธฐ์ˆ  ์Šคํƒ์œผ๋กœ ์ฑ„์šฉํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

    ํ•˜์ง€๋งŒ ๋‘˜ ๋‹ค ๋‚ด๊ฐ€ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์ฒ˜์Œ ์ ‘ํ•ด๋ณด์•˜์œผ๋ฉฐ, Ruby์˜ ๊ฐ„๋‹จํ•œ ๋ฌธ๋ฒ•๊ณผ Jekyll์˜ ํŽธ์˜์„ฑ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ํ•™์Šต์œผ๋กœ ์ธํ•œ ๊ฐœ๋ฐœ ์‹œ๊ฐ„ ์ฆ๊ฐ€์˜ ์›์ธ ์ค‘ ํ•˜๋‚˜์ด๊ธฐ๋„ ํ•˜๋‹ค.

    ์ด ๋‘˜์„ ํ†ตํ•ด ๋ธ”๋กœ๊ทธ ๊ธฐ๋Šฅ ์ค‘ ์ฃผ๋กœ ๋™์  ์š”๊ตฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒƒ๋“ค์„ ๋งŒ๋“ค์—ˆ๋‹ค.

    ๊ฐœ๋ฐœ ๊ธฐ๋Šฅ

    ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •

    • Ruby ์„ค์น˜ ๋ฐ linter ์„ค์ •
    ๐Ÿงพ๏ธ Gemfile ์˜ˆ์‹œ
    gem "webrick", "~> 1.7"
    gem "rufo"
    gem "reek"
    gem "rubocop"
    gem "jekyll-seo-tag"
    gem "nokogiri"
    

    Ruby๋ฅผ ์„ค์น˜ํ•œ ๋’ค, ์œ„์™€ ๊ฐ™์ด Gemfile์„ ์„ค์ • ํ›„, bundle install์„ ํ†ตํ•ด ์„ค์น˜ ํ›„, VScode ruby ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•˜์—ฌ ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ ์„ค์ •์„ ์†์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

    • VScode task ์„ค์ •
    ๐Ÿงพ๏ธ vscode .vscode/tasks.json
    {
      "version": "2.0.0",
      "tasks": [
        {
          "label": "test",
          "dependsOn":["jekyll", "webpack", "sass", "tsc"]
        },
        {
          "label": "jekyll",
          "command": "bundle exec jekyll serve",
          "type": "shell",
          "options": {
            "cwd": "./"
          },
          "presentation": {
            "reveal": "always",
            "panel": "new"
          }
        },
        {
          "label": "webpack",
          "command": "node_modules/.bin/webpack",
          "type": "shell",
          "options": {
            "cwd": "./"
          },
          "presentation": {
            "reveal": "always",
            "panel": "new"
          },
          "problemMatcher": []
        },
        {
          "label": "sass",
          "command": "sass -w _sass:assets/css",
          "type": "shell",
          "options": {
            "cwd": "./"
          },
          "presentation": {
            "reveal": "always",
            "panel": "new"
          },
          "problemMatcher": []
        },
        {
          "label": "tsc",
          "command": "npx tsc -w",
          "type": "shell",
          "options": {
            "cwd": "./"
          },
          "presentation": {
            "reveal": "always",
            "panel": "new"
          },
          "problemMatcher": []
        }
      ]
    }
    

    ํ”„๋กœ์ ํŠธ ๊ฐœ๋ฐœ ์‹œ ๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ปค๋งจ๋“œ๋“ค์„ ์ผ์ผ์ด ์ž…๋ ฅํ•ด์•ผ ํ–ˆ๋‹ค.

    • bundle exec jekyll serve : Gem์— ๋ช…์‹œ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค๊ณผ ํ•จ๊ป˜ Jekyll ๊ฐœ๋ฐœ ๋ชจ๋“œ๋กœ ์‹คํ–‰
    • node_modules/.bin/webpack -w: ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ ๋ณ€๊ฒฝ ์‹œ ์ž๋™ ๋ฒˆ๋“ค๋ง
    • sass -w _sass:assets/css: ์ž‘์„ฑํ•œ sass ํŒŒ์ผ ๋ณ€๊ฒฝ์‹œ css ํŒŒ์ผ๋กœ ์ž๋™ ์ปดํŒŒ์ผ
    • npx tsc -w: ์ž‘์„ฑํ•œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ ๋ณ€๊ฒฝ ์‹œ ์ž๋™ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ปดํŒŒ์ผ

    ์ด๋Š” ๋งค์šฐ ๊ท€์ฐฎ์€ ์ผ์ด์˜€๊ณ , ์œ„์™€ ๊ฐ™์ด VScode์˜ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•ด ์ปค์Šคํ…€ Task๋ฅผ ์ƒ์„ฑํ•ด ctrl + p Tasks: Run task ๋ช…๋ น์„ ํ†ตํ•ด ํ•œ๊บผ๋ฒˆ์— ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค.

    ํ”„๋กœ์ ํŠธ ํŒŒ์ผ ๊ตฌ์กฐ

    Jekyll์˜ ๊ธฐ๋ณธ ํด๋” ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ๋ช‡๋ช‡ ํด๋”์™€ ๋‹ค๋ฅธ ํˆด๋“ค์„ ์œ„ํ•œ ํŒŒ์ผ์ด ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

    โœ ํ”„๋กœ์ ํŠธ ํŒŒ์ผ ๊ตฌ์กฐ ๊ฐœ์š”
    subbrain/
    ---foldersโ†“---
     |-assets/ : css, ์ด๋ฏธ์ง€, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋“ฑ ์—ฌ๋Ÿฌ ์ •์  ํŒŒ์ผ์ด ์ €์žฅ๋˜์–ด ์žˆ๋Š” ํด๋”
     |-blog/ : ๋ผ์šฐํ„ฐ ์ธ๋ฑ์‹ฑ, ์ •์  ํŽ˜์ด์ง€๋“ค์˜ html ํŒŒ์ผ๋“ค ์ €์žฅ์†Œ
     |-node_modules/ : javascript๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ‚ค์ง€
     |-scripts/ : Typescript ํŒŒ์ผ๋“ค
     |-_articles/ : ์ž‘์„ฑํ•œ ๋งˆํฌ๋‹ค์šด ํŒŒ์ผ๋“ค์ด ์นดํ…Œ๊ณ ๋ฆฌ ๋ณ„ ํด๋” ๊ตฌ์กฐ๋กœ ๋‚˜๋‰˜์–ด ์ €์žฅ
     |-_data/ : ์ƒ์„ฑ๋œ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ๋“ค์˜ ์ •๋ณด(ํƒœ๊ทธ ์ •๋ณด, ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด ๋“ฑ)๊ฐ€ jsonํ˜•์‹์œผ๋กœ ์ €์žฅ
     |-_etcs/ : ๊ธฐํƒ€ ์ž„์‹œ ์ฝ”๋“œ ์ €์žฅ์šฉ ํด๋”
     |-_includes/ : ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค(ํ—ค๋”, ํ‘ธํ„ฐ, ๋“œ๋กœ์›Œ ๋“ฑ)
     |-_layouts/ : ํŽ˜์ด์ง€ ํ…œํ”Œ๋ฆฟ๋“ค(์˜ต์‹œ๋””์–ธ ๋งˆํฌ๋‹ค์šด ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ ๊ธ€ ๋“ฑ)
     |-_plugins/ : ์ปค์Šคํ…€ ๋ฃจ๋น„ ํ”Œ๋Ÿฌ๊ทธ์ธ ํŒŒ์ผ๋“ค, ์ฃผ๋กœ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ์˜ ์ „์ฒ˜๋ฆฌ์™€ ํ›„์ฒ˜๋ฆฌ ๊ตฌํ˜„
     |-_sass/ : css๋กœ ์ปดํŒŒ์ผ๋˜ assets ํด๋”๋กœ ์˜ฎ๊ฒจ์ง
     |-_site/ : ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ ๊ฒฐ๊ณผ๋ฌผ
     ---filesโ†“---
     |-tsconfig.json : Typescript ์„ค์ • ํŒŒ์ผ
     |-webpack.config.js : Webpack ์„ค์ • ํŒŒ์ผ
     |-package.json : Javascript ํŒจํ‚ค์ง€ ์ •๋ณด
     |-Gemfile : Ruby ํŒจํ‚ค์ง€ ์ •๋ณด
     |-index.html : ๋ฉ”์ธ ํŽ˜์ด์ง€
     |-.eslintrc.json : Typescript linter ์„ค์ • ํŒŒ์ผ
     |-_config.yml : Jekyll ์„ค์ • ํŒŒ์ผ
    
    • _๊ฐ€ ์•ž์— ๋ถ™์€ ํด๋”๋‚˜ _config.yml์—์„œ ์ œ์™ธ ๋ชฉ๋ก์— ๋“ค์–ด๊ฐ„ ํด๋”๋Š” ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ์‹œ ์ œ์™ธ๋จ
    ๐Ÿงพ๏ธ ์ผ๋ถ€ ํด๋” ์†Œ๊ฐœ
    • assets ํด๋” : css, ์ด๋ฏธ์ง€, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋“ฑ ์—ฌ๋Ÿฌ ์ •์  ํŒŒ์ผ์ด ์ €์žฅ๋˜์–ด ์žˆ๋Š” ํด๋”
      ์ •์  ์‚ฌ์ดํŠธ ํ”„๋กœ์ ํŠธ์ด๋ฏ€๋กœ ๊ทœ๋ชจ๊ฐ€ ํฌ๋‹ค. _sass ํด๋”์—์„œ css ํŒŒ์ผ์„, scripts ํด๋”์—์„œ JS ํŒŒ์ผ์„ ์ปดํŒŒ์ผํ•˜์—ฌ ์ด๊ณณ์—์„œ ์ €์žฅํ•œ๋‹ค.

    • _articles ํด๋” : ์ž‘์„ฑํ•œ ๋งˆํฌ๋‹ค์šด ํŒŒ์ผ๋“ค์ด ์นดํ…Œ๊ณ ๋ฆฌ ๋ณ„ ํด๋” ๊ตฌ์กฐ๋กœ ๋‚˜๋‰˜์–ด ์ €์žฅ
      ๊ธฐ์กด์˜ _post ํด๋”์˜ ๋™์ž‘์„ ๋ชจ๋ฐฉํ•˜์—ฌ, Jekyll์ด ์ด๋“ค์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ๊ตฌํ˜„ํ•จ

    • _data ํด๋” : ์ƒ์„ฑ๋œ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ๋“ค์˜ ์ •๋ณด(ํƒœ๊ทธ ์ •๋ณด, ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด ๋“ฑ)๊ฐ€ json ํ˜•์‹์œผ๋กœ ์ €์žฅ
      Jekyll์ด ์ž๋™์œผ๋กœ ๋ณ€ํ™”๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฒŒ๋” ๊ตฌํ˜„ํ•˜์˜€๋‹ค.
      ์ฃผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ์ปค์Šคํ…€ ํ”Œ๋Ÿฌ๊ทธ์ธ์—์„œ ํฌ์ŠคํŠธ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์ผ์ข…์˜ DB ์—ญํ• ์„ ํ•œ๋‹ค.
      • Liquid์˜ ๊ฒฝ์šฐ Jekyll์˜ site ๋ณ€์ˆ˜์—์„œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ, JS์™€ ruby์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด์„œ ๊ตฌํ˜„
    • _includes ํด๋”์™€ _layouts ํด๋”: ์ปดํฌ๋„ŒํŠธ์™€ ํŽ˜์ด์ง€ ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ๋“ค
      liquid ํƒœ๊ทธ๊ฐ€ ํฌํ•จ๋˜์–ด html ํŒŒ์ผ๋“ค์ด ์กด์žฌ, _layouts ๋‚ด์˜ ํŒŒ์ผ์€ ์ผ์ข…์˜ ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ์ด๊ณ , _includes ๋‚ด์˜ ํŒŒ์ผ์€ ์ผ์ข…์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์ด๋‹ค.
      • ์˜ˆ๋ฅผ ๋“ค์–ด _layouts/obsidian.html์€ ์˜ต์‹œ๋””์–ธ ํŒŒ์ผ๋“ค์„ ํŽ˜์ด์ง€๋กœ ๋งŒ๋“ค ๋•Œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ
      • _includes/drawer/drawer.html์€ ํŽ˜์ด์ง€ ๋‚ด drawer๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ liquid include ๋ฌธ๋ฒ•์œผ๋กœ ๋ถˆ๋Ÿฌ์™€ ์‚ฌ์šฉํ•œ๋‹ค.
    • blog ํด๋” : ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ํŽ˜์ด์ง€๋“ค์— ์‚ฌ์šฉ๋˜๋Š” html ํŒŒ์ผ๋“ค
      ์ผ์ข…์˜ ๋ผ์šฐํŒ… ์ธ๋ฑ์Šค ํด๋”, ๋‚ด ์†Œ๊ฐœ ํŽ˜์ด์ง€, ๊ฒ€์ƒ‰๊ฒฐ๊ณผ ํŽ˜์ด์ง€, 404 ์—๋Ÿฌ ํŽ˜์ด์ง€, ํฌ์ŠคํŠธ ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€๊ฐ€ ์กด์žฌ

    • _site ํด๋” : ์ƒ์„ฑ๋œ ์ •์  ์‚ฌ์ดํŠธ ๊ฒฐ๊ณผ๋ฌผ
      ๋‚ด๋ถ€ ํŒŒ์ผ์„ gh-page ๋ธŒ๋žœ์น˜์— ์˜ฎ๊ฒจ ๋ฐฐํฌํ•œ๋‹ค.

    • ๊ธฐํƒ€ ํด๋”(_sass ํด๋”, scripts ํด๋”, node_modules ํด๋”)๋Š” ํ•ด๋‹น ๋„๋ฉ”์ธ์—์„œ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.

    Obsidian <=> Jekyll ํฌ์ŠคํŠธ ๊ตฌ์กฐ

    โž• Obsidian ์ด๋ž€?

    Jekyll์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋งˆํฌ๋‹ค์šด ํŒŒ์ผ์„ HTML ํŒŒ์ผ๋กœ ๋ฐ”๊พธ์–ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค.

    • ์ปค์Šคํ…€ id ์„ค์ •๊ณผ Hard wrap ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด Kramdown ๋งˆํฌ๋‹ค์šด ๋ณ€ํ™˜์œผ๋กœ ์„ค์ •์„ ๋ฐ”๊พธ์–ด ์ฃผ์—ˆ๋‹ค.

    ์ถ”๊ฐ€์ ์œผ๋กœ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด Ruby ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

    • ์ง์ ‘ ๊ตฌํ˜„ํ•œ ์ด์œ ๋Š” ํ•™์Šต + ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์Œ + gh page์—์„œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ง€์› ์•ˆํ•จ
    โœ Obsidian <=> Jekyll ํฌ์ŠคํŠธ ์•„ํ‚คํ…์ฒ˜ ๊ตฌํ˜„

    • ๋ณ€ํ™˜ ์ „, md ํŒŒ์ผ์— ์˜ํ–ฅ์„ ์ค˜์•ผํ•˜๋Š” ๊ธฐ๋Šฅ์€ Jekyll์—์„œ ์ง€์›ํ•˜๋Š” Generator ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜์—ฌ ๊ตฌํ˜„
    • ๋ณ€ํ™˜ ํ›„, html ํŒŒ์ผ์— ์˜ํ–ฅ์„ ์ค˜์•ผํ•˜๋Š” ๊ธฐ๋Šฅ์€ Liquid์—์„œ ์ง€์›ํ•˜๋Š” Custom Filter ๋“ฑ๋ก ๊ธฐ๋Šฅ์œผ๋กœ ๊ตฌํ˜„

    ์ „์ฒ˜๋ฆฌ ๊ตฌํ˜„: Custom Generator ๊ธฐ๋ฐ˜

    ๐Ÿงพ๏ธ ์ „์ฒ˜๋ฆฌ ํ”Œ๋Ÿฌ๊ทธ์ธ ํŒŒ์ผ ๊ตฌ์กฐ

    300

    ์ „์ฒ˜๋ฆฌ ๋ ˆ์ด์–ด๋Š” ruby ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ๊ตฌํ˜„๋˜์—ˆ์œผ๋ฉฐ, ์ถ”๊ฐ€๋กœ ๋ ˆ์ด์–ด ๋‚ด๋ถ€์— ๊ฐ ์ „์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋“ค์ด ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.
    Jekyll ์ธก์—์„œ ๊ฐ ๋งˆํฌ๋‹ค์šด ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Generator ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

    ๐Ÿงพ๏ธ Preprocessor.rb
    require_relative './layouts/obsidian/preprocess_obsidian'
    require_relative './common/modules/preprocess_frontmatter'
    require_relative './common/preprocess_common'
    
    module Preprocessor
      class ArticleConverter < Jekyll::Generator
        include PreprocessObsidian
        include PreprocessFrontmatter
        include PreprocessCommon
        def generate(site)
          changed = register_articles(site.collections['articles'])
          clear_categories if changed
          site.collections['articles'].docs.map do |article|
            result = preprocess_common(article, changed)
            result = preprocess_obsidian(site, result) if result['layout'].upcase == 'OBSIDIAN'
            result
          end
          create_category_pages(site).each do |page|
            site.pages << page
          end
        end
      end
    end
    
    • ๊ฐ€์žฅ ๋จผ์ € ์ƒˆ๋กœ ๋“ฑ๋ก๋œ ํŒŒ์ผ๋“ค์˜ ์ •๋ณด๋ฅผ _data ํด๋”์— ์—…๋ฐ์ดํŠธํ•œ๋‹ค.(register_articles)
    • ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ์˜ ์ •๋ณด(ํƒœ๊ทธ, ์‚ฌ์šฉํ•˜๋Š” ๋ ˆ์ด์•„์›ƒ)์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์ฃผ๋กœ ์˜ต์‹œ๋””์–ธ์—์„œ๋งŒ ์ง€์›ํ•˜๋Š” ๋งˆํฌ๋‹ค์šด ๊ธฐ๋Šฅ๋“ค์„ ๋žœ๋”๋งํ•˜๊ธฐ ์œ„ํ•œ ์ •๋ณด๋“ค์„ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜๋“ค์ด๋‹ค.
    • ํด๋” ๊ตฌ์กฐ์— ๋”ฐ๋ผ ๋ณ€ํ˜•๋˜๋Š” ๊ฒŒ์‹œํŒ ์นดํ…Œ๊ณ ๋ฆฌ ๊ตฌ์กฐ ํŽ˜์ด์ง€ ๋˜ํ•œ ์ด๊ณณ์—์„œ ๊ตฌํ˜„๋œ๋‹ค.
    • ๋งˆํฌ๋‹ค์šด ํŒŒ์ผ์€ DOM ๊ตฌ์กฐ๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๋Œ€๋ถ€๋ถ„ ์ •๊ทœ ํ‘œํ˜„์‹์„ ํ†ตํ•ด ์š”์†Œ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์ˆ˜์ •ํ•œ๋‹ค.

    ๊ตฌํ˜„ํ•˜๋ฉด์„œ ์ •๊ทœํ‘œํ˜„์‹์„ ์ •๋ง ๋งŽ์ด ๊ณต๋ถ€ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
    ๊ธฐ์กด์—๋Š” ์ •๊ทœ ํ‘œํ˜„์‹์„ ์ •๋ง ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๊ณ  ๋ณต์žกํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ ์ดˆ๋ณด์ ์ธ ๋‹จ๊ณ„๊นŒ์ง€๋งŒ ํ•™์Šตํ–ˆ์ง€๋งŒ, ์ด์ œ ์บก์ฒ˜ ๊ทธ๋ฃน๋ถ€ํ„ฐ ๋ฃฉ ์–ดํ—ค๋“œ๊นŒ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

    ํ›„์ฒ˜๋ฆฌ ๊ตฌํ˜„ : Custom Liquid Filter ๊ธฐ๋ฐ˜

    ๐Ÿงพ๏ธ ํ›„์ฒ˜๋ฆฌ ํ”Œ๋Ÿฌ๊ทธ์ธ ํŒŒ์ผ ๊ตฌ์กฐ

    ํ›„์ฒ˜๋ฆฌ ๋ ˆ์ด์–ด ๋˜ํ•œ ruby ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ๊ตฌํ˜„๋˜์—ˆ์œผ๋ฉฐ, Jekyll์˜ layout ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด์„œ ํ•„์š”ํ•œ ํ›„์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋งŒ Liquid Custom Filter๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌ๋˜๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

    ๐Ÿงพ๏ธ layout ํ›„์ฒ˜๋ฆฌ ํ•„ํ„ฐ ์˜ˆ์‹œ
    ...
    <div class="content-section">
      {{content | postprocess_obsidian}}
    </div>
    ...
    

    ์ฃผ๋กœ, ์ฝœ์•„์›ƒ์ด๋‚˜ TOC, ์œ„ํ‚ค ๋งํฌ ๋“ฑ์˜ ์‹ค์ œ ๋ทฐ๋ฅผ HTML ํƒœ๊ทธ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์—ˆ๋‹ค.

    ๐Ÿงพ๏ธ postprocess_obsidian.rb
    require 'liquid'
    require 'nokogiri'
    require_relative './modules/postprocess_toc'
    require_relative './modules/postprocess_callout'
    require_relative './modules/postprocess_wikilink'  
    
    module Jekyll
      module PostprocessObsidian
        include PostprocessToc
        include PostprocessCallout
        include PostprocessWikilink
        def postprocess_obsidian(str)
          html = Nokogiri.HTML5(str)
          html = convert_noneng_custom_id(html)
          html = convert_toc(html)
          html = html.to_html
          html = convert_callout(html)
          html = convert_wikilink(html)
          html
        end
      end
    end
    
    Liquid::Template.register_filter(Jekyll::PostprocessObsidian)
    

    ๊ฐœ๋ฐœ ์ดˆ๋ฐ˜์—๋Š” DOM ํŠธ๋ฆฌ ํƒ์ƒ‰ ๋ฐ ๋ณ€๊ฒฝ์„ ์ •๊ทœํ‘œํ˜„์‹์œผ๋กœ ์ฒ˜๋ฆฌํ–ˆ์œผ๋‚˜, ํ›„๋ฐ˜์—๋Š” Nokogiri๋ผ๋Š” HTML DOM ๊ธฐ๋ฐ˜ parser ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ–ˆ๋‹ค.

    • ๋‹ค๋งŒ ์ผ๋ถ€ ๊ฒฝ์šฐ, ์˜คํžˆ๋ ค ๊ฐ€๋…์„ฑ์ด ๋‚˜๋น ์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด ๊ทธ๋Œ€๋กœ ์ •๊ทœ ํ‘œํ˜„์‹ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„ํ•œ ๊ธฐ๋Šฅ๋„ ์กด์žฌํ•œ๋‹ค.

    ํšŒ๊ณ 

    Ruby

    ๐Ÿงพ๏ธ ๋‚ด Ruby ์ฝ”๋“œ ์˜ˆ์‹œ
    def create_category_page_recursive(site, categories, data) # python๊ณผ ์œ ์‚ฌํ•˜๋‹ค.
      result = data['categories'].keys.inject([]) do |memo, sub_category| # ๋‹ค์–‘ํ•œ loop๋ฌธ ํ‘œํ˜„
        memo + create_category_page_recursive(site, categories + [sub_category], data['categories'][sub_category])
      end
      if categories.empty? # ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ, ํŒŒ๋ผ๋ฏธํ„ฐ ์—†์„ ๊ฒฝ์šฐ ์ƒ๋žต ๊ฐ€๋Šฅํ•œ "()"
        result # return์„ ์ƒ๋žต ๊ฐ€๋Šฅ
      else
        [CategoryPage.new(site, categories, data)] + result
      end
    end
    
    • Ruby๋Š” ํŒŒ์ด์ฌ๊ณผ ์ƒ๋‹นํžˆ ๋น„์Šทํ•˜๊ฒŒ ์‚ฌ์šฉ์ž์˜ ๊ฐ€๋…์„ฑ๊ณผ ํŽธ์˜์„ฑ์„ ์ƒ๋‹นํžˆ ์‹ ๊ฒฝ์“ด ๊ฒƒ์ด ๋Š๊ปด์กŒ๋‹ค.
      • ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์„ ์–ธํ•  ํ•„์š”๊ฐ€ ์—†์Œ
      • ํ•จ์ˆ˜์˜ return์„ ์ƒ๋žต ๊ฐ€๋Šฅ
      • .empty?, .nil? ๋“ฑ ์ง๊ด€์ ์ด๊ณ  ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๊ฐ€๋Šฅ
    • ๋‹จ, ์˜คํžˆ๋ ค ์ด์ ์ด ์˜คํžˆ๋ ค ํ˜ธ๋ถˆํ˜ธ ๊ฐˆ๋ฆฐ ๊ฒฝ์šฐ๋„ ๋งŽ๋‹ค.
      • ํ•จ์ˆ˜์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋„˜๊ธฐ์ง€ ์•Š์„ ๋•Œ๋Š” ๊ด„ํ˜ธ๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์Œ, ๊ทธ๋Ÿด ๊ฒฝ์šฐ ํ•ด๋‹น ๊ฐ์ฒด์˜ ๋ณ€์ˆ˜๋ฅผ ์ฝ์€๊ฑด์ง€, ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ๊ฑด์ง€ ๋ณด๊ธฐ๋งŒํ•ด์„œ๋Š” ์•Œ ์ˆ˜ ์—†์Œ.
      • ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ return ๊ฐ’์ด ์กด์žฌํ•˜๋Š” ํ•จ์ˆ˜์ธ์ง€, ์•„๋‹Œ์ง€๋„ ์•Œ๊ธฐ ํž˜๋“ค๋‹ค.
      • ๋งˆ์น˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฃจํ”„๋ฌธ๋“ค ์ฒ˜๋Ÿผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฐฉ์‹์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ 
      • unless ์ฒ˜๋Ÿผ ๋‹จ์ˆœํžˆ if์˜ ๋ฐ˜๋Œ€์˜ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„ ํ‘œํ˜„๋„ ์žˆ๋‹ค.
    ๐Ÿงพ๏ธ Rubocop Linter ๊ฒฝ๊ณ ๋ฌธ ์˜ˆ์‹œ

    • Ruby์˜ Linter ๊ฒธ Formatter์ธ Rubocop ์„ ์ ์šฉํ–ˆ์—ˆ๋Š”๋ฐ, ๋‚ด ์งง์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ธ์ƒ ์ค‘, ๊ฐ€์žฅ ํ›Œ๋ฅญํ•œ Linter์˜€๋‹ค.
      • ์ฝ”๋“œ ์Šคํƒ€์ผ, ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜, ์ฃผ์„ ์—ฌ๋ถ€ ๊ฐ™์€ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ
      • ๊ฐ™์€ ๋™์ž‘์˜ ๋” ์ข‹์€ ํ‘œํ˜„๊นŒ์ง€ ์ถ”์ฒœ
      • ABCSize, ์ˆœํ™˜ ๋ณต์žก๋„ ๊ฐ™์€ ๊ฐ์ข… ์ฝ”๋“œ ๋ณต์žก๋„๊นŒ์ง€ ์ง€์›
      • ๊ท€์ฐฎ์œผ๋ฉด ๋ฒ„ํŠผ ํ•˜๋‚˜๋กœ ์ด๋ฅผ ์ž๋™์œผ๋กœ ์ˆ˜์ • (์ฝ”๋“œ ํ‘œํ˜„๊นŒ์ง€๋„!)
      • VScode์™€์˜ ํ˜ธํ™˜์„ฑ์ด ์ข‹๊ณ , ์„ค์ •๋„ ์‰ฌ์› ์œผ5๋ฉฐ, Reek ๊ฐ™์€ ๋‹ค๋ฅธ ๋ฆฐํ„ฐ์™€ ๋™์‹œ์— ์‚ฌ์šฉ๊ฐ€๋Šฅ.
      • ์„ค๋ช…์ด ์ž˜๋˜์–ด ์žˆ๊ณ , ๋ฌธ์„œํ™”๊ฐ€ ์ž˜๋˜์–ด์žˆ๋‹ค.
    ๐Ÿงพ๏ธ Rubocop CyclomaticComplexity ๋ฌธ์„œ ์ค‘ ์ผ๋ถ€

    ๋ฌธ์„œ๋ฅผ ์ฝ์œผ๋ฉด์„œ, ์ข‹์€ ์ฝ”๋“œ์— ๋Œ€ํ•ด ๋งŽ์ด ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

    ๋ฌผ๋ก  ์–ด์ฉŒ๋ฉด ๋‚ด๊ฐ€ ๋‹ค๋ฅธ ์–ธ์–ด์˜ Linter๋ฅผ ์ž˜๋ชป์“ฐ๋Š” ๊ฒƒ์ผ์ง€๋„ ๋ชจ๋ฅด์ง€๋งŒ

    • regex๋ฅผ ์ด์šฉํ•˜๊ธฐ ์ „์— ์ง„์ฆ‰์— Nokogiri๋ฅผ ์ผ์œผ๋ฉด ์‹œ๊ฐ„์„ ๊ฝค๋‚˜ ์•„๊ผˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.
    • ์ œ๋Œ€๋กœ ์„ค๊ณ„๋ฅผ ์•ˆํ•˜๊ณ  ์จ์„œ ๊ทธ๋Ÿฐ์ง€, ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด๋‚˜ ์žฌ์‚ฌ์šฉ์„ฑ์ด ์กฐ๊ธˆ ์•„์‰ฝ๋‹ค.
    • Ruby on rails๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ–ˆ์œผ๋ฉด ๊ฒฝํ—˜์— ํฐ ๋„์›€์ด ๋ฌ์„ ๊ฒƒ ๊ฐ™์ง€๋งŒ, ๋‚ด๊ฐ€ Ruby๋ฅผ ๋” ํŒŒ๋ณผ ์ผ์€ ์—†์„ ๊ฒƒ ๊ฐ™๋‹ค.

    Jekyll

    • ํ™•์‹คํžˆ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ํด๋ฆญ ๋ช‡๋ฒˆ์œผ๋กœ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ , ๊ฐ€๋ฒผ์šด ๋ธ”๋กœ๊ทธ๋กœ์จ ์†์ƒ‰์ด ์—†์—ˆ์ง€๋งŒ, ๋‚˜์˜ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์š•์‹ฌ์ด ์ด๋ฅผ ๋ง์ณค๋‹ค.
      • ์˜คํžˆ๋ ค, ๊ธฐ์กด ๊ธฐ๋Šฅ์„ ์ˆ˜์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š๋ผ ํž˜๋“ค์—ˆ๋‹ค.
      • ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ธฐ๋ณธ ๊ฐ’์ธ post ์ฝœ๋ ‰์…˜์„ ์ด์šฉํ•˜๋‹ค ํŒŒ์ผ๋“ค์˜ ์ œ๋ชฉ์„ ์ด์ƒํ•˜๊ฒŒ ๋ฐ”๊ฟ”์•ผํ•˜๋Š” (date-sluggedtitle.md) ์ œํ•œ์ด ๋งˆ์Œ์— ์•ˆ๋“ค์–ด ์ƒˆ๋กœ์šด ์ฝœ๋ ‰์…˜์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ณผ์ •์—์„œ ๋ชจ๋“  ํŒŒ์ผ๋“ค์˜ ๋‚ด์šฉ๊ณผ ์ œ๋ชฉ์„ ์†๋ด์ค˜์•ผ ํ–ˆ๋‹ค.
      • ์ •์  ์‚ฌ์ดํŠธ์— ๋™์  ๊ธฐ๋Šฅ์„ ๋„ฃ์„ ์ƒ๊ฐ์„ ํ•œ ์‹œ์ ์—์„œ ์ด์ƒํ•จ์„ ๋Š๊ปด์•ผ ํ–ˆ๋‹ค.
    • github page์—์„œ ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ์ผ๋ถ€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ œ์™ธํ•˜๊ณ  ์ง€์›ํ•˜์ง€ ์•Š์•˜๋˜ ์  ๋˜ํ•œ ์น˜๋ช…์ ์ด์—ˆ๋‹ค.
      • ์ง€์›๋˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ ์ฐพ๊ธฐ -> netlify ๋“ฑ์˜ ๋‹ค๋ฅธ ๋ฌด๋ฃŒ ๋ฐฐํฌ ์„œ๋น„์Šค ์ฐพ์•„๋ณด๊ธฐ -> ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ, ๋ฃจ๋น„, ํ…œํ”Œ๋ฆฟ ์–ธ์–ด ๋“ฑ์œผ๋กœ ๊ธฐ๋Šฅ ์ง์ ‘ ๊ตฌํ˜„ -> ์ปค์Šคํ…€ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ง€์›์„ ์œ„ํ•ด github action ๊ฑด๋“œ๋ ค๋ณด๊ธฐ
      • ์œ„ ๊ณผ์ •์˜ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ ธ๋‹ค.
    • ํ•˜์ง€๋งŒ, ๋งŒ์•ฝ ๋‚˜์˜ ๊ฒฝ์šฐ์™€ ์ •๋ฐ˜๋Œ€๋กœ, ๋ณ„ ๋‹ค๋ฅธ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ์—†์ด ๋ธ”๋กœ๊น…ํ•˜๋ ค๋ฉด, ๊ตณ์ด Jekyll์„ ์“ฐ๋Š” ๊ฒƒ ๋ณด๋‹ค๋Š” Tistory๋‚˜ ๋„ค์ด๋ฒ„ ๋ธ”๋กœ๊ทธ, velog ๊ฐ™์€ ์ƒ์šฉ ๋ธ”๋กœ๊ทธ๋ฅผ ์“ฐ๋Š”๊ฒŒ ๋” ๋‚˜์€๊ฒƒ ๊ฐ™๋‹ค.
      • ๋Œ“๊ธ€, ์กฐํšŒ์ˆ˜, ์ถ”์ฒœ ๋“ฑ์˜ ๋™์ ์ธ ๊ธฐ๋Šฅ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๊ด‘๊ณ  ๋“ฑ์„ ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ
    • Liquid ํ…œํ”Œ๋ฆฟ ์–ธ์–ด๋Š” include๋ฅผ ์ด์šฉํ•œ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์ด ์‰ฌ์› ๊ณ , ๊ฐ์ข… ํ•„ํ„ฐ์™€ ํ•จ์ˆ˜๋“ค์ด ๊ฝค ํŽธ๋ฆฌํ–ˆ์ง€๋งŒ, ์—ฌ์ „ํžˆ ๋ณ„๋กœ์˜€๋‹ค. React์˜ JSX์™€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋„ˆ๋ฌด ๊ทธ๋ฆฌ์› ๋‹ค.
      • jinja2 ๊ฐ™์€ ๋‹ค๋ฅธ ํ…œํ”Œ๋ฆฟ ์–ธ์–ด์™€์˜ ์ฐจ๋ณ„์ ์€ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋‹ค.