NoCodeで
CMSと連携する
デザインツールを
作っている話

@miyaoka

本日のアジェンダ

1. STUDIOでやっていること

2. 動的なサイトを作れるようにする

3. CMSと連携させる

STUDIOで
やっていること

1

STUDIO

コードを書かずにWebサイト制作ができるプラットフォームサービス

こういう

要はホームページビルダーみたいな…

我々は
どういうものを
目指しているのか?

STUDIOの
WHY - HOW - WHAT

「なぜやるか?」

「どうやるか?」

「なにをやるか?」

WHY(ビジョン)

’Everyone is creative.’

「誰もが本来クリエイティブである」

→でもそうなってない

→なにかしらできない理由がある

HOW(ミッション)

’Unleash your creativity.’

「クリエイティビティを解放する」

→障壁になっていることを取り除く

WHAT

  • デザイナーとエンジニアのワークフローを一つにする

  • NoCodeでも動的な機能が実現できるようにする

  • CMS連携することでコンテンツドリブンの制作ができるようにする

「そのために何をするのか?」

我々フロントがやっていること

state定義

render関数

結果

コードによるワークフロー

state定義

render関数

結果

「がんばってコードを書く」

見た目・挙動を確認してコード調整

GUIエディタによるワークフロー

「いい感じに見た目をいじる」

state定義

render関数

結果

エディタにフィードバック

(STUDIOであらかじめ定義)

「がんばってコードを書く」

「いい感じに見た目をいじる」

✨Creativity✨

GUIエディタでできること

  • DOMの内容を編集(テキスト内容や画像パス、スタイルなど)

  • ドラッグしてリサイズ、ダブルクリックしてサイズautoに設定

  • 要素の追加・削除・並び替え

  • などなど…

GUIで編集したデータをレンダリング

const textDom = {
  content: {
    type: 'text',
    data: 'This is a Text.'
  },
  style: {
    color: '#3239e6',
    padding: '12px'
  }
}
const imgDom = {
  content: {
    type: 'img',
    src: 'https://example.com/img.jpg'
  },
  style: {
    width: '126px',
    height: 'auto',
    margin: '12px 0px 0px 0px'
  }
}

TextRenderer

ImgRenderer

Domの種類に応じたRender関数を用意して表示

const iconDom = {
  content: {
    type: 'icon',
    data: 'face'
  },
  style: {
    fontSize: '64px',
    color: 'rgb(106, 176, 29)'
  }
}

IconRenderer

ライブプレビュー

編集中の内容をリアルタイムに複数環境で確認したり共同編集したり

技術的な話:プレビューと公開

編集プレビュー中:
Firebaseでリアルタイム同期

 

公開サイト:
静的化したsnapshotデータを使って表示

そんなわけで
だいたい
いい感じにできる
ようになりました

静的サイトに限れば…

現状の課題点

  • 動的なデータという概念が無いため、言ってみれば全てがレイアウト情報
  • つまりコンテンツとレイアウトが分離されていない
    • コンテンツを更新していくようなワークフローに向かない(作りきりのLPの用途が多い)
  • 動的ページという概念もない
    • 一覧ページからの詳細ページをアイテム数分作らないといけない
    • レイアウトを変えようとしてもたくさんページを編集する必要がある

動的なサイトを
作れるようにする

2

動的とは

人類は
まだ
発明してない

成功してるGUI環境は、単目的か、プログラミングの補助ツールであって、制御構造をテキストプログラミング以外で表現するのは、現状あまりコスパがよくない。

それはそう

NoCodeを目指しながら
コードの表現力も
利用するようにしました

STUDIO Code

たとえば日付表示

  • テキスト要素にdateの変数をバインドしている
  • しかし日付文字列はデザインに応じてフォーマットする必要がある

日付フォーマットUI

  • 日付表示のパターンを選べるようにしたもの
  • しかし、これ以外に曜日も表示したいなど要望はいくらでもありうる
  • それらを完璧にGUIとして作るのはつらい

内部的には関数定義を保持

  • 先程のフォーマットUIはDate.toLocaleString()の引数の組み合わせをいくつか選択肢化して、関数そのもの(の文字列)を保存するようにしたもの
  • 詳細にフォーマットしたければこのコード自体を編集すればどうとでもなる

ワークフローのイメージ

定義をいじる

コードを書く

ビルドする

実行する

再計算する

実行されてる

ふつう

GUI化

再ビルドしなくても
処理を変えられるようにする

つまり動的に
stateを持った
componentを作りたい

export default Vue.component('DomGenerator', {
  functional: true,
  props: {
    studioDom: {
      type: Object as PropType<StudioDom>,
      required: true
    },
    vm: {
      type: Object as PropType<VM>,
      required: false,
      default: null
    }
  },
  render(h, { props }): VNode {
    const defs = props.studioDom.defs
    const childProps =
      defs || !props.vm
        ? {
            ...props,
            vm: createVm(defs || [])
          }
        : props

    return h(getRenderer(props.studioDom), {
      props: childProps
    })
  }
})
export const createVm = (defs: StudioDef[]): VM => {
  const data = defs...
  const computed = defs...
  const methods = defs...
  
  // 略

  return new Vue({
    data: () => data,
    computed,
    methods
  })
}

各DOMのpropにVMを追加しちゃう

const dom = {
  type: 'component',
  defs: [
    {
      type: 'state',
      key: 'count',
      value: 5      
    },
    {
      type: 'getter',
      key: 'square',
      value: 'return count * count'
    },
  ]
}

GUIで定義をいじる

新しい定義からDOMを再生成

必要であればVMを作る

(stateやmethodが定義されているDOMでscopeを作る)

こういうコードと同等のことをする

export const getVNodeData = (
  studioDom: StudioDom,
  vm: VM,
): VNodeData => {
  const data = studioDom.data
  return {
    on: getEventHandlers(vm, data?.on),
    style: getConditionalStyle(data?.style)
  }
}

button要素のイベントにメソッドをアサインする(GUI)

DOM生成部分でvNodeDataのonにvmのメソッドを紐付ける

const dom = {
  tag: 'button',
  data: {
    on: {
      click: 'increment'
    }
  },
  render(h, { props }): VNode {
    const { studioDom, vm } = props
    const text = studioDom.content?.value
    return h(
      studioDom.tag || 'div',
      {
        ...getVNodeData(studioDom, vm, scopeRootId),
        domProps: {
          innerHTML: text ? compileTemplate(text, vm) : ''
        }
      }
    )
  }
<template>
  <div>
    <div>count: {{count}}</div>
    <button @click="increment">increment</button>
  </div>
</template>

<script lang="ts">
import Vue, { PropType } from 'vue'

export default Vue.extend({
  data(){
    return {
      count: 5
    }
  },
  methods:{
    increment(){
      this.count++;
    },

こういう

 よく
わかんない
ですよね

デモ

右パネルでの変更:

要素定義自体(初期値)を変える

 

ボタンをクリック:

methodを呼んでvmのstateをミューテーション

元々のSTUDIOはエディタで初期値を書き換えることしかできなかった

つまりなにができるようになるのか

たとえばアコーディオンメニュー

  • アコーディオンcomponentがisOpenedというstateを持つ
  • stateをミューテーションするtoggleメソッドを持つ
  • ヘッダのclickイベントにtoggleメソッドを紐付ける
  • on/off時のstyleを変数を使って変更

こういった制御を独自にやるのは大変なので、実質コードを書くのと同じアプローチにして、GUIはその入力装置にする

あとは

UIへの落とし込みをがんばる

何も考えなくても使えるのが
正しいんですよ!

CPO: keima

変数バインディング

Design with Real Data

  • モックではなく実データを注入してデザインする
  • JSONを要素にドラッグしてbindする
  • デザイナーとエンジニアに分かれていたワークフローを統一させることができる

CMSと連携する

3

非エンジニアユーザーがAPI接続設定するのは難しいので、まずはNoConfigでいけるようにSTUDIO用のCMSを作りました

CMS管理画面

一覧画面

コンテント

モデル

コンテント編集画面

モデル編集画面

記事を作って

そこから
デザインエディタ

CMSコンテントをドラッグで配置

記事一覧ページ

詳細ページ

データバインディング

というわけで

CMSでコンテンツを編集し、
デザインエディタには
stateとして注入する

stateに応じた表示制御するのが
STUDIO Code機能

そんな感じで作ってます

いつできるのか?

4月くらいには…

NoCodeでCMSと連携するデザインツールを作っている話

By Masaya Kazama

NoCodeでCMSと連携するデザインツールを作っている話

  • 4,303