使用 AngularJS 和 Electron 构建桌面应用
Electron 丰富的原生 API 使我们能够在页面中直接使用 javascript 获取原生的内容。 这个教程向我们展示了如何使用 Angular 和 Electron 构建一个桌面应用。下面是本教程的所有步骤:
创建你的 Electron 应用起初,如果你的系统中还没有安装 Node,你需要先安装它。我们应用的结构如下所示: 这个项目中有两个 package.json 文件。
package.json 的格式和 Node 模块中的完全一致。你应用的启动脚本(的路径)需要在 app/package.json 中的
"AngularElectron",version: "0.0.0",main: "main.js"
}
{
name: 过执行
install --save-dev electron-prebuilt fs-jetpack asar rcedit Q
npm 创建启动脚本app/main.js 是我们应用的入口。它负责创建主窗口和处理系统事件。main.js 应该如下所示:
// app/main.js
// 应用的控制模块
var app = require('app');
// 创建原生浏览器窗口的模块
var BrowserWindow = require('browser-window');
var mainWindow = null;
// 当所有窗口都关闭的时候退出应用
app.on('window-all-closed',function () {
if (process.platform != 'darwin') {
app.quit();
}
});
// 当 Electron 结束的时候,这个方法将会生效
// 初始化并准备创建浏览器窗口
app.on('ready',function () {
// 创建浏览器窗口.
mainWindow = new BrowserWindow({ width: 800,height: 600 });
// 载入应用的 index.html
mainWindow.loadUrl('file://' + __dirname + '/index.html');
// 打开开发工具
// mainWindow.openDevTools();
// 窗口关闭时触发
mainWindow.on('closed',function () {
// 想要取消窗口对象的引用,如果你的应用支持多窗口,
// 通常你需要将所有的窗口对象存储到一个数组中,
// 在这个时候你应该删除相应的元素
mainWindow = null;
});
});
通过 DOM 访问原生正如我上面提到的那样,Electron 使你能够直接在 web 页面中访问本地 npm 模块和原生 API。你可以这样创建
<body> <h1>Hello World!</h1> We are using Electron <script> document.write(process.versions['electron']) </script> <script> document.write(process.platform) </script> <script type="text/javascript"> var fs = require('fs'); var file = fs.readFileSync('app/package.json'); document.write(file); </script> </body> </html>
<html>
app/index.html 是一个简单的 HTML 页面。在这里,它通过使用 Node’s fs (file system) 模块来读取 运行应用一旦你创建好了项目结构、 如果你已经在系统中全局安装了
electron app
在这里,
"node_modules/.bin/electron" "./app"
尽管你可以这样来运行应用,但是我还是建议你在
// 获取依赖
var gulp = require('gulp'),childProcess = require('child_process'),electron = require('electron-prebuilt');
// 创建 gulp 任务
gulp.task('run',function () {
childProcess.spawn(electron,['./app'],{ stdio: 'inherit' });
});
运行你的 gulp 任务: 配置 Visual Studio Code 开发环境Visual Studio Code 是微软的一款跨平台代码编辑器。VS Code 是基于 Electron 和 微软自身的 Monaco Code Editor 开发的。你可以在这里下载到 Visual Studio Code。 在 VS Code 中打开你的 electron 应用。 配置 Visual Studio Code Task Runner有很多自动化的工具,像构建、打包和测试等。我们大多从命令行中运行这些工具。VS Code task runner 使你能够将你自定义的任务集成到项目中。你可以在你的项目中直接运行 grunt,、gulp,、MsBuild 或者其他任务,这并不需要移步到命令行。 VS Code 能够自动检测你的 grunt 和 gulp 任务。按下 你将从
version": "0.1.0","command": "gulp","isShellCommand": true,"args": [ "--no-color" ],"tasks": [ { "taskName": "run","args": [],"isBuildCommand": true } ] }
{
"根部分声明命令为 现在,如果你按下 你可以在这里阅读到更多关于 visual studio code 任务的信息。 调试 Electron 应用打开调试面板点击配置按钮就会在 我们不需要启动 app.js 的配置,所以移除它。 现在,你的
"version": "0.1.0",// 配置列表。添加新的配置或更改已存在的配置。
// 仅支持 "node" 和 "mono",可以改变 "type" 来进行切换。
"configurations": [
{
"name": "Attach","type": "node",// TCP/IP 地址. 默认是 "localhost"
"address": "localhost",// 建立连接的端口.
"port": 5858,"sourceMaps": false
}
]
}
{
按照下面所示更改之前创建的 gulp
'run',['--debug=5858','./app'],{ stdio: 'inherit' });
});
gulp.task(在调试面板中选择 “Attach” 配置项,点击开始(run)或者按下 F5。稍等片刻后你应该就能在上部看到调试命令面板。 创建 AngularJS 应用第一次接触 AngularJS?浏览官方网站或一些 Scotch Angular 教程。 这一部分会讲解如何使用 angularjs 和 MySQL 数据库创建一个顾客管理(Customer Manager)应用。这个应用的目的不是为了强调 AngularJS 的核心概念,而是展示如何在 GiHub 的 Electron 中同时使用 angularjs 和 NodeJS 以及 mysql 。 我们的顾客管理应用正如下面这样简单:
项目结构我们的应用在 app 文件夹下,目录结构如下所示: 主页是 这里我更喜欢按照功能来组织脚本文件。每个功能都有它自己的文件夹,文件夹中有模板和控制器。获取更多关于目录结构的信息,可以阅读 AngularJS 最佳实践: 目录结构 在开始 AngularJS 应用之前,我们将使用 bower 安装客户端方面的依赖。如果你还没有 Bower 先要安装它。在命令提示行中将当前工作目录切换至你应用的根目录,然后依照下面的命令安装依赖。
install angular angular-route angular-material --save
bower 设置数据库在这个例子中,我将使用一个名字为
CREATE TABLE `customer_manager`.`customers` ( `customer_id` INT NOT NULL AUTO_INCREMENT,`name` VARCHAR(45) NOT NULL,`address` VARCHAR(450) NULL,`city` VARCHAR(45) NULL,`country` VARCHAR(45) NULL,`phone` VARCHAR(45) NULL,`remarks` VARCHAR(500) NULL,PRIMARY KEY (`customer_id`) );
创建一个 Angular Service 和 MySQL 进行交互一旦你的数据库和表都准备好了,就可以开始创建一个 AngularJS service 来直接从数据库中获取数据。使用
在命令提示行中切换工作目录至 app 文件夹然后按照下面所示安装模块:
install --save mysql
npm 我们的 angular service —— app/scripts/customer/customerService.js 如下所示:
function () {
'use strict';
var mysql = require('mysql');
// 创建 MySql 数据库连接
var connection = mysql.createConnection({
host: "localhost",user: "root",password: "password",database: "customer_manager"
});
angular.module('app')
.service('customerService',['$q',CustomerService]);
function CustomerService($q) {
return {
getCustomers: getCustomers,getById: getCustomerById,getByName: getCustomerByName,create: createCustomer,destroy: deleteCustomer,update: updateCustomer
};
function getCustomers() {
var deferred = $q.defer();
var query = "SELECT * FROM customers";
connection.query(query,function (err,rows) {
if (err) deferred.reject(err);
deferred.resolve(rows);
});
return deferred.promise;
}
function getCustomerById(id) {
var deferred = $q.defer();
var query = "SELECT * FROM customers WHERE customer_id = ?";
connection.query(query,[id],rows) {
if (err) deferred.reject(err);
deferred.resolve(rows);
});
return deferred.promise;
}
function getCustomerByName(name) {
var deferred = $q.defer();
var query = "SELECT * FROM customers WHERE name LIKE '" + name + "%'";
connection.query(query,[name],rows) {
if (err) deferred.reject(err);
deferred.resolve(rows);
});
return deferred.promise;
}
function createCustomer(customer) {
var deferred = $q.defer();
var query = "INSERT INTO customers SET ?";
connection.query(query,customer,res) if (err) deferred.reject(err); deferred.resolve(res.insertId); }); return deferred.promise; } function deleteCustomer(id) {
var deferred = $q.defer();
var query = "DELETE FROM customers WHERE customer_id = ?";
connection.query(query,res) {
if (err) deferred.reject(err);
deferred.resolve(res.affectedRows);
});
return deferred.promise;
}
function updateCustomer(customer) {
var deferred = $q.defer();
var query = "UPDATE customers SET name = ? WHERE customer_id = ?";
connection.query(query,[customer.name,customer.customer_id],res) {
if (err) deferred.reject(err);
deferred.resolve(res);
});
return deferred.promise;
}
}
})();
(
控制器 & 模板app/scripts/customer/customerController 中的
function () {
'use strict';
angular.module('app')
.controller('customerController',['customerService','$q','$mdDialog',CustomerController]);
function CustomerController(customerService,$q,$mdDialog) {
var self = this;
self.selected = null;
self.customers = [];
self.selectedIndex = 0;
self.filterText = null;
self.selectCustomer = selectCustomer;
self.deleteCustomer = deleteCustomer;
self.saveCustomer = saveCustomer;
self.createCustomer = createCustomer;
self.filter = filterCustomer;
// 载入初始数据
getAllCustomers();
//----------------------
// 内部方法
//----------------------
function selectCustomer(customer,index) {
self.selected = angular.isNumber(customer) ? self.customers[customer] : customer;
self.selectedIndex = angular.isNumber(customer) ? customer: index;
}
function deleteCustomer($event) {
var confirm = $mdDialog.confirm()
.title('Are you sure?')
.content('Are you sure want to delete this customer?')
.ok('Yes')
.cancel('No')
.targetEvent($event);
$mdDialog.show(confirm).then(function () {
customerService.destroy(self.selected.customer_id).then(function (affectedRows) {
self.customers.splice(self.selectedIndex,1);
});
},function () { });
}
function saveCustomer($event) {
if (self.selected != null && self.selected.customer_id != null) {
customerService.update(self.selected).then(function (affectedRows) {
$mdDialog.show(
$mdDialog
.alert()
.clickOutsideToClose(true)
.title('Success')
.content('Data Updated Successfully!')
.ok('Ok')
.targetEvent($event)
);
});
}
else {
//self.selected.customer_id = new Date().getSeconds();
customerService.create(self.selected).then(function (affectedRows) {
$mdDialog.show(
$mdDialog
.alert()
.clickOutsideToClose(true)
.title('Success')
.content('Data Added Successfully!')
.ok('Ok')
.targetEvent($event)
);
});
}
}
function createCustomer() {
self.selected = {};
self.selectedIndex = null;
}
function getAllCustomers() {
customerService.getCustomers().then(function (customers) {
self.customers = [].concat(customers);
self.selected = customers[0];
});
}
function filterCustomer() {
if (self.filterText == null || self.filterText == "") {
getAllCustomers();
}
else {
customerService.getByName(self.filterText).then(function (customers) {
self.customers = [].concat(customers);
self.selected = customers[0];
});
}
}
}
})();
(我们的顾客模板(app/scripts/customer/customer.html)使用了 angular material 组件来构建 UI,如下所示:
<div style="width:100%" layout="row">
<md-sidenav class="site-sidenav md-sidenav-left md-whiteframe-z2" md-component-id="left" md-is-locked-open="$mdMedia('gt-sm')">
<md-toolbar layout="row" class="md-whiteframe-z1">
<h1>Customers</h1>
</md-toolbar>
<md-input-container style="margin-bottom:0">
<label>Customer Name</label>
<input required name="customerName" ng-model="_ctrl.filterText" ng-change="_ctrl.filter()">
</md-input-container>
<md-list>
<md-list-item ng-repeat="it in _ctrl.customers">
<md-button ng-click="_ctrl.selectCustomer(it,$index)" ng-class="{'selected' : it === _ctrl.selected }">
{{it.name}}
</md-button>
</md-list-item>
</md-list>
</md-sidenav>
<div flex layout="column" tabIndex="-1" role="main" class="md-whiteframe-z2">
<md-toolbar layout="row" class="md-whiteframe-z1">
<md-button class="menu" hide-gt-sm ng-click="ul.toggleList()" aria-label="Show User List">
<md-icon md-svg-icon="menu"></md-icon>
</md-button>
<h1>{{ _ctrl.selected.name }}</h1>
</md-toolbar>
<md-content flex id="content">
<div layout="column" style="width:50%">
<br />
<md-content layout-padding class="autoScroll">
<md-input-container>
<label>Name</label>
<input ng-model="_ctrl.selected.name" type="text">
</md-input-container>
<md-input-container md-no-float>
<label>Email</label>
<input ng-model="_ctrl.selected.email" type="text">
</md-input-container>
<md-input-container>
<label>Address</label>
<input ng-model="_ctrl.selected.address" ng-required="true">
</md-input-container>
<md-input-container md-no-float>
<label>City</label>
<input ng-model="_ctrl.selected.city" type="text" >
</md-input-container>
<md-input-container md-no-float>
<label>Phone</label>
<input ng-model="_ctrl.selected.phone" type="text">
</md-input-container>
</md-content>
<section layout="row" layout-sm="column" layout-align="center center" layout-wrap>
<md-button class="md-raised md-info" ng-click="_ctrl.createCustomer()">Add</md-button>
<md-button class="md-raised md-primary" ng-click="_ctrl.saveCustomer()">Save</md-button>
<md-button class="md-raised md-danger" ng-click="_ctrl.cancelEdit()">Cancel</md-button>
<md-button class="md-raised md-warn" ng-click="_ctrl.deleteCustomer()">Delete</md-button>
</section>
</div>
</md-content>
</div>
</div>
app.js 包含模块初始化脚本和应用的路由配置,如下所示:
function () {
'use strict';
var _templateBase = './scripts';
angular.module('app',[
'ngRoute','ngMaterial','ngAnimate'
])
.config(['$routeProvider',function ($routeProvider) {
$routeProvider.when('/',{
templateUrl: _templateBase + '/customer/customer.html',controller: 'customerController',controllerAs: '_ctrl'
});
$routeProvider.otherwise({ redirectTo: '/' });
}
]);
})();
(最后是我们的首页 app/index.html
<html lang="en" ng-app="app">
<title>Customer Manager</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"gt; <meta name="description" content="">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<!-- build:css assets/css/app.css -->
<link rel="stylesheet" href="../bower_components/angular-material/angular-material.css" />
<link rel="stylesheet" href="assets/css/style.css" />
<!-- endbuild -->
<body>
<ng-view></ng-view>
<!-- build:js scripts/vendor.js -->
<script src="../bower_components/angular/angular.js"></script>
<script src="../bower_components/angular-route/angular-route.js"></script>
<script src="../bower_components/angular-animate/angular-animate.js"></script>
<script src="../bower_components/angular-aria/angular-aria.js"></script>
<script src="../bower_components/angular-material/angular-material.js"></script>
<!-- endbuild -->
<!-- build:app scripts/app.js -->
<script src="./scripts/app.js"></script>
<script src="./scripts/customer/customerService.js"></script>
<script src="./scripts/customer/customerController.js"></script>
<!-- endbuild -->
</body>
</html>
如果你已经如上面那样配置过 VS Code task runner 的话,使用 构建 AngularJS 应用为了构建我们的 Angular 应用,需要安装
install --save gulp-uglify gulp-minify-css gulp-usemin
npm 打开你的
var childProcess = require('child_process');
var electron = require('electron-prebuilt');
var gulp = require('gulp');
var jetpack = require('fs-jetpack');
var usemin = require('gulp-usemin');
var uglify = require('gulp-uglify');
var projectDir = jetpack;
var srcDir = projectDir.cwd('./app');
var destDir = projectDir.cwd('./build');
如果构建目录已经存在的话,清理一下它。
'clean',function (callback) {
return destDir.dirAsync('.',{ empty: true });
});
gulp.task(复制文件到构建目录。我们并不需要使用复制功能来复制 angular 应用的代码,在下一部分中
'copy',['clean'],function () {
return projectDir.copyAsync('app',destDir.path(),{
overwrite: true,matching: [
'./node_modules/**/*','*.html','*.css','main.js','package.json'
]
});
});
gulp.task(我们的构建任务将使用 gulp.src() 获取 app/index.html 然后传递给 usemin。然后它会将输出写入到构建目录并且把 index.html 中的引用用优化版代码替换掉 。
<!-- build:js scripts/vendor.js -->
<script src="../bower_components/angular/angular.js"></script>
<script src="../bower_components/angular-route/angular-route.js"></script>
<script src="../bower_components/angular-animate/angular-animate.js"></script>
<script src="../bower_components/angular-aria/angular-aria.js"></script>
<script src="../bower_components/angular-material/angular-material.js"></script>
<!-- endbuild -->
<!-- build:app scripts/app.js -->
<script src="./scripts/app.js"></script>
<script src="./scripts/customer/customerService.js"></script>
<script src="./scripts/customer/customerController.js"></script>
<!-- endbuild -->
构建任务如下所示:
'build',['copy'],function () {
return gulp.src('./app/index.html')
.pipe(usemin({
js: [uglify()]
}))
.pipe(gulp.dest('build/'));
});
gulp.task(为发行(distribution)做准备在这一部分我们将把 Electron 应用打包至生产环境。在根目录创建构建脚本 可以在
安装构建 electron 必要的依赖: 接下来,初始化我们的构建脚本,如下所示:
var Q = require('q');
var childProcess = require('child_process');
var asar = require('asar');
var jetpack = require('fs-jetpack');
var projectDir;
var buildDir;
var manifest;
var appDir;
function init() {
// 项目路径是应用的根目录
projectDir = jetpack;
// 构建目录是最终应用被构建后放置的目录
buildDir = projectDir.dir('./dist',{ empty: true });
// angular 应用目录
appDir = projectDir.dir('./build');
// angular 应用的 package.json 文件
manifest = appDir.read('./package.json','json');
return Q();
}
这里我们使用 复制 Electron Distribution从
function copyElectron() {
return projectDir.copyAsync('./node_modules/electron-prebuilt/dist',buildDir.path(),{ overwrite: true });
}
清理默认应用你可以在
function cleanupRuntime() {
return buildDir.removeAsync('resources/default_app');
}
创建 asar 包
function createAsar() {
var deferred = Q.defer();
asar.createPackage(appDir.path(),buildDir.path('resources/app.asar'),function () {
deferred.resolve();
});
return deferred.promise;
}
这将会把你 angular 应用的所有文件打包到一个 asar 包文件里。你可以在 替换为自己的应用资源下一步是将默认的 electron icon 替换成你自己的,更新产品的信息然后重命名应用。
function updateResources() {
var deferred = Q.defer();
// 将你的 icon 从 resource 文件夹复制到构建文件夹下
projectDir.copy('resources/windows/icon.ico',buildDir.path('icon.ico'));
// 将 Electron icon 替换成你自己的
var rcedit = require('rcedit');
rcedit(buildDir.path('electron.exe'),{
'icon': projectDir.path('resources/windows/icon.ico'),'version-string': {
'ProductName': manifest.name,'FileDescription': manifest.description,}
},function (err) {
if (!err) {
deferred.resolve();
}
});
return deferred.promise;
}
// 重命名 electron exe
function rename() {
return buildDir.renameAsync('electron.exe',manifest.name + '.exe');
}
创建原生安装包你可以使用 wix 或 NSIS 创建 windows 安装包。这里我们尽可能使用更小更灵活的 NSIS,它很适合网络应用。使用 NSIS 可以创建支持应用安装时需要的任何事情的安装包。 在 resources/windows/installer.nsis 中创建 NSIS 脚本
"{{dest}}"
!define src "{{src}}"
!define name "{{name}}"
!define productName "{{productName}}"
!define version "{{version}}"
!define icon "{{icon}}"
!define banner "{{banner}}"
!define exec "{{productName}}.exe"
!define regkey "Software${productName}"
!define uninstkey "SoftwareMicrosoftWindowsCurrentVersionUninstall${productName}"
!define uninstaller "uninstall.exe"
; --------------------------------
; Installation
; --------------------------------
SetCompressor lzma
Name "${productName}"
Icon "${icon}"
OutFile "${dest}"
InstallDir "$PROGRAMFILES${productName}"
InstallDirRegKey HKLM "${regkey}" ""
CRCCheck on
SilentInstall normal
XPStyle on
ShowInstDetails nevershow
AutoCloseWindow false
WindowIcon off
Caption "${productName} Setup"
; Don't add sub-captions to title bar SubCaption 3 " " SubCaption 4 " " Page custom welcome Page instfiles Var Image Var ImageHandle Function .onInit ; Extract banner image for welcome page InitPluginsDir ReserveFile "${banner}" File /oname=$PLUGINSDIRbanner.bmp "${banner}" FunctionEnd ; Custom welcome page Function welcome nsDialogs::Create 1018 ${NSD_CreateLabel} 185 1u 210 100% "Welcome to ${productName} version ${version} installer.$r$n$r$nClick install to begin." ${NSD_CreateBitmap} 0 0 170 210 "" Pop $Image ${NSD_SetImage} $Image $PLUGINSDIRbanner.bmp $ImageHandle nsDialogs::Show ${NSD_FreeImage} $ImageHandle FunctionEnd ; Installation declarations Section "Install" WriteRegStr HKLM "${regkey}" "Install_Dir" "$INSTDIR" WriteRegStr HKLM "${uninstkey}" "DisplayName" "${productName}" WriteRegStr HKLM "${uninstkey}" "DisplayIcon" '"$INSTDIRicon.ico"' WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$INSTDIR${uninstaller}"' ; Remove all application files copied by previous installation RMDir /r "$INSTDIR" SetOutPath $INSTDIR ; Include all files from /build directory File /r "${src}*" ; Create start menu shortcut CreateShortCut "$SMPROGRAMS${productName}.lnk" "$INSTDIR${exec}" "" "$INSTDIRicon.ico" WriteUninstaller "${uninstaller}" SectionEnd ; -------------------------------- ; Uninstaller ; -------------------------------- ShowUninstDetails nevershow UninstallCaption "Uninstall ${productName}" UninstallText "Don't like ${productName} anymore? Hit uninstall button." UninstallIcon "${icon}" UninstPage custom un.confirm un.confirmOnLeave UninstPage instfiles Var RemoveAppDataCheckbox Var RemoveAppDataCheckbox_State ; Custom uninstall confirm page Function un.confirm nsDialogs::Create 1018 ${NSD_CreateLabel} 1u 1u 100% 24u "If you really want to remove ${productName} from your computer press uninstall button." ${NSD_CreateCheckbox} 1u 35u 100% 10u "Remove also my ${productName} personal data" Pop $RemoveAppDataCheckbox nsDialogs::Show FunctionEnd Function un.confirmOnLeave ; Save checkbox state on page leave ${NSD_GetState} $RemoveAppDataCheckbox $RemoveAppDataCheckbox_State FunctionEnd ; Uninstall declarations Section "Uninstall" DeleteRegKey HKLM "${uninstkey}" DeleteRegKey HKLM "${regkey}" Delete "$SMPROGRAMS${productName}.lnk" ; Remove whole directory from Program Files RMDir /r "$INSTDIR" ; Remove also appData directory generated by your app if user checked this option ${If} $RemoveAppDataCheckbox_State == ${BST_CHECKED} RMDir /r "$LOCALAPPDATA${name}" ${EndIf} SectionEnd
!include LogicLib.nsh
!include nsDialogs.nsh
; --------------------------------
; Variables
; --------------------------------
!define dest 在
function createInstaller() {
var deferred = Q.defer();
function replace(str,patterns) {
Object.keys(patterns).forEach(function (pattern) {
console.log(pattern)
var matcher = new RegExp('{{' + pattern + '}}','g');
str = str.replace(matcher,patterns[pattern]);
});
return str;
}
var installScript = projectDir.read('resources/windows/installer.nsi');
installScript = replace(installScript,{
name: manifest.name,productName: manifest.name,version: manifest.version,src: buildDir.path(),dest: projectDir.path(),icon: buildDir.path('icon.ico'),setupIcon: buildDir.path('icon.ico'),banner: projectDir.path('resources/windows/banner.bmp'),});
buildDir.write('installer.nsi',installScript);
var nsis = childProcess.spawn('makensis',[buildDir.path('installer.nsi')],{
stdio: 'inherit'
});
nsis.on('error',function (err) {
if (err.message === 'spawn makensis ENOENT') {
throw "Can't find NSIS. Are you sure you've installed it and"
+ " added to PATH environment variable?";
} else {
throw err;
}
});
nsis.on('close',function () {
deferred.resolve();
});
return deferred.promise;
}
你应该安装了 NSIS,并且确保它在你的路径中是可用的。 将他们组合到一起创建一个函数把所有的片段放在一起,为了使 gulp 任务可以获取到然后输出它:
function build() {
return init()
.then(copyElectron)
.then(cleanupRuntime)
.then(createAsar)
.then(updateResources)
.then(rename)
.then(createInstaller);
}
module.exports = { build: build };
接着,在
var release_windows = require('./build.windows');
var os = require('os');
gulp.task('build-electron',['build'],function () {
switch (os.platform()) {
case 'darwin':
// 执行 build.osx.js
break;
case 'linux':
//执行 build.linux.js
break;
case 'win32':
return release_windows.build();
}
});
运行下面命令,你应该就会得到最终的产品:
gulp build-electron
你最终的 electron 应用应该在 总结Electron 不仅仅是一个支持打包 web 应用成为桌面应用的原生 web view。它现在包含 app 的自动升级、Windows 安装包、崩溃报告、通知和一些其它有用的原生 app 功能——所有的这些都通过 javascript API 调用。 到目前为止,很大范围的应用使用 electron 创建,包括聊天应用、数据库管理器、地图设计器、协作设计工具和手机原型等。 下面是 Github Electron 的一些有用的资源:
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |