Electronとは
- 旧)Atom Shell
- Node.jsに基づいたDesktop Application Flatform
- HTML, CSS, JavaScriptで、Cross-Flatformで 動くDesktop Applicationを作れる
- WebPageのGUIとjavascriptで操作するChromium Browser
- Desktop Application : 似た技術としてNW.js (node-webkit)が存在
- Electronで作られたアプリについては、Awesome Electron 参照
環境構築手順
目標
- WindowsでのElectron開発環境構築
- ElectronでHello Worldの出力
- パッケージングでexeファイルを作成、動作確認
基本設定
- 装置1スペック
- CPU : i3-4000M 2.40GHz
- RAM : 4.0GB
- OS : Microsoft Windows 8.1 Enterprise K 64Bit
- Electron Version: 0.36.8
- 装置2スペック
- CPU : i3-3240 3.40GHz
- RAM : 4.0GB
- OS : Microsoft Windows 7 Professional SP1 32Bit
- Electron Version: 0.36.8
下準備
- Node.js : Stable Version (v.5.7.1)
- npmを使うので、Node.jsの設置は必須!
- Windowsのバージョンに合わせて、msiファイルをダウンロードし、設置するだけでOK
- Node.jsの設置確認
- cmd > node
- 簡単なjavascriptコードを入力し、テスト
- jsファイルでのテスト : app.js (エンコード:UTF-8)
var http = require('http');
http.createServer(function(req,res){
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('Hello World\nHello node.js!');
}).listen(1337,"127.0.0.1");
console.log("Server running at http://127.0.0.1:1337/");
Electronのインストール
Electronの実行
Electron Appの構造
your-app/
├── package.json : main fieldにscript fileを指定し、main processのエントリーポイントとして使用
├── main.js : Windowを作り、システムイベントを処理
└── index.html : ユーザに見せるページ
プロジェクト生成
/**
* package.json
**/
{
"name": "electron",
"version": "1.0.0",
"description": "print \"Hello, Electron\"",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Youngjae Kwon",
"license": "ISC"
}
Hello, Electron!
- 一旦準備が終わったので、いつもの通り「Hello World」みたいな物を出力してみよう。
- initでmain scriptを「main.js」で設定したので、main.jsから作成することに。
main.js
/**
* 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.on('closed', function() {
// ウィンドーオブジェクトの参照を削除
mainWindow = null;
});
});
- main.jsがindex.htmlを呼ぶことにしたので、今度はindex.htmlを作成する。
index.html
<!--
/*
* index.html
*/
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<p>Hello, Electron!</p>
</body>
</html>
これで準備はOK。実行してみよう。
Packaging
早速使ってみよう
この通り、electron-win32-ia32とelectron-win32-x64フォルダが生成された。
書いた内容を説明すると…
platform : all, linux, win32, darwin
arch : all, ia32, x64
version : Electronのバージョン (現在0.36.8)
ここでallを選んだので、フォルダが32と64の二つができた。
もし32bitWindowsの装置を使ってるとしたら、実は
electron-packager ./electron electron --platform=win32 --arch=ia32 --version=0.36.8
これだけでOK。
実行
プロジェクト名をElectronにしてしまって、ちょっとわかり辛くなったが,
こうやってEXEファイルができ、それを実行したら普通にアプリが動く。
Electronでのアプリケーション開発
1. 目標
- 簡単なメモ帳アプリの作成 (テキストの保存とロード機能)
- WindowsでElectronを使うこと
- プロジェクト作成にはAtomとGruntを使ってみること
- パッケージングでEXEファイルを作り、動作を確認
2. 準備
2-1. Atom
- Atom ダウンロード (https://atom.io)
- Windowsのバージョンに合わせてインストールするだけでOK
- Packageの設置 (File→Settings→InstallでPackage検索)
- linter : 文法上のエラー表示
- grunt-runner : AtomでGrunt実行
- minimap, minimap-find-and-replace : minimapが見える
- atom-minify : JS, CSSの圧縮化 (ctrl+shift+m or 「Minify on save」設定)
2-2. Grunt
- Gruntとは?
- プロジェクト自動化のためのCommand Line Build Tool
- パッケージ管理者 (Yeoman , Bower , Gulp等と同じ)
- もっとも基本的な自動化パッケージ
- grunt-cli (Grunt’s Command Line Interface) 設置
- grunt-cliの設置で、システム経路に「grunt」コマンドが追加され、gruntが使えるようになる。
- grunt-cliの役割はただGruntflieというファイルがある場所に設置されたGruntを実行するだけ。
- Grunt Module 設置方法 (package.jsonがあるディレクトリで設置)
- 新しいModuleを設置し、package.jsonに記入 :
npm install grunt --save dev
- すでにpackage.jsonに記入されているModuleを設置 :
npm install
(package.jsonとGruntfile.jsがあれば、どこでも同じgrunt作業が可能!)
- ここでは2の方法でプロジェクト作成
3. Project作成
3-1. ディレクトリ構成図
C:\PROJECT\MEMO
│ Gruntfile.js
│ main.js
│ package.json
│
├─app
│ ├─css
│ │ bootstrap-theme.css
│ │ bootstrap-theme.css.map
│ │ bootstrap-theme.min.css
│ │ bootstrap.css
│ │ bootstrap.css.map
│ │ bootstrap.min.css
│ │
│ ├─fonts
│ │ glyphicons-halflings-regular.eot
│ │ glyphicons-halflings-regular.svg
│ │ glyphicons-halflings-regular.ttf
│ │ glyphicons-halflings-regular.woff
│ │ glyphicons-halflings-regular.woff2
│ │
│ ├─html
│ │ │ index.html
│ │ │
│ │ └─include
│ │ link.html
│ │ memo.html
│ │
│ ├─js
│ │ │ memo.js
│ │ │ memo.min.js
│ │ │
│ │ └─lib
│ │ bootstrap.js
│ │ bootstrap.min.js
│ │ jquery-1.12.1.js
│ │ jquery-1.12.1.min.js
│ │ npm.js
│ │
│ └─view
│ │ index.html
│ │
│ └─include
│ link.html
│ memo.html
│
├─dist
│ ├─css
│ │ style.min.css
│ │
│ └─js
│ site.js
│ site.min.js
│
└─node_modules
├─grunt
├─grunt-cache-breaker
├─grunt-contrib-cssmin
├─grunt-contrib-uglify
├─grunt-includes
├─load-grunt-tasks
├─moment
└─time-grunt
css・fonts・libフォルダには、
Bootstrap、
JQuery
をダウンロードして入れる。
3-2. プロジェクトソース
package.json
{
"name": "memo",
"version": "1.0.0",
"description": "save and load txt file",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Youngjae Kwon",
"license": "ISC",
"devDependencies": {
"grunt": "^0.4.5",
"moment": "^2.8.3",
"grunt-cache-breaker": "^2.0.1",
"grunt-contrib-cssmin": "^1.0.0",
"grunt-contrib-uglify": "^1.0.0",
"grunt-includes": "^0.5.4",
"load-grunt-tasks": "^3.4.1",
"time-grunt": "^1.3.0"
}
}
main.js
/**
* 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();
}
});
app.on('ready', function() {
mainWindow = new BrowserWindow({width: 550, height: 410});
mainWindow.loadUrl('file://' + __dirname + '/app/view/index.html');
mainWindow.on('closed', function() {
mainWindow = null;
});
});
Gruntfile.js
/**
* Gruntfile.js
**/
module.exports = function(grunt) {
'use strict';
var moment = (require('moment'))();
var timestamp = 'None';
// 自動でgrunt Taskをロードする。(grunt.loadNpmTasksは省略可能)
require('load-grunt-tasks')(grunt);
// 作業時間表示
require('time-grunt')(grunt);
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// html task
includes: {
files: {
cwd: 'app/html/', // app/htmlのhtmlファイルにinclude処理をして
src: ['**/*.html'],
dest: 'app/view/', // その結果をapp/viewに入れる
options: {
flatten: true,
debug: true,
includePath: 'app/html/'
}
}
},
// css task
cssmin: {
options: {
keepSpecialComments: 1,
},
dist: {
src: 'dist/css/style.css',
dest: 'dist/css/style.min.css'
}
},
// js task
uglify: {
options: {
banner: '<%= banner %>'
},
dist: {
src: 'dist/js/site.js',
dest: 'dist/js/site.min.js'
}
},
cachebreaker: {
dev: {
options: {
match: ['.js'],
replacement: function () {
return moment.format('YYYYMMDDhhmmss');
}
},
files: {
src: ['app/html/*.html', 'app/view/*.html']
}
}
}
});
// html task
grunt.registerTask('html', ['includes']);
// css task
grunt.registerTask('css', ['cssmin']);
// javascript task
grunt.registerTask('js', ['uglify', 'cachebreaker']);
// default task
grunt.registerTask('default', ['html', 'css', 'js']);
};
index.html
<!--
/*
* index.html
*/
-->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Memo MK2</title>
<link href="../css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
include "include/link.html"
include "include/memo.html"
</body>
</html>
link.html
<!--
/*
* link.html
*/
-->
<script src="../js/lib/jquery-1.12.1.min.js"></script>
<script src="../js/lib/bootstrap.min.js"></script>
<script type="text/javascript" src="../js/memo.min.js"></script>
memo.html
<!--
/*
* memo.html
*/
-->
<table class="table table-striped">
<tr>
<td style="text-align: left; width: 100px;">テキスト入力</td>
<td colspan="2" style="text-align:left; width:300px;">
<textarea id="ntText" class="input-xxlarge" style="width:95%; height:200px;" maxlength="4000"></textarea>
</td>
</tr>
<tr>
<td>ファイル名</td>
<td>
<input type="text" class="form-control" id="nmSaveFile" />
</td>
<td>
<button class="btn btn-default btn-primary" onclick="saveTxt()">保存する</button>
</td>
</tr>
<tr>
<td>ファイル選択</td>
<td>
<input type="file" class="form-control" id="nmLoadFile" />
</td>
<td>
<button class="btn btn-default btn-primary" onclick="loadTxt()">ロードする</button>
</td>
</tr>
</table>
memo.js
/**
* memo.js
**/
// テキスト保存
function saveTxt(){
var ntText = document.getElementById("ntText").value;
var ntBlobText = new Blob([ntText], {type:'text/plain'});
var nmSaveFile = document.getElementById("nmSaveFile").value;
var saveLink = document.createElement("a");
saveLink.download = (nmSaveFile === null || nmSaveFile == "") ? "memo.txt" : nmSaveFile + ".txt";
saveLink.innerHTML = "Download File";
saveLink.href = window.webkitURL.createObjectURL(ntBlobText);
saveLink.click();
}
// テキストロード
function loadTxt(){
var nmLoadFile = document.getElementById("nmLoadFile").files[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent){
var ntLoadText = fileLoadedEvent.target.result;
document.getElementById("ntText").value = ntLoadText;
};
fileReader.readAsText(nmLoadFile, "UTF-8");
}
3-3. プロジェクト作成
- node_modules インストール
- package.jsonにdevDependenciesとして定義されているmoduleを全部インストールする。
C:\PROJECT
にてnpm install
- Atom Minifyでmemo.min.js作成
- atom-minifyの設定で「Minify on save」を設定すると、保存する時に自動でmemo.min.jsを生成
- この画面が出ればOK。
- Grunt RunnerでGruntをDefaultで動かす
- Gruntは勉強用で入れたのがほとんどで、実際この作業で必須なのはincludesだけ。
- link.html、memo.htmlをindex.htmlに含め、/app/view/index.htmlを作成
- この画面が出ればOK。
C:\PROJECT
にてelectron memo/
で動作確認
4. パッケージング・動作確認
4-1. パッケージング
memoフォルダをmemoMK2という名前でパッケージングする。
C:\project>electron-packager ./memo memoMK2 --platform=win32 --arch=ia32 --version=0.36.8
Packaging app for platform win32 ia32 using electron v0.36.8
Wrote new app to C:\project\memoMK2-win32-ia32
C:\project>
4-2. 作動確認
まとめ
- すごく簡単!
- Web Pageを作る感覚で、普通にDesktop Applicationが作れる。
- 環境設定に時間がかからないのもメリット
- 以前のHadoopの時を考えたら…
- 特にWindowsでも簡単にできるのが嬉い。
- Creatorとしての喜び
- こうやって簡単にアプリを作れるから、創作意欲が沸く。
- 自分に必要な物は、自分で作ってみよう!
参考