node-webkitでWindows向けアプリケーションのアイコンを変更する
Icons に書いてある。
Resource Hackerで書き換える。
これだとWindowsのパッケージングが自動化出来ないのでアレ。
node-webkitで作ったアプリをWindows向けにパッケージングする
使う人の環境がWindowsだけど、一応Macも作っとく。
Gruntfile.coffeeはこんな感じ。appディレクトリに集めたファイルをパッケージング。
module.exports = (grunt) -> pkg = grunt.file.readJSON 'package.json' ......... grunt.initConfig ......... nodewebkit: options: mac: true win: true app_name: pkg.name app_version: pkg.version build_dir: 'build' src: [ 'app/**/*' ] ......... grunt.loadNpmTasks('grunt-node-webkit-builder') grunt.registerTask 'default', ['slim', 'concat', 'copy', 'nodewebkit']
便利。
node-webkit特有の問題にはまった
node-webkitでアプリを開発していて、node-webkitの環境ならでは?の問題にはまったのでメモ。
前提
% bower install eonasdan-bootstrap-datetimepicker --save
nodeのcontextではなくJavaScriptのcontextでの話。
アプリでbootstrap 3対応のdatetimepickerを使おうとしたら、読み込み時点でnot defineでエラー。
読み込まれているJSは公式に書いてあるとおりの下記JSを結合したもの*1
<script type="text/javascript" src="/bower_components/jquery/dist/jquery.min.js"></script> <script type="text/javascript" src="/bower_components/moment/min/moment-with-langs.min.js"></script> <script type="text/javascript" src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <script type="text/javascript" src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js"></script>
エラーの箇所はdatetimepickerが依存するmomentがあるか確認している部分。
//bootstrap-datetimepicker.js ; (function (factory) { if (typeof define === 'function' && define.amd) { // AMD is used - Register as an anonymous module. define(['jquery', 'moment'], factory); } else { // AMD is not used - Attempt to fetch dependencies from scope. if (!jQuery) { throw 'bootstrap-datetimepicker requires jQuery to be loaded first'; } else if (!moment) { // ←ここでエラー throw 'bootstrap-datetimepicker requires moment.js to be loaded first'; } else { factory(jQuery, moment); } } }
breakpointをしかけて確認。デバッグはWebStormで。グローバル空間に確かにmomentがいない模様。
moment.jsのコードを確認。requirejsなどをつかっていないので、一番下、else節のmakeGlobalが呼ばれる。
//moment.js // CommonJS module is defined if (hasModule) { module.exports = moment; } else if (typeof define === "function" && define.amd) { define("moment", function (require, exports, module) { if (module.config && module.config() && module.config().noGlobal === true) { // release the global variable globalScope.moment = oldGlobalMoment; } return moment; }); makeGlobal(true); } else { makeGlobal(); //←これが呼ばれる }
makeGlobalを確認。
globalScope変数にmomentを追加してる。
//moment.js function makeGlobal(shouldDeprecate) { /*global ender:false */ if (typeof ender !== 'undefined') { return; } oldGlobalMoment = globalScope.moment; if (shouldDeprecate) { globalScope.moment = deprecate( "Accessing Moment through the global scope is " + "deprecated, and will be removed in an upcoming " + "release.", moment); } else { globalScope.moment = moment;//←コレ } }
globalScopeを確認。 nodeならglobal、ブラウザ空間ならthisなので、windowと読める。
//moment.js var moment, VERSION = "2.6.0", // the global-scope this is NOT the global object in Node.js globalScope = typeof global !== 'undefined' ? global : this, oldGlobalMoment, round = Math.round, i, ........
コード的にはwindowにmomentが定義されるように思える・・。もう一回じっくりデバッグ。
Window下にglobalがいるので、Window.global.momentになって、window.momentではなかった。
グローバルはwindowだと思っていたがWindowだった。
momentの読み込みとdatetimepickerの読み込みの間にworkaroundを入れて対処。
window.moment = global.moment;
https://github.com/rogerwang/node-webkit/wiki/Window
Window is a wrapper of DOM's window object, it has extended operations and can receive various window events.
Wikiをよく読みましょう、思い込みを捨てましょうという話。
*1:他にも読み込んでいるが関係ないので省略
Node.jsの管理をhomebrewからnodebrewに変更
npmでglobalにインストールしたtypescriptとbowerを削除。
% npm uninstall -g bower % npm uninstall -g typescript
npmを削除
% npm uninstall -g npm
Node.jsを削除
brew uninstall node
nodebrewをインストール
% curl -L git.io/nodebrew | perl - setup
.zshrcにPATHを追加
export PATH=$HOME/.nodebrew/current/bin:$PATH
読み込み直し
% source ~/.zshrc
Node.jsをインストール
% nodebrew install stable
標準で使用するNode.jsのバージョン指定
% nodebrew use stable
bowerとtypescriptをグローバルにインストール
% npm install -g bower % npm install -g typescript
参考
TypeScriptリファレンス Ver.1.0対応のサンプルコードで--noImplicitAnyをつけて(略
備忘。TypeScriptリファレンス Ver.1.0対応のコールシグネチャのリスト6.56で--noImplicitAnyをつけてる場合。
function db(operation: string, key: string, value?: any): any { if (!db.data) { db.data = {}; } var data = db.data; var oldValue: any; //追加 if (operation === "update") { oldValue = data[key]; data[key] = value; return oldValue; } else if (operation === "read") { return data[key]; } } module db { export var data: any; export function update(key: string, value: any) { //追加 return db("update", key, value); } export function read(key: string) { //追加 return db("read",key); } } db.update("str", "string"); console.log(db.read("str")); db("update", "str", "文字列"); console.log(db("read", "str"));
TypeScriptリファレンス Ver1.0対応 4-4 Enumのサンプルコードで--noiImplicitAnyをつけてるとコンパイルエラー
TypeScriptリファレンス Ver.1.0対応の4-4 Enumのサンプルコードでtscに--noImplicitAnyをつけてるとコンパイルエラー。
enum Suit { Spade, Heart, Club, Diamond } var s1: Suit = Suit.Spade; var s2: number = s1; var s3: string = Suit[s2]; var s4: number = Suit[s3]; //↑ error TS7017: Index signature of object type implicitly has an 'any' type. console.log(s1, s2, s3, s4);
通るように。
var s4: number = Suit.Spade; //又は var s4: number = Suit["Spade"];
備忘録。enumが吐き出すjsのメモ
var Suit; (function (Suit) { Suit[Suit["Spade"] = 0] = "Spade"; Suit[Suit["Heart"] = 1] = "Heart"; Suit[Suit["Club"] = 2] = "Club"; Suit[Suit["Diamond"] = 3] = "Diamond"; })(Suit || (Suit = {})); //なのでSuitはこうなる。 {0: "Spade", 1: "Heart", 2: "Club", 3: "Diamond", Spade: 0, Heart: 1, Club: 2, Diamond: 3}