用 CirruScript 渲染 HTML

早的時候我嘗試過用 Cirru 語法直接生成 HTML
後邊也嘗試過用 Cirru 語法生成 JavaScript 的模板
效果勉勉強強, 主要是學習的做用, 後來有了 React 就乾脆不用了
不過將來加載靜態資源, 仍是須要有 HTML, 就以爲麻煩, 搞出點東西來css

stir-template

這個模塊通過幾回演變, 最終定型成爲 React 很類似的寫法
https://github.com/mvc-works/stir-template
代碼是用低版本的 CirruScript 寫的, API 也能在 CoffeeScript 裏調用html

stir = require :stir-tempate
html = stir.html
head = stir.head
body = stir.body
div = stir.createFactory :div

renderPage = (data) ->
  stir.render
    stir.doctype()
    html null,
      head null,
      body null,
        div name: 'a', 'empty'
        div()

能夠看到模仿了 React, 渲染函數的第一個參數是屬性, 後邊是子元素
也提供了類似的輔助函數 render, createElement, createFactory
這樣寫出來的風格, 跟 CoffeeScript 裏寫 React 組件也就差很少了
本身須要生成個標籤的話, 能夠嘗試這樣的語法:react

newTag = stir.createFactory 'new-tag'

另外 <!DOCTYPE html> 算是個特殊的標籤, React 當中不提供
那麼 stir-template 就方便配合 React 用在後者不方便的地方webpack

Cirru 的縮進

http://script.cirru.org/git

個人我的項目目前已經大量使用 CirruScript.. 算是刷排名吧
https://github.com/mvc-works/webpack-workflow
CirruScript 首先是編譯到 ES5 的代碼生成器, 其次才當作模板語言用
我以爲 CoffeeScript 裏逗號太多, 縮進有 bug, 不開心一直用
CirruScript 配合 stir-template 跟 React 能夠這樣用:github

var
  stir $ require :stir-template
  React $ require :react

var
  Page $ React.createFactory $ require :./src/page

var
  ({}~ html head title body meta script link div a span) stir

var
  line $ \ (text) (div ({} (:className :line)) text)

= module.exports $ \ (data)
  return $ stir.render
    stir.doctype
    html null
      head null
        title null ":Coffee Webpack Starter"
        meta $ object (:charset :utf-8)
        link $ object (:rel :icon)
          :href :http://tp4.sinaimg.cn/5592259015/180/5725970590/1
        link $ {} (:rel :stylesheet)
          :href $ cond data.dev :src/main.css data.style
        script $ object (:src data.vendor) (:defer true)
        script $ object (:src data.main) (:defer true)
      body null
        div ({} (:class :intro))
          div ({} (:class :title)) ":This is a demo of Webpack usage."
          line ":Open Console to see how it loads."
          div null
            span null ":Read more at "
            a
              {} (:href :http://github.com/teambition/coffee-webpack-starter)
              , :github.com/teambition/coffee-webpack-starter
            span null :.
        div ({} (:class :demo))
          React.renderToString (Page)

首先 HTML 的結構大概仍是能看到的, 接着就是語法了...web

  • 縮進編程

Cirru 首先不是靠不少語法發揮做用的語言, 而是靠的縮進
整個代碼會先被解析成一棵樹, 這棵樹纔是後邊執行的重點
至少我在寫代碼的時候, 時時刻刻腦補他的樹是怎樣的, 能夠看 Demo:
http://repo.cirru.org/parser/json

  • 美圓符號 $gulp

美圓符號是爲了解決一類縮進而引入的, 好比說下邊這樣的代碼:

(set a (f1 (f2 (f3 x))))

縮進之後想一想都以爲很累, 會是這樣的, 還不如用括號

set a
  f1
    f2
      f3 x

那麼我引入 $ 以後問題就輕鬆了, 直接就能夠這樣寫:

set a $ f1 $ f2 $ f3 x
  • 逗號 ,

而後逗號也是爲了解決一類狀況引入的, 意思大概和 $ 相反, 這樣的代碼

(set a (f1 a) (b) (f2))

改爲縮進的時候會是這樣的, 注意單行的 bf2 由於換行是有括號的:

set a
  f1 a
  b
  f2

那麼問題就來了, 有這樣的代碼怎麼表示, 這裏的 b 沒有括號了啊:

(set a (f1 a) b (f2))

因此我引入了 ,, 做用就是去掉一層縮進, 大概就是這樣:

(set a (f1 a) (, b) (f2))

而後再用縮進的寫法, 就不會解析出錯了:

set a
  f1 a
  , b
  f2

根據上邊 3 條規則, Cirru 語法的縮進能表示絕大部分編程需求
除了表達式第一個操做符裏狂用括號的... 放哪一個語言裏都沒正常的辦法

CirruScript 的操做符

CirruScript 的編譯器是經過識別表達式第一個操做符來轉換 AST 的
好比說 var return 會被識別成對應的表達式或者語句的 AST
另外的 div 這樣的, 沒有對應的操做符, 就會被處理爲函數調用

object 操做符, 用來生成對象, 它的參數都是鍵值對
它有個 alias 是{}, 我以爲看起來更習慣一些, 畢竟花括號仍是很眼熟的
array 操做符一樣的意思, 用來生成數組, 它的參數就是元素了
它有個 alias 是 []. 空數組可能會寫成 ([]) 表示爲表達式了

字面量還有標識符我作了一些處理, 方便寫代碼用
這裏邊的 null true 都是回自動識別的, 數字也作了處理
另外 data.main 這種, 也經過成員表達式的 AST 進行了處理

這裏邊還有些挺奇怪的好比說 {}~, 實際上是 object~
可是可是, 這種正確的名稱應該是: **解構賦值**, 只是奇怪了點
奇怪的語法仍是到 http://script.cirru.org 看吧, 能夠看具體 AST 是什麼

CirruScript 的字符串

字符串是個奇怪的事情, 由於 Cirru 是從圖形編輯器退化而來的..
退化嘛... 天然有的東西, 原來圖形很正常, 用文本表示就怪怪怪怪了的
Cirru 的語法裏 a"a", 帶不帶引號, 其實是同樣的
不同的是 "a1 a2"a1 a2, 沒有引號就是兩個節點, 有就是一個
因此... 引號其實是爲了特殊字符的轉義用的, 還有這種呢 "a1\" a2"
你在 <textarea> 裏打字的時候不用轉義, 圖形界面嘛, 那是正常的時候

而後爲了表示字符串, 我動起來歪腦筋, 對, 用冒號 :
冒號開頭的就是字符串了, 沒有特殊字符的時候還能夠少一個字符
:utf-8":utf-8" 表示的是一個意思, 編譯的結果也是同樣的
必須加引號的是 ":hello world" 這樣的有特殊字符的節點
看多了 Clojure 的話其實冒號你是會習慣的...

總結

最新版的 Gulp 應該是能識別 gulpfile.cirru 這樣的後綴的
我也寫了插件, 應該問題不大, CoffeeScript 這麼難用都用下來了
https://github.com/Cirru/gulp-cirru-script

通常我會寫個 template.cirru 文件, 從 Gulp 裏引用
最後執行一下函數, 就能從數據渲染出 HTML 來了:

require('cirru-script/lib/register')

gulp.task 'html', (cb) ->
  html = require'./template.cirru' # <-- 引用看這裏
  fs = require 'fs'

  if not env.dev
    assets = require './build/assets.json'
    env.main = "./build/#{assets.main}"
    env.vendor = "./build/#{assets.vendor}"
  fs.writeFile 'index.html', (html env), cb # <-- 調用看這裏

但願你有興趣用 CirruScript 生成 HTML. 早日淘汰手寫 HTML.

相關文章
相關標籤/搜索