LoginSignup
32
53

More than 3 years have passed since last update.

初めてのElectron

Last updated at Posted at 2016-03-03

Electron

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コードを入力し、テスト

cmdTest.png

  • 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/");

nodeJSTest2.png

Electronのインストール

  • npmを使って、electron-prebuiltをダウンロード
  • Globalで設置したので、どこでプロジェクトを作成しても「electron プロジェクト名/」で実行できる。

inst.png

Electronの実行

Electron Appの構造

your-app/
├── package.json : main fieldにscript fileを指定し、main processのエントリーポイントとして使用
├── main.js      : Windowを作り、システムイベントを処理
└── index.html   : ユーザに見せるページ

プロジェクト生成

  • Electronは、実行されるときに「package.json」のmain scriptを呼び出す。
    • main script:main processで作動し、GUI Component操作・Web Page生成
  • npm initpackage.jsonを作成
    • 何を言ってるのか全然理解できなかったら、ただEnterだけ押せばほとんどOK (ここではプロジェクト名をelectronに設定する)
    • ただ、entry pointには必ず「main.js」を設定すること!
    • entry pointindex.jsでも構わない(2019/06/04追記)
    • もしpackage.jsonmain scripttが設定されてない場合、 Electronは自動で同じディレクトリーのindex.jsをロードする

initProject.png

  • 上の作業で、下のような「package.json」が生成される
/**
 * 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」みたいな物を出力してみよう。
initmain script「main.js」で設定したので、main.jsから作成することに。

/**
 * main.js
 **/ 
// アプリケーション基盤をコントロールするモジュール
const {app} = require('electron');

// ブラウザーウィンドーを作るモジュール
const {BrowserWindow } = require('electron');

// ウィンドーオブジェクトを全域に維持
let 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.jsindex.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。
実行してみよう。

sample.png

Packaging

  • プロジェクトを誰でも使えるように、パッケージ化してみよう。
  • ここでは、electron-packagerを使って作業。 これもnpmでもってこればOK

packager.png

これでダウンロード終わり。

  • 早速使ってみよう

packager2.png

この通り、electron-win32-ia32とelectron-win32-x64フォルダが生成された。
書いた内容を説明すると…

platform : all, linux, win32, darwin
arch : all, ia32, x64
version : 今は要らなくなったので、上のScreenShotに書いてあるのは無視
electron-version : electronのversionを記載(2019/06/04 追記)
※electronのversionは、electron --versionで確認可能

ここでallを選んだので、フォルダが32と64の二つができた。

もし32bitWindowsの装置を使ってるとしたら、実は
electron-packager ./electron electron --platform=win32 --arch=ia32 --electron-version=1.4.13
これでOK。

  • 実行

run.png

プロジェクト名をElectronにしてしまって、ちょっとわかり辛くなったが…
こうやってEXEファイルができ、それを実行したら普通にアプリが動く。

Electronでのアプリケーション開発

0. Source Code

  • これを書いてから時間もたって、Electronにもちょっと変化があった。
  • 自分のGithubに新バージョンのソースを載せといたので、それを参照

1. 目標

  • 簡単なメモ帳アプリの作成 (テキストの保存とロード機能)
  • WindowsでElectronを使うこと
  • プロジェクト作成にはAtomGruntを使ってみること
  • パッケージングで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」設定)

package-atom.png

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-cli.png

  • 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": {
    "electron": "^1.6.11",
    "grunt": "^0.4.5",
    "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",
    "moment": "^2.8.3",
    "time-grunt": "^1.3.0"
  }
}
  • main.js
/**
 * main.js
 **/
'use strict';
const {app, BrowserWindow} = require('electron');
let 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.jsondevDependenciesとして定義されているmoduleを全部インストールする。
    • C:\PROJECTにてnpm install
  • Atom Minifymemo.min.js作成
    • atom-minifyの設定で「Minify on save」を設定すると、保存する時に自動でmemo.min.jsを生成
    • この画面が出ればOK。

success_minify.png

  • Grunt RunnerGruntDefaultで動かす
    • Gruntは勉強用で入れたのがほとんどで、実際この作業で必須なのはincludesだけ。
    • link.htmlmemo.htmlindex.htmlに含め、/app/view/index.htmlを作成
    • この画面が出ればOK。

grunt_success.png

  • C:\PROJECTにてelectron memo/で動作確認
    • この画面が出ればOK。

run_electron.png

4. パッケージング・動作確認

4-1. パッケージング

  • memoフォルダmemoMK2という名前でパッケージングする。
C:\Users\idenr\project>electron-packager ./memo memoMK2 --platform=win32 --arch=x64
Packaging app for platform win32 x64 using electron v1.6.11
Wrote new app to C:\Users\idenr\project\memoMK2-win32-x64

4-2. 作動確認

complete.png

まとめ

すごく簡単!

  • Web Pageを作る感覚で、普通にDesktop Applicationが作れる。
  • 環境設定に時間がかからないのもメリット
    • 以前のHadoopの時を考えたら…
    • 特にWindowsでも簡単にできるのが嬉い。

Creatorとしての喜び

  • こうやって簡単にアプリを作れるから、創作意欲が沸く。
  • 自分に必要な物は、自分で作ってみよう!

参考

32
53
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
53