原文:Creating Your First Desktop App With HTML, JS and Electron
做者:Danny Markovcss
近年來 web 應用變得愈來愈強大,可是桌面應用仍然有充分利用硬件的優點。html
今天,咱們能夠經過咱們熟悉的 HTML、JS 和 Node.js 來建立桌面應用,打包成一個可執行文件,而且發佈在 Windows, OS X 和 Linux 上。node
有兩個受歡迎的開源項目,可以幫助咱們實現這個目的。一個是幾個月前咱們討論到的 NW.js,另外一個是今天咱們將要使用的 Electron(點擊這裏查看它們的不一樣之處)。咱們將把舊項目的 NW.js 重構成 Electron,因此你能夠輕鬆地比較他們的不一樣。jquery
用 Electron 構建的應用僅僅是一個網站而已,這個網站在嵌入了 Chromium 的瀏覽器中運行。除了常規的 HTML5 接口,這些應用可以使用全部的 Node.js 模塊,以及 Electron 特有的模塊,這個模塊可以讓應用擁有訪問操做系統的能力。git
這篇文章中,咱們將會構建一個簡單的應用,經過 RSS 訂閱,來獲取 Tutorialzine 上最新的文章,並經過好看的輪播的形式展示出來。這個項目用到的全部文件,你能夠點擊文章頂部的下載按鈕獲取(譯者注:下載連接)。github
下載後,解壓內容到一個文件夾。從文件結構來看,你永遠猜不到這是一個桌面應用,而不只僅是一個簡單的網站。web
接下來,咱們將仔細分析這些項目文件,瞭解它們是如何工做的。但首先,咱們來運行這個應用。ajax
因爲 Electron 應用只是一個 Node.js 應用,你須要安裝 npm。你能夠點擊這裏學習怎樣安裝,這很容易。shell
解壓項目後,在解壓目錄下打開 cmd 或者命令行,執行如下命令:npm
npm install
這條命令會建立一個 node_modules
文件夾,裏面包含了項目須要全部的 Node.js 依賴。接下來,在同個終端上執行下面的命令:
npm start
這個應用會打開一個新的窗口。注意看,窗口有一個頂部菜單以及其餘東西。
你可能已經留意到,這個應用的啓動方式不怎麼友好。但這僅僅是開發時啓動應用的方式。應用打包發佈後,就會像普通的程序那樣只是一個安裝文件,雙擊圖標就能夠啓動。
這一段內容,咱們將討論 Electron 應用必要的文件。咱們將從 package.json
文件講起,這個文件包含關於這個項目的各類信息,好比版本號、npm 依賴以及其餘重要的配置。
package.json { "name": "electron-app", "version": "1.0.0", "description": "", "main": "main.js", "dependencies": { "pretty-bytes": "^2.0.1" }, "devDependencies": { "electron-prebuilt": "^0.35.2" }, "scripts": { "start": "electron main.js" }, "author": "", "license": "ISC" }
若是你以前使用過 Node.js,你已經知道了這個文件是作什麼的。在這裏最值得講述的是 scripts
這個屬性,它定義了 npm start
這條命令,容許咱們使用命令來運行應用。當咱們執行這條命令的時候,electron 就會執行 main.js
。這個 JS 文件的腳本打開了應用的窗口,定義了一些配置和事件處理。
var app = require('app'); // Module to control application life. var BrowserWindow = require('browser-window'); // Module to create native browser window. // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. var mainWindow = null; // 當全部窗口關閉時退出應用 app.on('window-all-closed', function() { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform != 'darwin') { app.quit(); } }); // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', function() { // 建立瀏覽器窗口 mainWindow = new BrowserWindow({width: 900, height: 600}); // 加載這個應用的 index.html mainWindow.loadURL('file://' + __dirname + '/index.html'); // 當窗口關閉時執行 mainWindow.on('closed', function() { // Dereference the window object, usually you would store windows // in an array if your app supports multi windows, this is the time // when you should delete the corresponding element. mainWindow = null; }); });
咱們來看一下,在 ready
方法作了哪些事情。首先咱們定義了一個瀏覽器窗口,而且設置了它的初始化大小。而後,在窗口裏面加載了 index.html
文件,這一步就像在瀏覽器中打開了一個 HTML 文件。
正如你所看到的,這個 HTML 文件自己並無什麼特別——它包含了一個輪播組件的容器標籤和一個用來展現 CPU 和 RAM 的 p
標籤。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Tutorialzine Electron Experiment</title> <link rel="stylesheet" href="./css/jquery.flipster.min.css"> <link rel="stylesheet" href="./css/styles.css"> </head> <body> <div class="flipster"> <ul> </ul> </div> <p class="stats"></p> <!-->In Electron, this is the correct way to include jQuery<--> <script>window.$ = window.jQuery = require('./js/jquery.min.js');</script> <script src="./js/jquery.flipster.min.js"></script> <script src="./js/script.js"></script> </body> </html>
這個 HTML 文件也引用了幾個必要的樣式文件,JS 庫和腳本。注意在這裏 jQuery 是經過一種奇怪的方式引入進來的。更多相關信息能夠查看這個issue。
最後,是這個應用的實際腳本文件。腳本里面,咱們調用 Tutorialzine 的 RSS 訂閱接口,獲取了最新的文章而且展現出來。若是咱們在瀏覽器環境這麼作,是獲取不到數據的,由於跨域的緣由,咱們沒法獲取到數據。但在 Electron 裏就沒有跨域的限制,咱們能夠簡單地經過 AJAX 請求來獲取咱們須要的信息。
$(function(){ // Display some statistics about this computer, using node's os module. var os = require('os'); var prettyBytes = require('pretty-bytes'); $('.stats').append('Number of cpu cores: <span>' + os.cpus().length + '</span>'); $('.stats').append('Free memory: <span>' + prettyBytes(os.freemem())+ '</span>'); // Electron's UI library. We will need it for later. var shell = require('shell'); // 獲取 Tutorialzine 上最新的文章 var ul = $('.flipster ul'); // The same-origin security policy doesn't apply to electron, so we can // send ajax request to other sites. Let's fetch Tutorialzine's rss feed: $.get('http://feeds.feedburner.com/Tutorialzine', function(response){ var rss = $(response); // Find all articles in the RSS feed: rss.find('item').each(function(){ var item = $(this); var content = item.find('encoded').html().split('</a></div>')[0]+'</a></div>'; var urlRegex = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/g; // Fetch the first image of the article. var imageSource = content.match(urlRegex)[1]; // Create a li item for every article, and append it to the unordered list. var li = $('<li><img /><a target="_blank"></a></li>'); li.find('a') .attr('href', item.find('link').text()) .text(item.find("title").text()); li.find('img').attr('src', imageSource); li.appendTo(ul); }); // Initialize the flipster plugin. $('.flipster').flipster({ style: 'carousel' }); // 文章被點擊時,在系統默認瀏覽器打開鏈接 // 不這樣作的話,會在 electron 窗口中打開鏈接,這不是咱們想要的效果 $('.flipster').on('click', 'a', function (e) { e.preventDefault(); // 在默認瀏覽器中打開連接 shell.openExternal(e.target.href); }); }); });
上面的代碼中,比較酷的是,咱們在一個文件同時使用了:
還有一件重要的事須要咱們去作,就是準備好咱們的應用給最終用戶使用。你須要把項目打包成一個可執行文件,能夠在用戶的機器上雙擊運行。因爲 Electron 應用能夠在多個不一樣的操做系統上運行,咱們須要分別打包成 Windows、OS X 和 Linux 各個版本。像 Electron Packager 這個 npm 模塊就是一個不錯的工具。
須要考慮的是,打包項目時會把全部資源,全部的 Node.js 依賴,加上一個縮小版的 WebKit 瀏覽器,打包成一個可執行的文件。這些東西加起來的結果就是,打包後的應用體積大約爲 50mb。這個體積已經算是比較大了,對於一些簡單的應用,好比這個示例項目來講,有些不太理想。但對於那些比較大而又複雜的項目來講,就可有可無了。
從這個示例項目能夠看出,Electron 與 NW.js 的主要差別在於,NW.js 是直接打開一個 HTML 頁面,而 Electron 是經過執行一個腳本文件,在代碼中建立一個窗口。Electron 這種建立方式,可以讓咱們更大程度地控制應用,好比咱們能夠輕鬆地構建一個多窗口應用,並在窗口之間進行通訊。
總體上,Electron 是一個使人激動的、經過 web 技術來構建桌面應用的方式。接下來,你能夠繼續閱讀: