當前位置:
首頁 > 最新 > 隨遇而安的DAPP開發實踐教程(二)使用HTML作為DAPP前端

隨遇而安的DAPP開發實踐教程(二)使用HTML作為DAPP前端

1、一個帶有用戶界面的案例

在上一篇教程《隨遇而安的DAPP開發實踐教程(一)搭建一個可用的開發環境》當中,我們基於Truffle官方提供的MetaCoin例子進行了初步的開發實踐和代碼剖析。我們甚至已經可以基於JavaScript編寫合約的測試代碼並檢查結果,看起來一切順利?

不過值得注意的是,我們是使用「truffle.cmd test」來執行.js文件中的代碼的,如果直接使用NodeJS或者瀏覽器打開,我們馬上就會收到成山的錯誤提示。顯然,這是因為JS程序代碼中缺少Truffle相關的導入庫文件,導致大量方法無法找到出處所致。

很顯然,作為一個完整的可向公眾發布的DAPP,我們希望它能夠在瀏覽器中結合前端界面的代碼,再伺機調用後端的智能合約介面,與私有或者公開的區塊鏈體系對接。僅僅是測試用的代碼完全無法滿足這樣的要求。

Truffle滿足了我們對於前端用戶界面的迫切需求,同樣是通過它自帶的例子WebPack。我們只需要仿照之前下載MetaCoin的方式,在控制台中輸入:

# mkdir WebPack

# cd WebPack

# truffle.cmd unbox webpack

這次等待的時間會更長一些,事實上,這是因為前端代碼與Truffle合約的通訊需要大量依賴庫所致。下載後的目錄中多了不少新的文件,它們與合約的編寫和發布並沒有直接關係。這裡的node_modules子目錄保存了所有需要用到的第三方依賴庫,包括提供了最新的JS語言特性的Babel,代碼檢查工具ESLint,以及最重要的以太坊專用的通訊介面Web3。而app子目錄中保存了網頁端的界面代碼,CSS樣式和JS腳本。工程根目錄新增的package.json文件主要被NodeJS和npm用來查找和更新依賴庫,以及查找必需模塊。

之後的工作和前文所述並無區別,開啟Ganache測試鏈之後,還是依次compile和migrate,即在WebPack目錄下,通過控制台依次執行:

# truffle.cmd compile

# truffle.cmd migrate

事實上WebPack工程所涉及的合約代碼和MetaCoin沒有任何區別,它只是演示了如何給這個非常原始的代幣合約案例增加一個圖形化的前端而已。不過這也正好讓我們有時間去更詳細地研究智能合約發布和使用的流程,反省並準備開始從頭編寫自己的DAPP程序。

現在,我們依然可以通過truffle.cmd test來進行快速的合約函數測試,不過我們已經不滿足於此了,我們需要的是在瀏覽器端看到自己的成果。不過單純雙擊app/index.html並不會有什麼效果:Chrome等瀏覽器對於本地運行的JS腳本有各種安全性的限制,例如無法讀取外部JSON腳本,Truffle相關的代碼可能因而無法正常執行;此外我們也要考慮載入NodeJS的諸多模塊。

我們首先要確認前端代碼中設置了正確的私有鏈地址和埠,從前文中我們已經知道,Ganache默認的地址為127.0.0.1:7545,打開app/javascripts/app.js,找到設置地址和埠的代碼段,並修改為正確的數值如圖:

此時我們也可以順便看一看app.js中的其它代碼段落,了解其中對於智能合約函數sendCoin()和getBalance()的調用方法。簡單來說,和上一個教程中的測試JS代碼幾乎沒有什麼不同,這對於正摩拳擦掌準備自己編寫前端代碼的我們來說無疑是一個好消息。

保存退出後,一切看起來還是沒有什麼頭緒,幸好我們有強大的npm。在控制台輸入:

# npm run dev

此時會啟動開發者模式,自動建立一個本地的伺服器端並調用index.html顯示前端界面。

根據控制台輸出的提示,在瀏覽器(筆者所用的是Chrome)中輸入http://localhost:8080,看看發生了什麼?

太神奇了,現在從Ganache的用戶列表中隨便選擇一個地址,在網頁上粘貼用戶地址之後,再把當前持有的一部分代幣分享給他看看。

在Ganache的交易記錄中可以找到這筆最新發生的交易,並且我們可以從TX DATA中找到剛才輸入的用戶地址,以及發送的數額(1000的十六進位為3e8)。

不過帶著如此龐大的依賴庫終究是巨大的累贅,其中大部分API與當前工程並沒有直接關聯,甚至還包含了一些對本工程完全無用的案例和文檔代碼;而且我們在構建自己的網路應用的時候,也絕對不希望用npm來啟動服務。不過我們還有另一個指令可以執行,按Ctrl+C退出目前的服務,在控制台中繼續輸入:

# npm run build

完成後進入build子目錄,我們可以發現新生成的index.html和app.js文件,後者的尺寸相比之前顯得相當可觀(從4KB到1.34MB),顯然是把多個依賴庫打包合併之後的結果。

很讓人興奮對不對,現在我們將build目錄的文件(本工程中只有HTML和JS文件,不需要包含編譯合約時生成的contracts子目錄)拷貝到新的位置,並且啟用任何Web伺服器構建工具(最簡單的方法是在新位置下執行python.exe -m SimpleHTTPServer,如果已經安裝了Python的話):

沒錯,因為Ganache還在運行,私有鏈依然存在,所以當前用戶(默認總是用戶)所持有的MetaCoin代幣還是9000個,嘗試給另一個用戶發送代幣之後:

一切順利!並且如果現在直接雙擊HTML文件在瀏覽器中打開的話,也可以看到正確的調用結果。這意味著我們未來有更多的方法去調用後端合約代碼,例如通過libcef(即Chromium Embedded Framework,地址為https://bitbucket.org/chromiumembedded/cef)這樣的嵌入式開發庫,在C/C++或者Unity遊戲引擎中直接調用這裡的JS代碼(當然這並不是一個很優雅的方案,不過對於初學者來說足夠直接)。也許我們在後面的系列教程中會進行這樣的嘗試。

2、合約的發布腳本和流程

現在我們來關注一個之前被忽略的問題:「truffle.cmd migrate」這個命令到底做了什麼?

顧名思義,migrate的過程也就是把已經編譯完成的智能合約「移植」(或者更準確的說,就是發布)到區塊鏈上的過程。這個過程同樣需要通過相對簡單的JavaScript來進行控制。

發布的過程可以被人為劃分成多個階段,每個階段都通過一個單獨的.js腳本來控制,而這些腳本都被保存在工程的migrations子目錄中,在我們目前所使用的MetaCoin/WebPack例子中,該目錄下都只有兩個文件,分別是:

1_initial_migration.js:負責發布Migrations.sol中的智能合約,這個合約是Truffle自動生成的,有自己內置的介面標準,通常不需要用戶進行改動。它主要被用來管理髮布合約的所有歷史數據。

2_deploy_contracts.js:負責發布用戶編寫的智能合約,本工程中它們被保存在MetaCoin.sol(合約代碼)和ConvertLib.sol(輔助功能代碼)兩個文件中,並且後者被前者所引用。

這種類似「序號_說明.js」的文件命名方式並不是必需的,不過它起到了兩個主要的作用:其一是可讀性,用戶很容易從文件名理解發布合約的每個階段在做什麼;其二是確立正確的執行順序,Truffle在發布過程中會按照文件名排序來執行各個階段的腳本,以數字序號作為開頭無疑確保了執行的正確順序。

此外,每次我們執行「truffle.cmd migrate」的時候,它都會自動判斷用戶代碼是否發生了改動,以及上一次發布合約時的最後一個階段在哪裡。然後查找用戶是否在migrations目錄中添加了新的階段腳本,並且僅運行新的腳本。因此,如果我們在控制台中反覆輸入這個指令(此過程中對合約代碼和發布腳本不做任何改動),第二次會給出「up to date」(不需要任何改動)的提示。

這對於合約發布的過程是很有實際價值的,畢竟以太坊區塊鏈上的所有「寫入」操作都需要消耗對應的資源(ETH)。如果我們因為錯誤的操作反覆發布完全相同的合約,那麼自然就白白損失了自己的「以太」。Truffle的發布流程可以確保只有改動過或者新增的合約被發布到鏈上,避免了財產損失,也避免鏈上堆積大量無用的數據。

注意,我們可以通過下面的指令來強制重新發布所有的合約:

# truffle.cmd migrate --reset

對於Truffle而言,使用migrate發布合約就意味著付出ETH作為代價(並且在此之前區塊鏈必須已經可用);不過compile是可以隨時隨意執行的,所有的操作都只作用於本地磁碟上。

打開文件2_deploy_contracts.js,裡面的內容基本上是一目了然的程度:

var ConvertLib = artifacts.require("./ConvertLib.sol"); //獲取ConvertLib介面對象

var MetaCoin = artifacts.require("./MetaCoin.sol"); //獲取MetaCoin介面對象

module.exports = function(deployer) { //固定格式,定義合約發布函數

deployer.deploy(ConvertLib); //發布ConvertLib到區塊鏈上

deployer.link(ConvertLib, MetaCoin); //鏈接ConvertLib到MetaCoin

deployer.deploy(MetaCoin); //發布MetaCoin到區塊鏈上

};

通過前一篇文章的閱讀我們已經知道,ConvertLib的作用是為MetaCoin提供輔助功能函數(雖然只有一個convert()),並且MetaCoin.sol的合約代碼中也把它作為導入庫使用。這很像是C/C++語言里使用#include來包含函數聲明的做法;以此類推,這裡我們使用deployer.link()將ConvertLib鏈接到MetaCoin的行為,也就可以類比成C/C++中的Link。這之後才能生成正確的合約結果並且發布。

而合約涉及的所有介面對象都是通過artifacts.require()來獲取的,值得注意的是,因為本工程中每個.sol文件中只定義了一個介面,因此require()的參數可以直接傳遞contracts目錄中的文件名。如果.sol中定義了多個介面,例如在ContractData.sol中定義了ContractA和ContractB兩個介面對象,那麼發布腳本中需要通過下面的語句來分別獲取兩個對象:

var ContractA = artifacts.require("ContractA");

var ContractB = artifacts.require("ContractB");

更多有關發布腳本和流程的內容,可以參考官方的入門文檔:

http://truffleframework.com/docs/getting_started/migrations

3、通過網站發布DAPP程序

我們在前面的章節中已經修改過前端界面對應的app.js文件的內容,以便正確對應區塊鏈的伺服器地址和埠號,現在我們再次打開這個文件(對於WebPack工程,它位於app/javascripts/目錄下),簡單了解一下它都做了哪些工作。

(1)文件的開頭部分首先導入必需的依賴庫(web3和truffle-contract)以及編譯後的合約文件,並建立唯一的抽象層介面MetaCoin。

(2)之後我們定義一個JS層面的App介面,它主要包括四個成員函數,分別是:

App.start():將區塊鏈的web3介面設置給MetaCoin抽象層,同時從web3.eth獲取用戶列表,設置交易的發起用戶(本工程中總是設置為accounts[0])並刷新他持有的代幣數。

App.setStatus():設置HTML界面上的日誌輸出內容。

App.refreshBalance():刷新當前用戶持有代幣總數的數額和界面顯示,這裡通過MetaCoin的實例對象觸發getBalance()方法,實現了JS前端對合約介面的調用。

App.sendCoin():向界面中給定的用戶地址發送一定數額的代幣,這裡通過MetaCoin的實例對象觸發sendCoin()方法,實現了JS前端對合約介面的調用(HTML文件中也有相應的代碼)。

(3)在window.addEventListener("load")所包含的代碼段中,我們從預先設置好的區塊鏈伺服器地址和埠嘗試獲取一個web3介面對象。因為這段代碼是在網頁載入時自動執行的,因此可以確保HTML頁面載入完成後就會獲取對象,然後執行App.start()初始化合約調用的相關介面。

事實上,Truffle甚至還提供了一個瀏覽器端的工具MetaMask,可以通過插件的方式直接載入到瀏覽器中,幫助編譯、發布和審閱合約,連接區塊鏈服務。這樣的話也就不需要在app.js中設置區塊鏈伺服器的地址和埠了。這個工具的相關說明可以參看:

http://truffleframework.com/docs/advanced/truffle-with-metamask

而window.addEventListener("load")中也會優先嘗試通過MetaMask直接獲取web3對象,如果失敗再通過JS文件中提供的地址連接。當然,之後的合約介面調用都是一致的。

現在,我們要嘗試將WebPack這個工程發布到一個簡易的網站上,讓其他客戶端(例如手機)也可以訪問界面,交互性地完成智能合約的查詢和交易操作。我們可以簡單地在控制台中通過ipconfig來查詢自己主機的IP地址(筆者為192.168.0.101)。

將這個IP地址分別填寫到工程根目錄的truffle.js文件(用於配置合約的發布腳本),app/javascripts/app.js文件(配置前端訪問),以及Ganache的伺服器設置頁面中:

選擇「保存並重新啟動」(Save & Restart)之後,這裡有一個需要注意的事情:Ganache本身是一個測試專用的私有鏈生成和維護工具,一旦它被關閉或者重啟,鏈上的所有區塊,以及區塊上的合約也都會被清空重置。再加上我們修改了合約相關的多個腳本文件,因此這裡最好重新執行一遍「編譯-發布-生成前端頁面」的指令流程為宜:

# truffle.cmd compile

# truffle.cmd migrate

# npm run build

之後我們可以進入build子目錄,或者將新生成的index.html和app.js拷貝到新的目錄,並建立一個最基礎的伺服器(例如通過Python):

# python.exe -m SimpleHTTPServer 8000

在瀏覽器端打開http://192.168.0.101:8000,看是否能正確顯示代幣總量,然後再給任意用戶地址發送一些代幣,看看交易能否順利完成?

同時,我們也可以通過其它客戶端(例如手機瀏覽器)進入到同一個網站,可以刷新觀察代幣的總量變化,或者執行更多交易操作了。

至此,雖然還很原始,但是我們已經擁有了正常運行的智能合約後端,基於HTML+JS的前端界面,以及通過多個客戶端去訪問它們了。下一步,該是自己創作一些內容的時候了。

歡迎隨便轉載。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 全球大搜羅 的精彩文章:

讓千生知道有個我,讓萬生知道有個你「12th station」
有一種人品叫做,我唯一的鞋子讓給你——伊朗電影《小鞋子》觀影報告

TAG:全球大搜羅 |