Featured image of post [Netlify CMS] Markdown 한글 입력 오류 해결 방안

[Netlify CMS] Markdown 한글 입력 오류 해결 방안

한글 씹힘, 마크다운 적용 안됨, 커서 마음대로 이동

Introduction

최근 블로그에 다시 글을 쓰기 시작하면서 여러가지 겪었던 불편 중에 가장 큰 비중을 차지 했던 문제를 해결 할만한 대안을 발견하여 급하게 글을 작성한다. 필자도 Netlify CMS를 초창기 부터 사용하면서 겪었던 문제고, 찾아보니 라틴어 계열이 아닌 국가에서 많이 겪고 있는 문제로 보였다.

나도 이 문제 때문에 기껏 만든 웹 기반 CMS에서 글을 작성하지 않고 메모장에 작성 후 다시 붙여넣는 등 Preview 기능을 제대로 활용할 수 없어 굉장히 비효율적 이었다. Netlify CMS의 Preview를 내 블로그 스타일과 동일하게 적용하면서 CMS 구조를 분석해보다가 해결 방법을 찾게 되었다. 하지만 완전히 해결하는 방법은 아니고 약간의 꼼수를 사용하는 방법이다.


Problem

먼저 필자가 겪었던 문제점을 크게 분류 하자면 다음과 같다.

  1. 한글 입력 시 커서가 해당 줄 맨 뒤로 자동으로 이동
  2. 한글 입력 중 커서가 해당 글자 아래에 있을 때, 다른 행동을 하면 해당 글자가 씹혀 없어짐
  3. 모음과 자음이 합쳐지지 않고 따로따로 입력되는 문제

해당 Github 에 확인을 해보면 이러한 문제 말고 다른 오류도 발생하는 것으로 보인다. 이러한 문제가 발생하는 것은 Netlify CMS는 Slate 라는 마크다운 편집기를 사용하는데, Issues 를 확인해보면 Slate 내부적으로 발생하는 문제인 것으로 확인된다. 관련 내용을 쭉 읽어보면 Slate의 버전을 높이면 어느정도 해결 가능하다고 하나, 다른 문제가 발생하기도 하고 Netlify CMS 내부적으로 구현되어있는 Slate의 버전을 내가 높이기는 어렵다.


Settings

Netlify CMS를 사용한다면 /admin 하위 폴더에 index.htmlconfig.yml 두 가지 파일이 있을 것 이다. 문제를 단순히 설명하기 위해 config.yml은 아래와 같이 Markdown 입력 폼 하나로만 구성되어 있다고 하자.

1
2
3
4
5
6
7
8
collections:
  - name: "posts"
    label: "Posts"
    folder: "content/post"
    create: true
    path: "{{slug}}/index"
    fields:
      - {label: "Body", name: "body", widget: "markdown"}

그리고 index.html<script></script> 부분만 아래와 같이 가정하자.

1
2
3
4
5
6
7
8
<script>
    var PostPreview = createClass({
        render: function() {
            return h('section', {"className" : "article-content"}, this.props.widgetFor('body'));
        }
    });
    CMS.registerPreviewTemplate("posts", PostPreview);
</script>

Solution

해당 문제를 해결하기 위해 이것저것 실험을 해보는 중 Netlify CMS 공식 Docs 를 보면 오류가 발생하는 markdownDataTypestring (markdown)으로 되어 있는데, 이를 textstring (multiline)으로 대체 해보았다.

이 경우에 기존 config.ymlwidget: "markdown"widget: "text"로 변경하고 index.htmlthis.props.widgetFor('body') 부분을 entry.getIn(['data', 'body'])으로 변경하면 Preview 부분에 마크다운이 하나도 적용되지 않고 출력되는 것을 확인 할 수 있다. 하지만 text의 경우에는 한글 씹힘이 일어나지 않는 것을 확인 할 수 있다.

markdown일 때의 console.log(this.props.widgetFor('body'))를 통해 구조를 확인해 보면 아래와 같이 출력 된다.

마크다운의 this.props.widgetFor('body') 구조

해당 구조를 자세히 보면 props.value 부분이 Preview에 보여주는 마크다운 형태의 텍스트인 것을 확인 할 수 있다.

따라서 이 부분을 text폼을 통해 입력받고 entry.getIn(['data', 'body'])으로 값을 가져와 props.value 값에 대입만 해주면 된다.

🚨 단, 한가지 중요한 점은 markdown 데이터 구조를 얻기위해 사용하지 않을 markdown 입력 창을 추가로 생성해야 한다. 아래와 같이 두 코드를 수정하자.

📄 config.yml

1
2
3
4
5
6
7
8
9
collections:
  - name: "posts"
    label: "Posts"
    folder: "content/post"
    create: true
    path: "{{slug}}/index"
    fields:
      - {label: "Body", name: "body", widget: "text", default: "No Edit"}
      - {label: "MD", name: "MD", widget: "markdown"}

📄 index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<script>
    var MD = this.props.widgetFor('MD');
    var text = entry.getIn(['data', 'body']);
    MD.props.value = text;

    var PostPreview = createClass({
        render: function() {
            return h('section', {"className" : "article-content"}, MD);
        }
    });
    CMS.registerPreviewTemplate("posts", PostPreview);
</script>

🦉 마무리 🦉

이렇게 텍스트 폼에 입력을 하면 오른쪽 Preview 창에 바로 반영 된다. 마크다운도 잘 적용 되는 것을 확인 할 수 있다. 그리고 입력창과 Preview 창의 싱크까지 맞는 예상치 못한 효과도 얻었다.

🚨 해당 기능을 추가하면 추가하기 이전에 생성한 글들은 Preview로 열리지 않는 경우가 발생할 수 있다. 필자는 Hugo를 사용하기 때문에 이전 모든 포스팅을 손으로 하나하나 수정 해주었다.

21년도 부터 나만의 블로그 제작 환경을 구축하고 싶었는데, 실력이 부족 하였는지 필요한 기능을 모두 갖추지 못한채 불편하게 포스팅 하였다. 그런 이유로 인해서인지 포스팅 하는 주기가 길어졌던 것 같다. 현재 원하던 모든 기능을 갖추게 되어 포스팅을 활발히 하게 되지 않을까 싶다.

Built with Hugo
Theme Stack designed by Jimmy