【記錄】node supervisor 跑 babel-node 發生的問題

目前可以在網路上找到的問題在 stackoverflow 的這篇

如果使用 supervisor -exec babel-node app.js 的話,修改檔案後會出現 listen EADDRINUSE 的錯誤

nodemon 的話不會有這個問題
不過因為我用在 docker 上一直沒辦法 reload 的關係,所以我還是繼續用 supervisor...XD
目前想到比較好的解決方案,還是用 babel/register 就好

require('babel/register');
require('./app.js');

個人覺得要開個新檔不是很漂亮的做法...自己的 options 也是設在 .babelrc
所以直接用 node -r 'babel/register' app.js 解決,使用 supervisor 的話長這樣:

supervisor -- -r 'babel/register' app.js

【分享】jsonschema 應用於 RESTful API 開發

JSON Schema 可以定義一套規則來驗證 JSON 格式,目前是 draft v4,個人覺得在 RESTful API 開發上非常方便,除了不需要再寫噁心的欄位判斷以外(有時候欄位判斷邏輯甚至會很複雜),定義好的 schema 也可以直接拿來用在 document 上再做點修改。

以下是以 node.js + koa + jsonschema 的例子,使用的是 jsonschema 這套 validator 實作

先來寫一個簡易的 koa middleware

var Validator = require('jsonschema').Validator;
var v = new Validator();

module.exports = function schema(schemaObj) {
  return function *(next) {
    // 當 query 出現 schema-help 時, 回應 schemaObj 給 client 參考

    if (this.request.query.schema-help !== undefined) {
      this.body = schemaObj;
      return;
    }
  
    var result = v.validate(this.request.body, schemaObj);
    // 當 schema 不匹配時, 會產生錯誤訊息在 result.errors

    if (result.errors.length) {
      console.log('schema-errors:', result.errors);
      this.body = {
        message: 'schema not match',
        errors: result.errors
      };
      return;
    }
    yield next;
  };
}

然後 route 就可以像這樣寫

var Koa = require('koa');
var body = require('koa-body');
var Router = require('koa-router');
var schema = require('./middlewares/schema');

var app = new Koa();
var router = new Router();

// 新增文章

router.post('/article', schema({
  type: 'object',
  properties: {
    title: { type: 'string', maxLength: 100 },
    content: { type: 'string' },
    tags: {
      type: 'array',
      items: { type: 'string', maxLength: 20 }
    },
    public: { type: 'boolean' }
  },
  required: [ 'title', 'content', 'tags' ],
  additionalProperties: false
}), function *() {
  // API logic... 

});

app.use(body());
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000);

這個是簡易的新增文章例子,有時候我們甚至需要做更複雜的欄位判斷,試想不用 validator 做這些驗證會花多少精神...

最完整的 jsonschema 用法可以參考 official document。(比較重要的部分在第五個章節)

例舉幾個自己常用的

  1. min*, max*: number, string, array, object 的限制 (5.1 ~ 5.4)
  2. pattern, enum: regex 和 enum
  3. required: 在 object properties 中的必填欄位
  4. additionalProperties: 表示在 object properties 中是否允許增加未知欄位, 預設為 true
  5. dependencies: 可以在欄位間建立相依關係,例如讓兩個非必填欄位如果有填的話必須兩個都存在,像是 latitude, longitude
  6. anyOf, allOf, oneOf, not: 參考這裡會更清楚

draft v5

v5-Proposals

jsonschema + is.js ?

is.js 是一個很棒的 check library,提供了不少方法在一般情況下不需要再寫 regex 做判斷,於是我把它帶到 jsonschema 來用,可以參考這個套件: jsonschema-is-js-plugin

目前主要是針對這套 validator 實作,也是例子中所使用的。

【教學】使用 LiveScript 寫 ReactJS/Native 應用

LiveScript 是我很喜歡的 "compile to JavaScript" 語言,其簡潔程度可以讓我省去很多時間成本。

目前它沒有像 JSX 的 transformer,在寫 React 的時候可能只能用原生的方式來寫,但感覺起來不會像原本的 JS 寫法難維護。

使用 React.DOM 的方式,或者是 createFactory 來生成元素的 factory

require! react: React

table = React.DOM.table
# or
table = React.create-factory \table

tr = React.create-factory \tr
td = React.create-factory \td

page = React.create-class do
  render: ->
    table null,
      tr null,
        td null, \1
        td null, \2
      tr null
        td null, \3
        td null, \4

自己不是很喜歡 xml,連寫 html 都是用 jade,所以這樣對我來說剛好。
(雖然很多 null 會有點煩,不過在 attr 多的時候不會常見到,或是可以用 {} 代替)

如果覺得 xml 比較好區分邏輯和 view,也是可以用用看 coffee 的 transform
不過有個問題是在標籤如果以 backslash(\) 開頭作為字串的話,也會被 parse 掉。(以單雙引號來說不會,所以其實不算大問題)

str = \<div></div>

# cjsx-transform result
str = \React.createElement("div", null)

拿來寫 React Native 也是爽度很高的一件事,你可以用 React.createFactory 帶入 component 來生成 factory
直接把官方的 Tutorial 範例改用 livescript 來寫

'use strict'

require! \react-native : React

{
  AppRegistry
  Image
  ListView
  StyleSheet
  Text
  View
} = React

image = React.create-factory Image
listview = React.create-factory ListView
view = React.create-factory View
text = React.create-factory Text

API_KEY = \7waqfqbprs7pajbz28mqf6vz
API_URL = \http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json
PAGE_SIZE = 25
PARAMS = "?apikey=#{API_KEY}&page_limit=#{PAGE_SIZE}"
REQUEST_URL = API_URL + PARAMS

AwesomeProject = React.create-class do
  getInitialState: ->
    dataSource: new ListView.DataSource do
      rowHasChanged: (row1, row2) -> row1 is not row2
    loaded: false

  componentDidMount: ->
    @fetchData!

  fetchData: ->
    fetch REQUEST_URL
      .then (response) -> response.json!
      .then (responseData) ~>
        @setState do
          dataSource: @state.dataSource.cloneWithRows responseData.movies
          loaded: true
      .done!

  render: ->
    return @renderLoadingView! if not @state.loaded

    listview do
      dataSource: @state.dataSource
      renderRow: @renderMovie
      style: styles.listView

  renderLoadingView: ->
    view do
      style: styles.container
      text null, 'Loading movies...'

  renderMovie: (movie) ->
    view do
      style: styles.container
      image do
        source: { uri: movie.posters.thumbnail }
        style: styles.thumbnail
      view do
        style: styles.rightContainer
        text do
          style: styles.title
          movie.title
        text do
          style: styles.year
          movie.year

styles = StyleSheet.create do
  container:
    flex: 1
    flexDirection: \row
    justifyContent: \center
    alignItems: \center
    backgroundColor: \#F5FCFF
  rightContainer:
    flex: 1
  title:
    fontSize: 20
    marginBottom: 8
    textAlign: \center
  year:
    textAlign: \center
  thumbnail:
    width: 53
    height: 81
  listView:
    paddingTop: 20
    backgroundColor: \#F5FCFF

AppRegistry.registerComponent \AwesomeProject, -> AwesomeProject

階層很分明,尤其是在 livescript 中 do 保留字真的非常好用。

【會後心得】Modern Web Conference 2015

參與 conf 已經漸漸成為一種習慣,無非是求知慾作祟,另一方面則是提升熱情,認識更多同好。
(希望很久沒寫的 blog 一篇起頭,以後可以養成寫文章的習慣...XD)

這次的 Modern Web Conference 是由 WebConf 與 ithome 共同主辦的,同時也邀請到了多位國內外的大師前來分享。


(我是來學習的沒錯,不過這不是 conference 嗎?XD)

Conf 沒有直接提供 IRC channel 真的很可惜,雖然社群中的大大們也因為這樣開了 IRC 和 gitter 的聊天室,不過我是第二天才知道的。(第一天之前我幾乎忙到沒時間看 facebook...)

再來除了攝影師會瘋狂打閃光這個行為,還有網路不是很穩之外,其他的點我都覺得 ithome 還算辦得不錯。(網站的部分就別提了)


最近自己的睡眠很不正常,加上當天還在做公司的事情,所以整個會議的內容不是很好吸收,沒在動鍵盤的時候還會擋不下瞌睡蟲...

所幸有大大們在 Hackpad 熱血共筆,我可以拿來回憶當下所見,或是看看其他場次的內容。

第一日(5/15)

[R0+R1+R2] JavaScript at 20 Years

Slide link

JavaScript 在二十年前誕生,一直到近幾年,隨著 web 技術邏輯越來越複雜,JS 才開始越來越受到重視,同時 Node.js 的出現,讓它走出瀏覽器,從後端、工具,甚至是寫桌面應用程式(nw.js, electron...)。

現在,地表上大概沒有什麼可以阻止 JavaScript 的發展了...

這次 JavaScript 的老爸 - Brendan Eich 受到邀請前來分享,講的主要是 JavaScript 的發展,從起源一直講到 ES6、asm.js。

一直在 JavaScript 誕生之前,Java 還是主要在 Web 前端的語言(Applet?)。Brendan Eich 在十天內創造它,其實拿了很多 Java 的語法特徵,尤其是 bytecode 受到 Java 影響深遠。

ECMAScript6 也即將在 6 月發佈正式標準,在這之前其實各種技術已經開始支援 ES6,像是 io.js 一部分的支援(我現在用 generator 用得很愉快XD),或者是 babel 可以把 es6 的程式碼轉換成 es5 的形式。

[R1] 聽說 KKTIX 現在都是用 Go 寫的

Slide link

標題在騙(XD),其實只有部分是使用 Go,大多都還是 Rails。

Go 很吸引我的地方
  1. 在 deploy 方面很方便,因為 dependency 低,binary 檔容易散佈
  2. 資源用量低,啟動速度快
  3. 雖然是靜態語言,但寫起來很有動態語言的感覺,像是有 closure
  4. 語法簡潔。執行效率快,開發效率高
  5. 用 Goroutine 爽度很高

Go 很適合在需要提升效能的部分來使用,但又不會像一般靜態語言(ex: C++)這樣難使用,而且 dependency 低,踩到的雷自然就少。

公司現在也有一部份的服務是用 Go 實作的,其餘大部份是使用 Node.js,所以我對 Go 很有興趣,已經開始在學習。

[R0+R1+R2] 開源之道,Open Source Enlightenment

Slide link

我對這份 slide 的印象十分深刻,不過已經忘記是什麼時候看到的了,也許它曾經就是我入坑的關鍵鑰匙之一。

“我們參與開源社群,就像是在一條道路上並肩而行:這不僅讓我們成為更好的創作者,也讓我們通過與人合作,而成為更好的人。”

“獲得正確答案的方式,不是問問題。是講一個錯的答案。”

“萬事萬物都有缺口,缺口就是光的入口。”

“取暖、小圈圈、自 high 也沒什麼不好,先形成 working group,才有機會成事。”

“「劣即是夯」不要害怕丟臉,會越來越好。”

[R1] Webpack pack your web.

Slide link

Webpack 算是一個頗年輕的 CommonJS/AMD modules 打包工具,除了它之外,還有一個 CommonJS 打包工具叫做 Browserify,在更之前呢?應該是 require.js 了,AMD 標準就是從它發展。

Webpack 的特色就是不只包 JS,連 css, font, image, html 都可以包。講者提了一個常見的案例,就是在前端引入 script 時會有引入順序的問題。Webpack 可以讓你集中管理前端的套件,同時將打包好的 js 檔案作遷移也是非常方便。Webpack 也支援使用 webpack-dev-server 來以 live reload 的方式開發。

同時講者也提到了 AMD 本身可以不需打包的優勢,不過碰到了 ES6 仍然沒輒(現在瀏覽器都不太支援,你可能需要一個 babel-loader)。

兩個月前,我寫了一個 isomorphic-react-flux-boilerplate 其中 client 就是使用 webpack 打包的。不過一直沒有時間好好更新它...

第二日(5/16)

[R0] 從 React Native 看 "Learn once write anywhere" 帶來的開發典範轉移

Slide link

React Native 是我這幾個月最關注的開源專案之一,可以使用 React.js 的方式來撰寫 Native Mobile app,除了 Component 不是 html 之外,其他基本上大同小異。我也準備拿來開發一些應用,亦或是把之前寫的應用來做移轉,而事實上我卻根本沒有寫過 iOS app。

這個講題大致的內容我算是聽了第三遍(XD),第一次是去年 JSDC 的錄影(當初只有 react.js 的部分),第二次則是在第五次的 ReactJS.tw 小聚。

最印象深刻的是在架構策略的部分,從 Java Swing 一直到 Adobe Flash/Air,以及現在的 HTML5 app 都是跨平台的 solution,結論基本上都是用戶體驗不佳、效能不佳、評價不佳。

Learn once write anywhere 可以說是現在的趨勢,以 React Native 來說,在未來你可以使用 JS 來寫任何平台的程式(目前只有 iOS),並且讓用戶得到 Native 的體驗、效能,並給予 Native 的評價!


React Native 目前對我來說最大的吸引力是在它支援的開發模式非常貼近 Web 開發,在 Debugging 方面,你可以使用 live reload 的方式來開發 ReactNative,也可以使用官方提供的 devtools extension 在瀏覽器上 debug ReactNative app。

我曾經是 Android app 的開發者,算是已經能獨立開發應用(除了 NDK 我只有曾經 build 過 ilbc Codec 的經驗XD),我之後轉向擁抱 Web 開發,其實原因很單純,一為討厭 Java,二則是我希望的是一個能夠快速編譯(或是沒有編譯)、快速開發的環境,一般 Native Mobile app 都是經過編譯、打包,然後才會傳輸到裝置(或 VM)進行安裝、開啟,而我個人很受不了這點時間的浪費。

React Native 除了 Native Component 之外,你無須重新做這些事情,第一次 build 完成之後,之後一切都是 JS 程式碼的動態 render 行為,你改好程式只需要 CMD+R 即可秀出結果,或者是立刻給你看(Live Reload)。

React Native 算是我目前看到 facebook 一路走來對於 mobile app development for web technologies 最優的 solution 之一,從 facebook 應用曾經使用 HTML5 webapp 方式開發,因為效能上的失敗轉移到 Native 應用的開發方式看來是這個樣子。現在看起來 React Native 大概可以解決多半的 Native 應用開發需求。

小結

還有很多個頗有心得的講題沒寫上,日後有空再來補充(或許就遺忘了Orz)