render

/usr/local/m2/setting.json 다음 영역에 대해 기술한다.

{
  "functions": {
    "contents": {
      "render": {
        ...
      }
    }
  }
}

How to use

명령어 리스트

# /templates/banner.html 를 기반으로 이미지를 생성한다.
# 변수는 args로 입력한다.
https://exmple.com/templates/banner.html/render/args/title=this_is_title;desc=this_is_desc
https://exmple.com/templates/banner.html/render/args/code=200
https://exmple.com/templates/banner.html/render/args/id=[1,3,5,7,9];key=ASDDDKKQW9
https://exmple.com/templates/banner.html/render/args/maintext=%ec%a0%9c%eb%aa%a9;subtext=%ec%84%a4%eb%aa%85;id=100

# output 명령어를 이용해 다양한 포맷과 크기로 가공한다.
https://exmple.com/templates/banner.html/render/args/code=200/output/format=pdf
https://exmple.com/templates/banner.html/render/args/code=200/output/format=png;width=1200

명령어

파라미터

동작

args

문자열 URL 인코딩

URL 인코딩된 문자열

output

(하위설정)

output 설정

meta

"meta" : {
  "enable" : false,
  "keyword": "render",
  "timeout": 5
}
enable (기본: false)

렌더링 활성화

keyword (기본: render)

렌더링 키워드

timeout (기본: 5초)

렌더링 타임아웃

output

출력 형식의 기본 값을 정의한다.

"output" : {
  "format" : "jpg",
  "width" : "auto",
  "height" : "auto"
}
format (기본: jpg)

출력 포맷 jpg , png , webp , avif (draft) , pdf , html (debug 용) 를 지원한다.

width (기본: auto)

가로 길이

  • auto 속성( <div style="width: 640px; ..."> )이 명시된 태그를 기반으로 계산한다. 속성이 명확하지 않다면 부정학할 수 있다.

  • {pixel} 640처럼 가로 길이를 고정한다.

height (기본: auto)

세로 길이

  • auto 태그 렌더링 면적의 높이를 계산한다.

  • {pixel} 480처럼 세로 길이를 고정한다.

Note

렌더링은 다음 우선순위에 따른다.

  1. 클라이언트에 의한 output 명령어 호출

  2. template에 정의된 <meta name="m2-render-output"> 의 속성

  3. output 설정 (기본)

템플릿 제작

템플릿(template)은 html 파일 형식의 렌더링 소스이다. 다양한 데이터 참조 방법을 이용해 동적 콘텐츠 제작에 사용된다. 다음은 간단한 400 x 300 해상도의 png 파일을 생성하는 간단한 예제이다.

<!DOCTYPE html>
<html>
   <head>
      <meta name="m2-render-output" format="png" width="400" height="300">
      <style>
         p { display: block; margin-top: 1em; margin-bottom: 1em; }
      </style>
   </head>
   <body>
      <H1>{{ args.maintext }}</H1>
      <H2>{{ args.subtext }}</H2>
   </body>
</html>

Warning

템플릿의 모든 리소스는 절대 URL로 기재되어야 정상동작한다. 다음과 같이 이미지를 상대주소로 로딩하면 기술적인 이유로 동작하지 않는다.

<img src="/noimage.jpg">
<img src="//demo.winesoft.co.kr/noimage.jpg">
<img src="https://demo.winesoft.co.kr/no2.jpg" onerror="this.src='//demo.winesoft.co.kr/no2.jpg'">

올바른 표현은 아래와 같다.

<img src="https://demo.winesoft.co.kr/noimage.jpg">
<img src="https://demo.winesoft.co.kr/no2.jpg" onerror="this.src='https://demo.winesoft.co.kr/no2.jpg'">

데이터 참조에는 {{ ... }} 라는 nunjucks 표현이 사용된다.

데이터 참조

템플릿에서는 3가지 형태의 데이터 참조가 가능하다.

표현

설명

{{ req.* }}

클라이언트 HTTP 요청

{{ args.* }}

args 명령어로 입력된 Key/Value 쌍의 값

{{ ext.* }}

템플릿에 선언된 백엔드 API 호출의 응답

HTTP 요청 {{ req }}

클라이언트가 전송한 HTTP 요청은 다음과 같이 구조화되어 템플릿에서 참조한다.

{
  "req": {
   "headers": {
      "host": "www.example.com:8585",
      "if-modified-since": "Mon, 13 Apr 2020 06:41:28 GMT",
      "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36",
      "accept-encoding": "gzip"
   },
   "hostname": "www.example.com",
   "httpVersion": "1.1",
   "method": "GET",
   "path": "/fruits",
   "protocol": "http",
   "query": {
      "model": "apple",
      "view": "list"
   },
   "url": "/fruits?model=apple&view=list",
   "xhr": false
}
  • headers - 클라이언트 요청헤더 목록

  • hostname - 요청 호스트 이름

  • httpVersion - HTTP 버전

  • method - HTTP 메소드

  • path - 요청 URL 중 경로 정보

  • protocol - 프로토콜

  • query - 쿼리스트링 키/값 리스트

  • url - 요청 URL 정보

  • xhr - Ajax에 의한 요청 여부 ( true 인 경우 Ajax호출)

클라이언트 입력 {{ args }}

클라이언트가 호출한 HTTP 요청 중 args 의 값을 구조화하여 템플릿에서 참조한다.

https://exmple.com/templates/banner.html/render/args/maintext=%ec%a0%9c%eb%aa%a9;subtext=%ec%84%a4%eb%aa%85;id=100

Note

값은 URL 디코딩된다.

{
  "args": {
    "maintext": "제목",
    "subtext": "설명",
    "id": 100
  }
}

{{ args }} 는 1차원적인 Key/Value 쌍을 제공하는 목적으로 구조화된 데이터 모델을 제공하지는 않는다.

외부 API {{ ext }}

렌더링 시점에 참조해야 할 백엔드 API 서버가 있다면 템플릿 파일에 정의한다.

<!DOCTYPE html>
<html>
  <head>
    <!-- link 태그는 데이터 참조 후 제거된다. -->
    <link ref="external" href="https://myapi.com/info?key={{ args.id }} name="info">
    ...
  </head>
  <body>
    <H1>{{ ext.info.name }} {{ ext.info.age }}</H1>
    <p>{{ ext.info.city }}</p>
  </body>
</html>

템플릿을 렌더링 하기 전 <link ref="external" ...> 태그는 모두 전처리/참조되어 {{ ext }} 에 바인딩된다. 위 예제는 아래와 같이 동작한다.

# https://myapi.com/info?key=100 호출 결과
{name:"John", age:31, city:"New York"}

# 호출결과는 ext 하위에 name 속성 값으로 바인딩 된다.
{
  "ext": {
    "info": {
      "name": "John",
      "age": 31,
      "city": "New York"
    }
  }
}

# 템플릿의 {{ ext.* }} 표현을 데이터 매핑한다.
<body>
  <H1>John 31</H1>
  <p>New York</p>
</body>

Note

  • name 속성이 제공되지 않으면 _anon_ 이 사용된다.

    {
      "ext": {
        "_anon_": { ... }
      }
    }
    
  • 같은 name 속성이라면 마지막 선언된 <link> 로 덮어씌워진다.

외부 API {{ ext }} 동형/배열 참조

args 를 배열로 입력하면 백엔드 API를 여러번 호출한 결과를 배열로 구성한다.

# 클라이언트 호출
https://exmple.com/templates/banner.html/render/args/id=[1,3,5,7,9]

# 템플릿의 API 참조
<link ref="external" href="https://myapi.com/info?key={{ args.id }}" name="info">

# 데이터 참조
https://myapi.com/info?key=1
https://myapi.com/info?key=3
https://myapi.com/info?key=5
https://myapi.com/info?key=7
https://myapi.com/info?key=9

5개의 동일한 결과는 배열로 {{ ext }} 에 바인딩된다.

{
  "ext": {
    "info": [
      {
        "name": "John",
        "age": 31,
        "city": "New York"
      },
      {
        "name": "Jane",
        "age": 24,
        "city": "Boston"
      },
      ...
    ]
  }
}

템플릿에서 배열 표현으로 참조 가능하다.

<!DOCTYPE html>
<html>
  <body>
    <ul>
      {% for item in ext.info %}
      <li>{{ item.name }}</li>
      {% endfor %}
    </ul>
  </body>
</html>

외부 API {{ ext }} 이형 참조

서로 다른(=heterogeneous) 백엔드 API를 연동하는 경우 name 속성을 다르게 바인딩한다.

#  template - <html><head>
<link ref="external" href="https://myapi.com/info?key={{ args.id }}" name="info">
<link ref="external" href="https://desc.myapi.com/products/{{ args.id }}" name="desc">

# {{ ext }} - 호출 결과는 ext 하위로 name 속성을 통해 바인딩된다.
{
  "ext": {
    "info": { ... },
    "desc": { ... },
  }
}

# template
<H1>{{ ext.info.name }} {{ ext.info.age }}</H1>
<p>{{ ext.desc.descriptions }}</p>

nunjucks

NunjucksFlask 에서 사용하는 Jinja2 에 영감을 받은 언어이다.

{
  "firstName": "John",
  "lastName": "Smith",
  "age": 25,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021"
  },
  "phoneNumber": [
    { "type": "home", "number": "212 555-1234" },
    { "type": "fax", "number": "646 555-4567" }
  ]
}

Nunjucks 형식으로 다음과 같이 템플릿에서 참조 가능하다.

{{ firstname }}
{{ address.state }}
{{ phoneNumber.0.number }}

조건문, 반복문을 지원한다.

{% if hungry %}
  I am hungry
{% elif tired %}
  I am tired
{% else %}
  I am good!
{% endif %}
<h1>Posts</h1>
<ul>
{% for item in items %}
   <li>{{ item.title }}</li>
{% else %}
   <li>This would display if the 'item' collection were empty</li>
{% endfor %}
</ul>

Note

더 많은 내용은 https://mozilla.github.io/nunjucks/ 를 참조한다.