NW.js + React.js + Material UI 簡單整合範例

前言

NW.js 提供了一用 Html 5 / Javascript 開發軟體的選擇, 雖然目前採用相關方法開發的程式 (例如: PhoneGap) 速度上以及程式大小上還無法跟原生軟體相比, 但是這個距離正在拉近中. 採用 Html 5 / Javascript 技術開發應用程式速度上的確比傳統應用程式快移植也快, 但是大大小小的問題讓這個開發方式有一條很長的路要走.

ReactJS 是 Facebook 發表的一套 Web UI 架構 Framework, 它的作用不是用來取代現有的 Framework, 而是提供一個架構讓 Web UI 元件化並提高元件的可再用性. ReactJS 內建的 JSX 語法讓 Javascript 與 Html 語法更緊密的結合在一起, 在某種程度上看起來有點像 Server-side Script (PHP/JSP/ASP) 跟 Html 碼交互呈現的感覺. 畢竟現在 Javascript 要產生 Html DOM 內容並不像 Server-side Script 這麼直覺. 所以採用 ReactJS 在某種程度上有助於簡化以及讓程式碼更易於維護.

Material-UI 是一套以 ReactJS 為底層實作的一系列仿 Google Material UI 風格的 Web UI 元件, 對於這套 UI 我還不是很了解.

本篇的目的是如何把這 ReactJS 以及 Material-UI 成功的運行在 NW.js 上面. 有關 Material-UI 以及 ReactJS 的用法就不在本篇的探討範圍中.

準備工作

請先下載 NW.js

與 Node.js 一樣, NW.js 需要 package.json 告訴它要從哪裡開始載入, 並採用那些函式庫. 以下是一個可以運行的範例:

{
    "name": "Tester",
    "main": "index.html",
    "scripts": {
        "less": "lessc css/main.less > css/main.css"
    },
    "dependencies": {
        "material-ui": "^0.7.3",
        "node-jsx": "^0.12.4",
        "react": "^0.13.1",
        "react-tap-event-plugin": "^0.1.6"
    }
}

範例一: package.js

接下來是 index.html 的內容:

<!DOCTYPE html>
<html>
    <head>
        <title>Tester</title>
        <link rel="stylesheet" type="text/css" href="css/main.css">
    </head>
    <body>
        <script>
        global.document= window.document
        global.navigator= window.navigator
        window.onload = function() {
            require('node-jsx').install({extension: '.js'});
            require('./app/main.js');
        }
        </script>
    </body>
</html>

範例二: index.html

接下來是 Material-UI 的 css 定義:

@import "node_modules/material-ui/src/less/scaffolding.less";
@import "node_modules/material-ui/src/less/components.less";

範例三: main.less

Material-UI 是使用 less, 所以必須要安裝 less 做 css 編譯工作 npm install less. 安裝完成之後可以執行 npm run-script less 編譯 css.

目前 ReactJS 主要還是運行在瀏覽器上, 跟 Node.js 還是並沒有 100% 相容, 所以這兩行程式碼主要是解決相容性問題以免 ReactJS 找不到 document 以及 navigator 物件

global.document= window.document
global.navigator= window.navigator

在 index.html 之中我採用了內嵌式的 Javascript <script>...</script> , 並在內部用 CommonJS 載入主程式. 而不是 <script type="text/jsx">...</script> 或是 <script src="app/main.js">...</script> , 是因為 NW.js 無法解析 <script type="text/jsx"> , 採用 <script src="app/main.js"> 的話 main.js 必須是採用正規 Javascript 的語法而不能用 JSX 語法.

ReactJS 原本是 Web 的 Framework, 所以直接在 NW.js 上使用 ReactJS 會有些問題. 所以我們改用 node-jsx 套件並提前載入 jsx 解譯器. {extension: '.js'} 則是告訴解譯器 JSX 副檔名為 .js

接下來是 main.js:

(function () {
    var React = require('react'),
        injectTapEventPlugin = require("react-tap-event-plugin"),
        Main = require('./main_ui.js');

    //Needed for React Developer Tools
    window.React = React;

    //Needed for onTouchTap
    //Can go away when react 1.0 release
    //Check this repo:
    //https://github.com/zilverline/react-tap-event-plugin
    injectTapEventPlugin();

    // Render the main app react component into the document body. 
    // For more details see: https://facebook.github.io/react/docs/top-level-api.html#react.render
    React.render(<Main />, document.body);
})();

範例四: app/main.js

大部分的程式碼在註解都有解釋了, 我還是稍微提一下. react-tap-event-plugin 是目前用來啟動 ReactJS 的Touch 事件支援, 也許以後就不需要了.

這樣基本的 ReactJS 架構就已經成形, 接下來就是程式碼的部分.

主程式

這個程式只用了一個標準扁平按鈕做測試, 以下是程式碼.

var React = require('react'),
    mui = require('material-ui'),
    FlatButton = mui.FlatButton;

var MainUi = React.createClass({
    render: function() {
        return (
            <FlatButton label="Primary" primary={true} />
        );
    }
});
module.exports = MainUi;

範例五: app/main_ui.js

2015/7/6 更新:

React.js 在 0.13.2 版之後似乎對於內部架構有所變動, 目前還沒有找到解決方案. 如果目前不想改的話只能暫時使用 0.13.1 之前的版本.

修改 package.json

{
        ...
        "node-jsx": "^0.12.4",
        "react": "0.13.1", // 把版本固定在 0.13.1
        "react-tap-event-plugin": "^0.1.6"
        ...
}

執行 npm update 更新 react.js.

我也發現這篇教學忘了把 css 部份加入所以畫面顯示會不正常, 順便補上.

留言

熱門文章