今天晚上受邀至朋友舉辦的 Meetup 分享。
分享我如何將一個現成的 business idea (繪禮物 http://www.giftpaint.com) 轉化為網路服務,並且建置出來。
由於此 Meetup 與 coding 有關,所以會簡單帶過 Laravel framework。
希望能讓一些想學程式或者有點子卻不知道如何開始的人有幫助。
2016年12月30日 星期五
2016年11月17日 星期四
Laravel 5.2 發送內部 Request 來呼叫現成 AJAX API
如果我在 Laravel Controller 內部,想要 call 另外一個現成的 AJAX 做事怎麼辦呢?
在這裡我們可以看到
我們可以利用內部 Routing 機制,不用真的發 HTTP request,就可以達到類似的效果了。
以下這段程式情境如下:
- 我們的顯示購物車頁面,有一個參數是欲加入的商品代號。如果這個參數有值,會先將此商品加入購物車以後才出現商品清單畫面,使用者從這個畫面開始結帳流程。
- 在此之前,我們的使用者是利用一隻 AJAX API 來將商品加入購物車。
public function getCheckoutForm(Request $request) {
$productId = $request->input('product_id', null);
if(!empty($productId)) {
// http://stackoverflow.com/questions/16597420/how-can-i-access-query-string-parameters-for-requests-ive-manually-dispatched-i
$rr = Request::create(route('post.ajax.addcart'), 'POST', ['product_id' => $productId, '_token' => csrf_token()]);
// Store the original input of the request and then replace the input with your request instances input.
$originalInput = $request->input();
$request->replace($rr->input());
$response = Route::dispatch($rr);
$request->replace($originalInput);
}
// getCheckoutForm() business logic
}
在這裡我們可以看到
- 我們先建立新的 Request 物件 $rr。
- 然後備份目前的 request input
- 將目前的 request input 置換成 $rr 的 input
- 利用 Route::dispatch() 產生 Request call
- 呼叫完畢以後再把目前 request input 換回來
參考
2016年8月17日 星期三
做行銷的人與做產品人的糾結
最近聽了一些故事,看了一些網站,然後產生心裡的惡魔:做行銷的人與做產品人的糾結。
這些小網站都是行銷高手創立的,內容是他們的武器,他們攻的是客人的「心」,再把自己的(銷售)能力包裝成產品賣給別人,然後賺了很多錢(至少自己夠用)。
天平的另外一端是工程師,講求用最好的方式高深的技術,創造一個有高度彈性,碰到颶風也不會倒的系統。
行銷成精的人,你只要給他wordpress的頁面可以打打字貼連結,每個頁面有獨立網址,他們就可以開始做生意。
當他們碰到一個新想法的時候,心裡想的是,客群是誰,我的文案要下什麼套路能對顧客講故事,讓他越看越深最後買單。
做系統做到精的人(含PM, SA, RD, QA, QE),碰到新想法的時候,開始分析需求切功能,然後開始想像這些功能可以如何被使用,這個系統會不會被破解,流量大撐不撐的住,做不做的出來。
行銷人看做系統的人:賺錢不用這麼複雜,能吸引客人的東西沒半樣,給我wordpress就好。
做系統的人看行銷人員:我做的系統功能這麼強大,居然只用那1%功能,到底懂不懂呀?
懂行銷的人懂市場,知道客戶在哪裡以及他們需要什麼。Wordpress 雖有彈性,但是其中很多小環節都是人工處理,例如產生 Email 名單並貼到另外一個系統,或是訂單細節與客戶電話來來往往討論,一旦需要將業務規模化(更大量)就會需要更多這些事務性的人,隨著人員擴張,公司會越來越沒有效率(人需要組織管理,另外每個人都是特別的,不可能請到一模一樣的人),最後公司隨著人員膨脹,而這些人員都在做事務性工作,對公司並沒有增額的產出,也因此沒辦法獲得更多資源做下一輪投資。
「系統」存在的目的是為了「規模化」,要達到規模化必須要自動化,以防止上述事務性人員擴張的問題。將已經市場驗證完成的商業模式,找出行為與規格,創建出系統自動化,或者讓失誤的機率降低以減少成本。到了這個階段,就變成針對該商業模式客製化系統的過程 (無論是擺脫 Wordpress 重新寫一個,或是找技術人才寫 Wordpress 外掛)。
要規模化,隨之而來的就是限制(做法與規格),才能產生流程與系統。
有了系統的幫忙,原有的人力可以空出來,搜尋下一個機會,等確認了以後,再轉換成系統,如此往復,系統價值不斷的累積,人力的成本卻沒有等比例增加,公司的價值就產生了正向的循環。
這兩種人活在不同的世界,做事方法也截然不同,甚至對方的長處可能是自己用不上的。但我想最重要的是互相理解並合作,或許用另外一種方式試試看,能獲得不一樣的收獲。
這些小網站都是行銷高手創立的,內容是他們的武器,他們攻的是客人的「心」,再把自己的(銷售)能力包裝成產品賣給別人,然後賺了很多錢(至少自己夠用)。
天平的另外一端是工程師,講求用最好的方式高深的技術,創造一個有高度彈性,碰到颶風也不會倒的系統。
做行銷的人
行銷成精的人,你只要給他wordpress的頁面可以打打字貼連結,每個頁面有獨立網址,他們就可以開始做生意。
當他們碰到一個新想法的時候,心裡想的是,客群是誰,我的文案要下什麼套路能對顧客講故事,讓他越看越深最後買單。
做產品的人
做系統做到精的人(含PM, SA, RD, QA, QE),碰到新想法的時候,開始分析需求切功能,然後開始想像這些功能可以如何被使用,這個系統會不會被破解,流量大撐不撐的住,做不做的出來。
兩種人互看
行銷人看做系統的人:賺錢不用這麼複雜,能吸引客人的東西沒半樣,給我wordpress就好。
做系統的人看行銷人員:我做的系統功能這麼強大,居然只用那1%功能,到底懂不懂呀?
其實我們兩種人都需要
懂行銷的人懂市場,知道客戶在哪裡以及他們需要什麼。Wordpress 雖有彈性,但是其中很多小環節都是人工處理,例如產生 Email 名單並貼到另外一個系統,或是訂單細節與客戶電話來來往往討論,一旦需要將業務規模化(更大量)就會需要更多這些事務性的人,隨著人員擴張,公司會越來越沒有效率(人需要組織管理,另外每個人都是特別的,不可能請到一模一樣的人),最後公司隨著人員膨脹,而這些人員都在做事務性工作,對公司並沒有增額的產出,也因此沒辦法獲得更多資源做下一輪投資。
「系統」存在的目的是為了「規模化」,要達到規模化必須要自動化,以防止上述事務性人員擴張的問題。將已經市場驗證完成的商業模式,找出行為與規格,創建出系統自動化,或者讓失誤的機率降低以減少成本。到了這個階段,就變成針對該商業模式客製化系統的過程 (無論是擺脫 Wordpress 重新寫一個,或是找技術人才寫 Wordpress 外掛)。
要規模化,隨之而來的就是限制(做法與規格),才能產生流程與系統。
有了系統的幫忙,原有的人力可以空出來,搜尋下一個機會,等確認了以後,再轉換成系統,如此往復,系統價值不斷的累積,人力的成本卻沒有等比例增加,公司的價值就產生了正向的循環。
這兩種人活在不同的世界,做事方法也截然不同,甚至對方的長處可能是自己用不上的。但我想最重要的是互相理解並合作,或許用另外一種方式試試看,能獲得不一樣的收獲。
2016年7月6日 星期三
在 Shell 下 pretty print JSON
Python
$ python -m json.tool some.json
或
$ cat some.json | python -m json.tool
PHP json_decode
上面 python 的方法只是純排版,但是如果 unicode 已經被編碼為 \xxxxx 模式的話,不會幫你 unescape。所以又想了這一招
在 .bashrc 或 .bash_profile 加入
alias pretty_json='php -r "\$json = file_get_contents(\"php://stdin\", \"r\"); \$d=json_decode(\$json); echo json_encode(\$d, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;"'
之後只要下
$ cat some.json | pretty_json
2016年2月13日 星期六
從大公司到創業小公司:尋找主題的心路歷程
2015 年九月,我離開了待了 3 年又 11 個月的 Yahoo ,跟著前老闆創業的夢想,加入了他的公司,成為第一號員工。
五個月過去了,雖然目前還沒有什麼說得上的進展,但是中間心路歷程還是紀錄一下,留給未來的我。
大公司和小公司果然不一樣。
在大公司有做不完的案子,業務、營運、企劃都有一大堆讓產品更好想法、一大堆新功能、一大堆客戶的建議,希望工程部門能夠接受他們的想法幫忙把東西做出來。但是工程師就這麼些人,這樣海量的專案不可能做得完,所以要有人篩選。所謂篩選,其實是無盡的會議,來評估每一個案子未來效益如何,機會成本如何,值不值得捨棄其他的案子現在就做下去。
未來的事情尚未發生,沒有人知道東西做出來是不是真的可以達到指標,我們只能在平行時空裡面用最嚴謹的邏輯持續辯證,排除可以看得到的問題。再加上部門多人多意見多,團隊合作就是妥協的藝術。但是產品一旦妥協變更需求,就又跟當初想更不一樣,至於最後達成的成效,就只能求神拜佛,上線前一天就跟選舉投票前一天一樣,民調都只是參考用,希望投票當下選民能把票投給我們。
但無論大公司小公司、有雄厚資本的外商、或是純自幹的個人 SOHO 族,其實這就是產品誕生的過程,產品尚未存在這個世界上,在還沒做出來以前沒有人知道結果,我們所能做的就是上線前準備到最好。
但是天底下哪裡有這麼好的事情,東西初次做出來就是使用者要的。如果人們能夠通靈知道使用者心理在想什麼,要做到什麼程度他們才會願意掏錢,那必定存在一間公司永遠賺錢,獲利不會衰退,可惜世界上沒有不會衰退公司。身為人類我們只能從種種數據中看到使用者的反應如何,是不是有符合使用者的心但目前只是轉換率還不高,如何用方法提升使用者的轉換率於是再下去修改下一個版本。
好的產品就在這麼一次又一次的修改當中越來越好,最後達到 MVP,出現神奇的瞬間,服務就起來了。
如果你在心態上只是要當一個安穩的工程師,那麼上述一切就會與你無關。而這是在大公司的環境裡面,被無數多的案子雜事的壓榨凌虐之下,極有可能萌生心理上的小確幸。
到了小公司,什麼都不一樣了。
以前大公司的案子你都玩不起,我們公司就這麼兩三個人,資金是燒老闆自己的儲蓄,可能案子沒做完,資金就燒完了。
我們也沒有操作一個產品上線並且真正面對客戶的經驗,也不懂得行銷。作為一個工程師,學習工具對我們來說相對容易,甚至我們可以把工具再自幹一個出來,但是就是不知道怎麼用,這就是悲慘的地方。
最後,你要做什麼主題?再也不會像以前一樣有案子排隊硬擠給你。要自己想什麼東西有機會,什麼東西可以進去做,做完了以後拿不拿的到錢,可以讓公司活得更久一點,這個東西可以活多久?這種感覺像是雖然你是工程師,但你知道現在的資金夠你幾個月可以活,你投資未來幾個月自己的時間去創造了某個東西,是不是可以養活接下來的你。而以前我們的基準是去想產品利用這個工法是否可以準時上線,會不會只有這麼短的時間結果下不了班。
但是這並不代表你會永無止境的加班,反而這能讓你更有效的投資你的時間。你能計算出做這件事情報酬會是什麼,時程上的成本會是多少,風險能不能承擔。能了解自己投入的每分鐘的產值很有一種踏實感,因此也更能使用自己的步調前進,壓力也不會這麼大。
當然,這是人少的時候才會需要思考這些事情。或許人一開始便多就會變回以前大公司的模式,但是公司文化也會影響整個開發的思考模式、節奏與感覺。
我和我老闆都是大公司來的,一開始我們身上都帶有那種大公司處理事情的態度以及想法。但很快的我們發現憑我們兩個人玩不起這樣規模的專案。於是我們從小網站開始做,驗證自己的想法與觀點,學習最新以及開源的技術,行銷的技巧,怎麼做 landing page 下下廣告之類的。用以前的模式比喻,就是拿真的錢去玩 Hackday,但是這個想法做出來以後必須要能夠讓公司有機會活得更久。
在這過程裡面,我有看到老闆思維上的轉變,少了那麼一點大公司的氣息,對產品的觀點卻更敏銳了。
我們團隊目前還在尋找想法和方向,有的時候閒聊想到一個新的想法就會開始進行辯論,討論這個想法有沒有機會幫公司賺錢,一辯論就兩三個小時過去了。
這一兩個月,我也早早下班,私底下想了幾個點子做了 Hack,一個是用 PHP 去爬 PTT 看板串接 Slack 做個爆掛通知,這是我從很小的時候就想做了,只是我發現繼續做下去就很像鄉民晚報了;另一個是之前同事的一個想法,把 APP 改成用 Responsive Web 目的是幫他趕快找到心儀的對象。
在做這兩件事情的時候,讓我更不得不去想一個兩三人的新創公司,到底該做什麼主題好呢?做什麼主題會有機會呢?什麼主題是值得投入自己兩年三年的時間去做的呢?如果讀者你也有機會加入這樣超級新的新創公司或者要當老闆不妨參考看看。
如果還不知道要做什麼,可以去學習或試用最新的科技或商業模式。新科技和商業模式其實都是工具,他們比舊有的工具會更有效率。尋找看看你擅長的領域,這些新科技或商業模式有沒有派上用場的地方,如果能派得上用場,而且新的解法比原本的模式有更好的效益,而且沒有人做過,恭喜你,趕快去做吧!
為了符合這一項,你必須要砍掉產品多餘的部分,只留下核心。趕快做好最小的產品丟到市場上,觀察使用者的使用,蒐集使用者的意見,持續改進你的產品,直到使用者買單。
所謂新的東西,有可能是從來不存在世界上的東西,或者類似的東西或服務已經有了,但是你融入新的做法,讓商業模式更容易規模化。
做熟悉的領域可以節省比較多的時間,也比較知道那裏是地雷,缺點是容易深陷舊思維裡面無法跳脫框架,於是做不出新的東西。也有可能過去認為的地雷其實不是地雷,但是你就是被舊思維限制住了。
做不熟悉的領域很多都要學要實驗要嘗試,所以會花很多時間,因為不知道哪裡是地雷,所以都很勇敢,大不了踩到地雷爆炸了,早點收收換下一個主題不會賠太多。
朋友能夠提供寶貴的經驗,即使是陌生的市場,如果有個朋友可以當個顧問,可以避免走很多冤枉路。如果能夠異業結盟做出雙贏局面,那就更好了。
一個產品的價值在於解決的問題有多少價值,當這個產品解決的問題有價值,自然就會有人用。
當我們缺錢的時候,自然會陷入會計的精算,斤斤計較。這樣的方式結果就是無法解決任何問題帶來價值,唯一能做的就是成本上的精簡。如果是一個新產品,你會得到成本太高無法進行的結果。我們如果確保我們投入的資源不高於要解決的問題的價值,這樣就不會虧損太嚴重。
解決問題的本身是在幫助別人,當大家的問題都漸漸被解決了,社會也就變好了。
以上是我目前想到的,希望大家包含我們自己都能早點找到目標與方向。
五個月過去了,雖然目前還沒有什麼說得上的進展,但是中間心路歷程還是紀錄一下,留給未來的我。
大公司的開發模式
大公司和小公司果然不一樣。
在大公司有做不完的案子,業務、營運、企劃都有一大堆讓產品更好想法、一大堆新功能、一大堆客戶的建議,希望工程部門能夠接受他們的想法幫忙把東西做出來。但是工程師就這麼些人,這樣海量的專案不可能做得完,所以要有人篩選。所謂篩選,其實是無盡的會議,來評估每一個案子未來效益如何,機會成本如何,值不值得捨棄其他的案子現在就做下去。
未來的事情尚未發生,沒有人知道東西做出來是不是真的可以達到指標,我們只能在平行時空裡面用最嚴謹的邏輯持續辯證,排除可以看得到的問題。再加上部門多人多意見多,團隊合作就是妥協的藝術。但是產品一旦妥協變更需求,就又跟當初想更不一樣,至於最後達成的成效,就只能求神拜佛,上線前一天就跟選舉投票前一天一樣,民調都只是參考用,希望投票當下選民能把票投給我們。
但無論大公司小公司、有雄厚資本的外商、或是純自幹的個人 SOHO 族,其實這就是產品誕生的過程,產品尚未存在這個世界上,在還沒做出來以前沒有人知道結果,我們所能做的就是上線前準備到最好。
但是天底下哪裡有這麼好的事情,東西初次做出來就是使用者要的。如果人們能夠通靈知道使用者心理在想什麼,要做到什麼程度他們才會願意掏錢,那必定存在一間公司永遠賺錢,獲利不會衰退,可惜世界上沒有不會衰退公司。身為人類我們只能從種種數據中看到使用者的反應如何,是不是有符合使用者的心但目前只是轉換率還不高,如何用方法提升使用者的轉換率於是再下去修改下一個版本。
好的產品就在這麼一次又一次的修改當中越來越好,最後達到 MVP,出現神奇的瞬間,服務就起來了。
如果你在心態上只是要當一個安穩的工程師,那麼上述一切就會與你無關。而這是在大公司的環境裡面,被無數多的案子雜事的壓榨凌虐之下,極有可能萌生心理上的小確幸。
小團隊的開發模式
到了小公司,什麼都不一樣了。
以前大公司的案子你都玩不起,我們公司就這麼兩三個人,資金是燒老闆自己的儲蓄,可能案子沒做完,資金就燒完了。
我們也沒有操作一個產品上線並且真正面對客戶的經驗,也不懂得行銷。作為一個工程師,學習工具對我們來說相對容易,甚至我們可以把工具再自幹一個出來,但是就是不知道怎麼用,這就是悲慘的地方。
最後,你要做什麼主題?再也不會像以前一樣有案子排隊硬擠給你。要自己想什麼東西有機會,什麼東西可以進去做,做完了以後拿不拿的到錢,可以讓公司活得更久一點,這個東西可以活多久?這種感覺像是雖然你是工程師,但你知道現在的資金夠你幾個月可以活,你投資未來幾個月自己的時間去創造了某個東西,是不是可以養活接下來的你。而以前我們的基準是去想產品利用這個工法是否可以準時上線,會不會只有這麼短的時間結果下不了班。
但是這並不代表你會永無止境的加班,反而這能讓你更有效的投資你的時間。你能計算出做這件事情報酬會是什麼,時程上的成本會是多少,風險能不能承擔。能了解自己投入的每分鐘的產值很有一種踏實感,因此也更能使用自己的步調前進,壓力也不會這麼大。
當然,這是人少的時候才會需要思考這些事情。或許人一開始便多就會變回以前大公司的模式,但是公司文化也會影響整個開發的思考模式、節奏與感覺。
我和我老闆都是大公司來的,一開始我們身上都帶有那種大公司處理事情的態度以及想法。但很快的我們發現憑我們兩個人玩不起這樣規模的專案。於是我們從小網站開始做,驗證自己的想法與觀點,學習最新以及開源的技術,行銷的技巧,怎麼做 landing page 下下廣告之類的。用以前的模式比喻,就是拿真的錢去玩 Hackday,但是這個想法做出來以後必須要能夠讓公司有機會活得更久。
在這過程裡面,我有看到老闆思維上的轉變,少了那麼一點大公司的氣息,對產品的觀點卻更敏銳了。
挑選主題
我們團隊目前還在尋找想法和方向,有的時候閒聊想到一個新的想法就會開始進行辯論,討論這個想法有沒有機會幫公司賺錢,一辯論就兩三個小時過去了。
這一兩個月,我也早早下班,私底下想了幾個點子做了 Hack,一個是用 PHP 去爬 PTT 看板串接 Slack 做個爆掛通知,這是我從很小的時候就想做了,只是我發現繼續做下去就很像鄉民晚報了;另一個是之前同事的一個想法,把 APP 改成用 Responsive Web 目的是幫他趕快找到心儀的對象。
在做這兩件事情的時候,讓我更不得不去想一個兩三人的新創公司,到底該做什麼主題好呢?做什麼主題會有機會呢?什麼主題是值得投入自己兩年三年的時間去做的呢?如果讀者你也有機會加入這樣超級新的新創公司或者要當老闆不妨參考看看。
1. 擁抱新的東西與觀念。
如果還不知道要做什麼,可以去學習或試用最新的科技或商業模式。新科技和商業模式其實都是工具,他們比舊有的工具會更有效率。尋找看看你擅長的領域,這些新科技或商業模式有沒有派上用場的地方,如果能派得上用場,而且新的解法比原本的模式有更好的效益,而且沒有人做過,恭喜你,趕快去做吧!
2. 不要一開始做太大的東西,2 ~ 3 個人左右花幾個月時間做得出來的東西,這才是大小剛好的想法。
為了符合這一項,你必須要砍掉產品多餘的部分,只留下核心。趕快做好最小的產品丟到市場上,觀察使用者的使用,蒐集使用者的意見,持續改進你的產品,直到使用者買單。
3. 做新的東西。
所謂新的東西,有可能是從來不存在世界上的東西,或者類似的東西或服務已經有了,但是你融入新的做法,讓商業模式更容易規模化。
4. 熟悉與不熟悉的領域。
做熟悉的領域可以節省比較多的時間,也比較知道那裏是地雷,缺點是容易深陷舊思維裡面無法跳脫框架,於是做不出新的東西。也有可能過去認為的地雷其實不是地雷,但是你就是被舊思維限制住了。
做不熟悉的領域很多都要學要實驗要嘗試,所以會花很多時間,因為不知道哪裡是地雷,所以都很勇敢,大不了踩到地雷爆炸了,早點收收換下一個主題不會賠太多。
5. 做朋友可以幫助你的事情。
朋友能夠提供寶貴的經驗,即使是陌生的市場,如果有個朋友可以當個顧問,可以避免走很多冤枉路。如果能夠異業結盟做出雙贏局面,那就更好了。
6. 幫助別人,讓社會更好。
一個產品的價值在於解決的問題有多少價值,當這個產品解決的問題有價值,自然就會有人用。
當我們缺錢的時候,自然會陷入會計的精算,斤斤計較。這樣的方式結果就是無法解決任何問題帶來價值,唯一能做的就是成本上的精簡。如果是一個新產品,你會得到成本太高無法進行的結果。我們如果確保我們投入的資源不高於要解決的問題的價值,這樣就不會虧損太嚴重。
解決問題的本身是在幫助別人,當大家的問題都漸漸被解決了,社會也就變好了。
以上是我目前想到的,希望大家包含我們自己都能早點找到目標與方向。
2016年1月12日 星期二
在 Electron 裡使用 node_sqlite3
這幾天工作需要,所以需要在我們的 Electron 專案中使用 sqlite3,但是當程式跑起來需要用到 sqlite 的時候,卻發生找不到 module 的情況。
錯誤訊息如下:
這是因為 electron 嘗試要去找 node_modules\sqlite3\lib\binding\node-v47-win32-x64 但是我們安裝下來的 sqlite 卻只有 node_modules\sqlite3\lib\binding\node-v46-win32-x64,因此就找不到 module 摟。
後來找到了這一篇文章,照著的說明就可以成功的在 windows 以及 mac 上重新編譯 node_sqlite3 正常執行了。以下將步驟節錄在此。
依照 electron 的文件,node-gyp 可以幫助我們重新編譯 module。
如果是 windows ,要記得安裝編譯器,可以參考這篇文章 在 windows 安裝 electron-prebuilt。
主要的指令為
第三個是 target_platform, 第四個是 arch
把他合成一行加入我們的 package.json 的 script ,變成
就可以
錯誤訊息如下:
Error: Cannot find module 'C:\Users\hialan\electron-app\node_modules\
sqlite3\lib\binding\node-v47-win32-x64\node_sqlite3.node'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:289:25)
這是因為 electron 嘗試要去找 node_modules\sqlite3\lib\binding\node-v47-win32-x64 但是我們安裝下來的 sqlite 卻只有 node_modules\sqlite3\lib\binding\node-v46-win32-x64,因此就找不到 module 摟。
後來找到了這一篇文章,照著的說明就可以成功的在 windows 以及 mac 上重新編譯 node_sqlite3 正常執行了。以下將步驟節錄在此。
依照 electron 的文件,node-gyp 可以幫助我們重新編譯 module。
如果是 windows ,要記得安裝編譯器,可以參考這篇文章 在 windows 安裝 electron-prebuilt。
主要的指令為
$ cd node_modules/sqlite3 && npm run prepublish
$ node-gyp configure --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-win32-x64
$ node-gyp rebuild --target=0.36.2 --arch=x64 --target_platform=win32 --dist-url=https://atom.io/download/atom-shell --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-win32-x64
- --target 是我們 electron 的版本,目前我用的是 0.36.2
- 可以用 ./node_modules/.bin/electron -v 看到你的版本
- --module_path 是 electron 要找的路徑
- --target_platform 是你的作業系統
- Windows 為 win32
- Mac 為 darwin
- --arch 為你的 CPU 架構
$ npm config get user-agent
npm/2.14.12 node/v4.2.4 win32 x64
第三個是 target_platform, 第四個是 arch
把他合成一行加入我們的 package.json 的 script ,變成
"scripts": {
"rebuild-sqlite3-win32": "cd node_modules/sqlite3 && npm run prepublish && node-gyp configure --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-win32-x64 && node-gyp rebuild --target=0.36.2 --arch=x64 --target_platform=win32 --dist-url=https://atom.io/download/atom-shell --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-win32-x64",
"rebuild-sqlite3-darwin": "cd node_modules/sqlite3 && npm run prepublish && node-gyp configure --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-darwin-x64 && node-gyp rebuild --target=0.36.2 --arch=x64 --target_platform=darwin --dist-url=https://atom.io/download/atom-shell --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-darwin-x64"
}
就可以
- 編譯 windows: npm run rebuild-sqlite3-win32
- 編譯 mac: npm run rebuild-sqlite3-darwin
2016年1月10日 星期日
[教學] Electron + React: 使用 JavaScript 建立跨平台桌面應用程式
平常建立桌機用的視窗應用程式,我們都是用 C++, VB6 或是 C#。但是現在的產品,除了要提供網頁版,手機 APP,Windows / Mac 桌面的客戶端,不然使用者會很不方便。但是使用的語言不同,我們便需要使用不同的技術重複寫好多次。
Github 推出了 Electron 這個開源的專案,它的出現讓使用 JavaScript 來寫桌面應用程式變為可能。Electron 可以視為使用 io.js 控制的修改過的瀏覽器,利用網頁技術來做為畫面的輸出,但同時又可以存取本機資源 (沒有 sendbox)。
如此一來,網頁和桌面應用程式就沒有任何差別,只要瀏覽器可以跑的地方我們的程式幾乎都可以執行 (取決於是否用到特殊的 extension)。而因為是用網頁做為視窗畫面的輸出,所有網頁現成的工具如 jQuery, React, bootstrap 等,也馬上可以用在桌面應用程式上了!
目前 Github 的 Atom 編輯器,Slack 桌面端,微軟的 Visual Studio Code 都是建構在 Electron 上面。
Electron 是 Github 推出的 Atom 編輯器的底層,也是 Github 的一個開源項目。
我們可以將 Electron 視為是修改過的 Chromium 瀏覽器提供 Node.js API (Chromium Content API),讓我們可以寫 JavaScript 來控制視窗的行為,而 Electron 也是修改自 Chromium multi-process 架構。以下投影片來自 Electron × React — 前端開發者高速跨界桌面開發 。
他每開啟一個視窗,可以想像成開啟 Chrome 瀏覽器的一個 tab,一個 tab 是一個獨立的 process。每一個視窗都可以有自己的 WebKit,有自己的 DOM,執行自己的 JavaScript 來處理畫面,因此我們可以在這裡面套用 React 方便我們做頁面的互動。
一個應用程式可能會有很多個視窗,每個視窗都是獨立的 process,因此在 Electron 裡面,還會有一個幕後的 process 稱為 main process 來管理這些視窗 process,視窗 process 又叫做 renderer process。
接下來,我們來撰寫一個只有一個視窗的應用程式,並且作為範例。
我們應用程式的檔案結構如下:
package.json
註:如果 package.json 沒有指定 main 欄位,Electron 預設會使用 index.js 這個檔案。
main.js 是用來建立視窗,處理系統事件。我們範例的 main.js 如下:
main.js
而 app/mainWindow.html 是你想要在視窗中顯示的內容
app/mainWindow.html
安裝套件
如果有使用 Windows 的使用者碰到困難,可以參考我之前寫的這篇:
執行
首先,將需要的套件加進來。以下是我們的 package.json 檔案。
package.json
需要的工具說明如下:
我們的 webpack設定檔 webpack.config.js 如下:
webpack.config.js
webpack 的使用不在本文範圍內,如果不熟的人可以去搜尋教學文件。
這裡我們做重點說明:
app/mainWindow.jsx
我們的範例是畫面中會有一個 textbox,在 textbox 輸入任何字會同步顯示在頁面上。
而 renderer 用到的 mainWindow.html 也要讀取新的 js 才會動喔。因此將 mainWindow.html 改為如下:
app/mainWindow.html
程式的部分就都完成了。
然後執行 Electron
為了方便未來容易使用,我們將指令放到 package.json
之後只需要
Github 推出了 Electron 這個開源的專案,它的出現讓使用 JavaScript 來寫桌面應用程式變為可能。Electron 可以視為使用 io.js 控制的修改過的瀏覽器,利用網頁技術來做為畫面的輸出,但同時又可以存取本機資源 (沒有 sendbox)。
如此一來,網頁和桌面應用程式就沒有任何差別,只要瀏覽器可以跑的地方我們的程式幾乎都可以執行 (取決於是否用到特殊的 extension)。而因為是用網頁做為視窗畫面的輸出,所有網頁現成的工具如 jQuery, React, bootstrap 等,也馬上可以用在桌面應用程式上了!
目前 Github 的 Atom 編輯器,Slack 桌面端,微軟的 Visual Studio Code 都是建構在 Electron 上面。
Electron 簡介
Electron 是 Github 推出的 Atom 編輯器的底層,也是 Github 的一個開源項目。
我們可以將 Electron 視為是修改過的 Chromium 瀏覽器提供 Node.js API (Chromium Content API),讓我們可以寫 JavaScript 來控制視窗的行為,而 Electron 也是修改自 Chromium multi-process 架構。以下投影片來自 Electron × React — 前端開發者高速跨界桌面開發 。
一個應用程式可能會有很多個視窗,每個視窗都是獨立的 process,因此在 Electron 裡面,還會有一個幕後的 process 稱為 main process 來管理這些視窗 process,視窗 process 又叫做 renderer process。
接下來,我們來撰寫一個只有一個視窗的應用程式,並且作為範例。
撰寫第一個 Electron + React 應用程式
Electron 基本操作
我們應用程式的檔案結構如下:
your-app/其中 package.json 格式跟 Node 模組的 package.json 一樣。其中最重要的是 main 欄位指定的檔案會成為 Electron 開始程式的檔案,這會啟動 main process。package.json 範例如下:
├── package.json
├── main.js
├── webpack.config.js
└── app/
├── mainWindow.html
└── mainWindow.jsx
package.json
{
"name": "electron-example",
"version": "0.1.0",
"main": "main.js"
}
我們也指定程式開啟的時候讀取同一層目錄的 main.js 這個檔案。註:如果 package.json 沒有指定 main 欄位,Electron 預設會使用 index.js 這個檔案。
main.js 是用來建立視窗,處理系統事件。我們範例的 main.js 如下:
main.js
'use strict';
const electron = require('electron');
// app: 控制應用程式生命週期的模組
const app = electron.app;
// BrowserWindow: 建立系統原生視窗 (native window) 的模組
const BrowserWindow = electron.BrowserWindow;
// 保留一個全域的物件關聯以避免 JavaScript 物件 GC 機制造成視窗自動關閉
let mainWindow;
function createWindow () {
// 建立 browser window
mainWindow = new BrowserWindow({width: 800, height: 600});
// 載入 mainWindow.html 作為畫面
mainWindow.loadURL('file://' + __dirname + '/app/mainWindow.html');
// 開啟開發者工具
mainWindow.webContents.openDevTools();
// 當 browser window 被關閉時,會送出 'closed' 訊號,並執行相關的 callback
mainWindow.on('closed', function() {
// 將此 window 物件解除關聯。
// 如果你的應用程式支援多視窗,通常會將這些物件存在一個陣列裡面。
// 現在就是刪除對應的視窗物件的時機。
mainWindow = null;
});
}
// 當 Electron 完成初始化並且可以開始建立視窗的時候,
// 會發送 'ready' 訊號,並執行對應的 callback
// 我們指定收到 'ready' 訊號時,執行 createWindow()
app.on('ready', createWindow);
// 當所有視窗都關閉時,結束應用程式 ( app.quit() )
app.on('window-all-closed', function () {
// OS X 的使用習慣是當所有視窗關閉的時候,上方的 menu bar 仍然維持開啟
// 此時應用程式還沒有完全關閉,除非使用者強制按 Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', function () {
// OS X 通常在應用程式已經起來了,但是所有視窗關閉的時候,還可以重新建立主視窗
if (mainWindow === null) {
createWindow();
}
});
而 app/mainWindow.html 是你想要在視窗中顯示的內容
app/mainWindow.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Electron-React app</title>
</head>
<body>
<div id="content">
Hello World!!
</div>
</body>
</html>
執行程式
安裝套件
$ npm install electron-prebuilt
如果有使用 Windows 的使用者碰到困難,可以參考我之前寫的這篇:
執行
$ ./node_modules/.bin/electron .
其中第二個路徑是 package.json 所在的目錄
加入 React
首先,將需要的套件加進來。以下是我們的 package.json 檔案。
package.json
{
"name": "electron-example",
"version": "0.1.0",
"main": "main.js",
"dependencies": {
"react": "^0.14.5",
"react-dom": "^0.14.5"
},
"devDependencies": {
"babel-core": "^6.3.26",
"babel-loader": "^6.2.1",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"electron-packager": "^5.2.0",
"electron-prebuilt": "^0.36.2",
"electron-rebuild": "^1.0.2",
"webpack": "^1.12.9",
"webpack-target-electron-renderer": "^0.3.0"
}
}
需要的工具說明如下:
- webpack: 我們將使用 webpack 幫助我們處理壓縮 js / css 等,我們只處理 renderer 用到的 js。
- babel: 我們將使用 JSX 來撰寫 React,他會幫助我們將 JSX 翻譯為 JavaScript ,中間透過 babel-loader 讓 webpack 執行 babel 進行翻譯。
- webpack-target-electron-renderer: 由於 webpack 會嘗試處理 require 語句,而其中 electron 是原生的 node extension,處理的時候會壞掉。這個 package 會告訴 webpack 跳過那些 electron extension。
我們的 webpack設定檔 webpack.config.js 如下:
webpack.config.js
var webpack = require('webpack');
var webpackTargetElectronRenderer = require('webpack-target-electron-renderer');
var config = {
entry: {
mainWindow: ['./app/mainWindow.jsx']
},
output: {
path: './app/built',
filename: '[name].js'
},
module: {
loaders: [
{
test: /\.jsx$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015'],
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015'],
}
}
]
},
plugins: [
new webpack.ExternalsPlugin('commonjs',['fs']),
new webpack.IgnorePlugin(/vertx/)
]
}
config.target = webpackTargetElectronRenderer(config);
module.exports = config;
webpack 的使用不在本文範圍內,如果不熟的人可以去搜尋教學文件。
這裡我們做重點說明:
- entry: 原則上一個 window 會有獨立的 js 檔案,因為我們目前只有 mainWindow 這個視窗,因此只有一個項目。
- output: 輸出的目錄會在 ./app/built/,並搭配 entry 欄位的名稱。因此上面這個範例輸出檔案為 ./app/built/mainWindow.js
app/mainWindow.jsx
'use strict';
import React from "react";
import ReactDOM from "react-dom";
var MainWindow = React.createClass({
getInitialState: function() {
return {
message: '',
};
},
handleTextChange: function(event) {
this.setState({message: event.target.value});
},
render: function() {
return (
<div>
Hello world!!
<hr/>
<input type="text" onChange={this.handleTextChange} />
<p><strong>你輸入的是</strong></p>
<p>
<span>{this.state.message}</span>
</p>
</div>
);
}
});
ReactDOM.render(
<MainWindow/>,
document.getElementById('content')
);
我們的範例是畫面中會有一個 textbox,在 textbox 輸入任何字會同步顯示在頁面上。
而 renderer 用到的 mainWindow.html 也要讀取新的 js 才會動喔。因此將 mainWindow.html 改為如下:
app/mainWindow.html
<html>
<head>
<title>My Electron-React app</title>
</head>
<body>
<div id="content">
</div>
</body>
<script src="./built/mainWindow.js"></script>
</html>
程式的部分就都完成了。
編譯與執行
執行 webpack 產生新的 app/built/mainWindow.js$ ./node_modules/.bin/webpack
然後執行 Electron
$ ./node_modules/.bin/electron .
為了方便未來容易使用,我們將指令放到 package.json
"scripts": {
"start": "./node_modules/.bin/electron ./",
"electron-rebuild": "./node_modules/.bin/electron-rebuild",
"webpack": "./node_modules/.bin/webpack"
}
之後只需要
$ npm run webpack && npm start
就行摟!相關文件
在 windows 中使用 npm 安裝 electron-prebuilt
今天嘗試在家裡的 windows 10 建立 electron 開發環境。
碰到了一些問題,紀錄一下。
安裝完畢後,進入命令列模式 (cmd.exe)
npm install [package name] --msvs_version=2015 )
執行
碰到了一些問題,紀錄一下。
需要安裝的程式
- 在 node.org 下載安裝程式 (我是用 4.2.4 LTS msi 版的)
- 會需要 python 2.x ,在這裡下載
- https://www.python.org/downloads/windows/
- 裝好以後要設定環境變數 PYTHON="C:\Python27\python.exe"
然後會需要編譯工具 (VCBuild.exe)Microsoft Build Tools 2015Windows 7 要另外安裝 .NET Framework 4.5.1- 2016/02/16 更正:請安裝 Visual Studio Community 2015
設定
安裝完畢後,進入命令列模式 (cmd.exe)
$ npm config set msvs_version 2015 --global
(這樣可以避免每次安裝都要下參數,例如npm install [package name] --msvs_version=2015 )
安裝
執行
$ npm install electron-prebuilt --save
應該就可以裝得起來了參考資料
訂閱:
文章 (Atom)