Meteor全棧開發平臺 - 不單單是前端

全棧開發平臺 - 不只僅是前端

Meteor和那些名聲如雷貫耳的前端框架,好比Angular, React等都不同,它是一個 採用單一開發語言的全棧開發的平臺:開發者可使用JavaScript同時 進行前端和後端的開發,而後交給Meteor運行這個包含了先後端的完整應用:css

739368-20150907092604184-1035868592.jpg

從圖中你能夠看到,Meteo在前端使用瀏覽器做爲基礎運行環境,在後端則是以NodeJS做爲 基礎運行環境,以MongoDB做爲數據持久化系統。html

Meteor提供了一個橫跨前端和後端的中間層平臺,預置封裝了不少功能庫,簡化了 Web應用的開發:使用單一語言快速開發Web應用,這是Meteor的最重要訴求。前端

初識Meteor

從構成來說,能夠認爲Meteor開發平臺由兩部分構成:web

Meteor庫 - 以功能包的形式存在,封裝了諸如實時通訊、反應式編程之類的核心功能。當 一個Meteor應用啓動時,Meteor會自動加載這些庫,爲應用提供了一個基礎環境。數據庫

Meteor工具 - 能夠理解爲命令行方式的開發環境,它使咱們能夠輕鬆地管理整個應用 開發流程:從建立應用、調試應用、自動化測試到打包、部署、熱升級。編程

如今,讓咱們讓咱們使用Meteor命令行工具meteor建立並啓動第一個Meteor應用吧。後端

≡ 建立應用 —— meteor create [project]

在終端中輸入meteor create test,而後按回車:瀏覽器

~$ meteor create test↵

這個命令將在當前目錄下建立一個子文件夾test,Meteor將使用內置的應用模板 做爲這個文件夾的內容。咱們能夠進入test文件夾,執行ls命令查看一下內容:前端框架

~$ cd test↵
~/test$ ls -al↵

你能夠看到Meteor建立了3個文件和1個目錄。服務器

test.css - 前端的樣式表文件
test.html -前端的HTML文件
test.js - 前端/後端共用的JavaScript文件。全棧,對吧O(∩_∩)O~
.meteor - 這個子目錄是Meteor應用必須的特殊子目錄,由Meteor平臺維護,咱們不要動
先略過3個文件的具體內容,咱們運行起來看看。

≡ 運行應用 —— meteor run

執行meteor命令啓動應用,在終端中輸入meteor,這等價於運行meteor run:

~/test$ meteor↵

當你看到終端中出現下面的提示信息:

...
App running at: http://localhost:3000/

恭喜!咱們的第一個Meteor應用已經運行起來了!

≡ 中止應用運行 —— Ctrl+C

用鼠標左鍵點擊一下終端區域,確保它得到鍵盤輸入焦點(你應該能夠看到一個 閃爍的光標),而後同時按Ctrl鍵和C鍵,便可中止應用運行:

^C
~/test$

≡ 復位應用數據 —— meteor reset

Meteor應用運行時會生成打包文件、建立應用數據庫。可使用下面命令 清理這些生成的文件和應用數據:

~/test$ meteor rest↵

meteor reset命令不影響你的源代碼文件。

模板文件 - test.html

打開test.html,你可能會略有不適:

739368-20150907093250997-1841577833.jpg

它不是一個標準的HTML文件:沒有html頂層標籤,奇怪的符號{{> hello}}... 不過,在Metoer中這樣的文件倒是合法的文件 —— 模板文件。

≡ 模板頂層標籤 —— head/body/template

Meteor規定,在一個模板文件裏,只能出現三種頂層標籤:head、body和template。 也就是說,模板文件只能包含以這三種標籤爲頂層標籤的HTML片斷。

這是由於,Meteor在運行應用以前有一個打包/bundle的過程,此時Meteor會提取全部 模板文件(一個應用中能夠有多個模板文件)中的head、body和template片斷,分別進行 合併、編譯後才呈現給用戶:

739368-20150907093354481-1117564188.jpg

上圖中,a.html和b.html中的head片斷合併後做爲最終的head內容,b.html和c.html中 的body片斷合併後做爲最終的body內容,至於c.html中的template的內容,則最終替換了 b.html中的{{> hello}}。

≡ 模板語言 —— Spacebars

Meteor的模板使用的語言是私有的spacebars語言,它基於流行的handlebars,經過 在HTML片斷中嵌入模板標籤(以兩對大括號爲邊界)實現模板化。所以,Meteor的模板 其實就是HTML標籤和模板標籤的混合體。

{{> hello}}模板標籤用來調用一個子模板,Meteor將在最終呈現給用戶的HTML文檔中, 使用子模板hello的內容進行原地替換。

特殊的template標籤用來定義一個子模板。

{{counter}}模板標籤執行插值工做,Meteror將在最終呈現給用戶的HTML文檔中,使用 標識符counter對應的值進行原地替換。

樣式文件 - test.css

和模板文件相似,Meteor在打包過程當中,會將全部的樣式文件合併成一個大的樣式文件, 而後在呈現給用戶的HTML文檔中引用這個樣式文件:
739368-20150907093807059-834165956.jpg

上圖中,a.css和b.css的內容將被合併爲一個文件,並在最終呈現給用戶的HTML文檔中, 使用link標籤引用這個文件。

代碼文件 - test.js

test.js是最有趣的文件,Meteor將在前端和後端同時運行這個文件。能夠這樣理解:

前端 - Meteor將在最終呈現給用戶的HTML文檔中使用script標籤引用test.js
後端 - Meteor將經過NodeJS讀入並運行test.js
毫無疑問,若是不作任何處理,誰也無法保證一段JS代碼既能夠在前端瀏覽器環境中運行, 也能夠在後端NodeJS中運行。在test.js中,咱們須要判斷當前的具體運行環境,以便 執行相應的代碼。

≡ 判斷代碼執行環境 —— Meteor.isClient/Meteor.isServer

讓同一個js文件便可以跑在前端,也能夠跑在後端(好比NodeJS),已經有不少 應用了,只須要判斷下在某個特定環境才存在的變量就能夠了(好比,NodeJS有global,而 瀏覽器有window)。Meteor提供了一組更加清晰的API來實現這個判斷:

Meteor.isClient - 爲真時,表示當前運行環境爲前端
Meteor.isServer - 爲真時,表示當前運行環境爲後端
你能夠看到,在test.js中也是這麼作的:

//test.js
if(Meteor.isClient){
  //僅在前端執行的代碼塊
}
if(Meteor.isServer){
  //僅在後端執行的代碼塊
}

≡ 先後端都執行的代碼

很顯然,若是在test.js中,不判斷執行環境的代碼將同時在前端和後端運行。好比:

//test.js
console.log("Hello,Meteor!");
if(Meteor.isClient){...}
if(Meteor.isServer){...}

運行應用後,你將在後臺的終端中看到Hello,Meteor!,也將在前臺的調試臺 中看到相同的輸出。

前端代碼 - 模板實例對象

回憶下,在模板文件test.html中,咱們定義了一個模板:

<!--test.html-->
<template name="hello">
  <button>Click Me</button>
  <p>You've pressed the button {{counter}} times.</p> 
</template>

當Meteor運行這個應用時,將自動建立一個對應的模板實例對象:Template.hello。 對模板的數據綁定和事件綁定,這些一般須要使用JavaScript實現的功能,就經過這 個對象來實現:

739368-20150907094431606-1884270806.jpg

在hello模板中,{{counter}}模板標籤中的標識符couter的值,將由對應模板實例 對象的counter函數返回值決定,這個函數被稱爲模板的helper函數,使用模板實例的 helpers()方法聲明模板標籤中標識符對應的helper函數。

而經過模板實例對象的events方法,則爲模板中的button元素掛接了click事件監聽處理 函數。

前端代碼 - 模板標籤標識符解析/helper

使用Template.hello.helpers(helpers)方法聲明hello模板中模板標籤標識符的解析函數。參數helpers是一個JS對象,屬性表示應用在模板標籤中的標識符,值 一般是一個函數,被稱爲helper,大體是幫助Meteor解析模板中的標識符的值 這樣的意思。

好比,在test.js中咱們爲hello模板中出如今{{counter}}模板標籤中的counter表達 式聲明其對應的helper函數:

//test.js
Template.hello.helpers({
  'counter':function(){
    return Session.get('counter');
  }
});

每次當Meteor須要對模板標籤{{counter}}進行計算時,都將調用其counter標識符 對應的helper函數進行計算:它簡單地返回Session變量counter的當前值。

≡ 爲helper函數設定參數

helper函數能夠接受參數,好比對於模板test中的displayName標識符:

<template name="test">
  <h1>Hello,{{displayName "Jason" "Mr."}}!</h1>
</template>

聲明以下的helper函數:

Template.test.helpers({
  'displayName' : function(name,title){
    return title + ' ' + name;
  }
});

那麼Meteor渲染後將得到以下的HTML結果:

<h1>Hello,Mr. Jason!</h1>

≡ 使用常量helper

固然,也能夠將helper定義爲一個常量:

Template.test.helpers({
  displayName : "Mr. WHOAMI"
})

這時,模板標籤{{displayName}}將永遠地被設定爲固定的值了。

後端代碼

在test.js中,後端代碼幾乎是空的,除了使用Meteor.startup(func)聲明 了一個空的初始化函數。

Meteor.startup(func)方法在前端和後端都是可用的。參數func指定了 一個初始化函數,當平臺就緒時,將調用這個初始化函數。

當在前端調用這個函數時,平臺的就緒意味着DOM已經就緒,這時你能夠進行DOM操做了:

//client side
Meteor.startup(function(){
  //jQuery對象在Meteor前端老是可用的
  $("<h1>Hello,world</h1>").appendTo("body");
});

當在後端調用這個函數時,平臺的就緒意味着Meteor平臺的服務進程已經正常啓動,能夠 進行應用層級的初始化工做了,好比,爲空的後端數據集填充一些數據:

//server side
Meteor.startup(function(){
  var persons = new Mongo.Collection("persons");
  if(persons.find().count() === 0){
    persons.insert({...});
  }
});

應用目錄結構

一個Meteor應用由目錄下的前端文件(HTML、CSS、腳本、資源文件等)和後端文件組成。 因爲Meteor存在一個打包/bundle的階段,所以,Meteor對應用的目錄結構進行了約定, 以便其打包過程可以順利完成。

默認狀況下,Meteor會搜索應用目錄(包括子目錄)中的全部JavaScript文件,打包後分別 送往前端和後端運行,文件和子目錄的名稱會影響打包結果。Meteor對如下的子目錄將特別處理:

≡ client —— 參與打包的前端代碼文件夾

任何名稱爲client的目錄,其文件都不會被送日後端運行。這相似於使用if(Meter.isClient){...} 進行前端代碼隔離的效果。

在生產模式下,client目錄裏的文件將被自動合併、壓縮,但在開發模式下,JavaScript 文件和CSS文件並不進行壓縮處理(CSS仍是會合並,但JavaScript文件不進行合併處理),以便於 開發過程當中的調試和錯誤定位。

Meteor會搜索目錄中全部的模板文件中的三個頂層元素:head, body, template,其中全部 的head段會合並,body段和template段的聲明都將轉換爲模板操做的JavaScript代碼。

≡ server —— 參與打包的後端代碼文件夾

任何名稱爲server的目錄,其文件都不會送往前端運行。這相似於使用if(Meteor.isServer){...} 進行後端代碼隔離的效果,但不一樣的是,server目錄內的部分代碼不會發送到前端,所以一些敏感的 代碼(好比身份驗證等)應當放在這個目錄。

Meteor會收集除了client, public和private子目錄以外的全部JS文件,而後交給後端NodeJS 運行。後端的JavaScript代碼對每一個請求將使用一個單獨的線程來處理,這不一樣於一般NodeJS的異步 代碼模式,由於Meter認爲這種模式更適合Meteor應用場景。

≡ public —— 不參與打包的前端資源文件夾

應用根目錄下public子目錄中的文件僅用於前端,這些文件不會被打包,可視爲http訪問的虛擬根目錄。 例如,public目錄下的logo.jpg文件,能夠經過url:"/log.jpg"來訪問。這個目錄能夠用來放置favicon.ico, robots.txt,或者一些靜態的HTM文件。

≡ client/compatibility —— 不參與打包的前端兼容庫目錄

有些前端JavaScript庫依賴於使用var定義的全局變量。爲了兼容這些庫,這個目錄裏的文件在被送 往前端時,不會被嵌套在一個做用域中,而且會在其餘前端JavaScript文件以前先執行。

≡ tests —— 僅用於測試的文件夾

任何名爲test的目錄內的文件僅用於測試,前端和後端都不會使用。

內容小結

讓咱們簡單回顧這個示例Meteor應用的開發過程(僞裝沒有使用meteor工具):

建立模板文件test.html,定義文檔結構
建立樣式文件test.css,定義文檔樣式
編寫前端腳本test.js,實現模板、數據、事件的綁定
在這個示例中,咱們基本不須要編寫後端腳本
這些就緒後,扔給Meteor運行就能夠了。

這有點像Apache+PHP或者IIS+ASP這些東西,Meteor提供一個基本的運行環境,你往 裏面扔一個模板,立馬就能夠看到效果,你編寫一段後端腳本,立馬加強了服務器的 能力。那麼,Meteor和它們的區別在哪裏呢?

≡ 橫跨先後端的中間層平臺

在前面的課程中,咱們看到,前端和後端同時都有一個Meteor對象做爲API入口(固然, 前端的Meteor對象和後端的Meteor對象不是徹底相同的實現),可使用Meteor.isClient或 Meteor.isServer判斷代碼運行環境,可使用一樣的Meteor.startup()方法分別在 前端和後端注入初始化代碼。這意味着什麼?

讓我把最開始的那張示意圖中的Meteor層再細化一下:

739368-20150907094957731-1209143891.jpg

很顯然,Meteor最不同凡響的是,使用同一套代碼,同時在前端和後端提供了應用運行的 基礎環境。不得不提的是,Meteor平臺在前端基礎環境和後端基礎環境之間,甚至已經基於 websocket創建了一個雙向實時的通道!

個人網站上有對應的實例練習,你們能夠去實戰下。

相關文章
相關標籤/搜索