javascript
Dreamwear如何创建javascript_JavaScript 太糟糕,JVM 有妙招!
雖然 JavaScript 憑借其簡潔性、交互性等優(yōu)勢橫掃了各大編程語言榜單,但是一直以來,JavaScript?應用程序的工具鏈極其復雜,引發(fā)不少開發(fā)者吐槽,在此,我們是否有更好的解決方案將其替代?
接下來,本文中將分享幾個 JVM 的替代方案,希望對大家有所裨益。
作者 |?Renato Athaydes
譯者 | 彎月
責編 | 屠敏
出品 | CSDN(ID:CSDNnews)
以下為譯文:
我是一個主要從事后端的開發(fā)人員,但時不時地也需要做一些前端工作。因為有時在個人的項目中也會用到前端。
出于這個原因,我一直在遠遠地關注JavaScript的發(fā)展,但說實話我并不喜歡JavaScript的世界。
我最不喜歡的一點是專業(yè)JavaScript應用程序的工具鏈極其復雜。從前,你只需要寫幾行HTML,然后用瀏覽器打開(file:///home/me/index.htlm)即可,在添加動態(tài)效果的時候只需要鏈接一個簡單的JS文件,然后刷新一下頁面就好了,但是這樣的日子已經(jīng)一去不復返了。
JavaScript的MDN頁面(https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript)上展示的方法才是正確地使用HTML和JS的方法——不需要構建工具,也不需要框架。然而,很少有人聽得進去。如今,JavaScript的工具鏈包含了后端工具鏈所有的復雜性,有過之而無不及。甚至就在幾年前,工具鏈的許多部分和現(xiàn)在都是不同的!看看StackOverflow上一些問題的答案(https://stackoverflow.com/questions/1480186/what-is-in-your-javascript-toolchain),你會有覺得很有意思。
這個Pluralsight JS開發(fā)環(huán)境(https://github.com/coryhouse/javascript-development-environment)建議你利用32種工具來構建你的應用程序(例如babel、chai、cheerio、eslint、mocha、webpack ......)。
2016年的這篇文章(https://italonascimento.github.io/configuring-a-basic-environment-for-javascript-development/)中記錄了在Google和DuckDuckGo中搜索基本的JS開發(fā)環(huán)境時,搜索結果中包含哪些工具:
依賴管理工具(npm或yarn)
模塊打包(webpack或gulp、browserify、bower)
ES6編譯(babel)
任務自動化(npm腳本)
實時重新加載(live-server)
如果你按照上述文章的說明操作,那么最終會得到3個配置文件(npm、babel和webpack每個工具各一個),你需要通過嵌入到JSON配置文件的shell腳本來管理構建的過程,而且你的項目需要通過編譯和實時重新加載HTTP服務器才能運行。
我認為如果我需要編譯東西,那么至少我應該使用編譯器來檢查我的代碼!
那么為什么不試試TypeScript呢?!
于是,我按照這個教程(https://alligator.io/typescript/new-project/)所說,創(chuàng)建了一個TypeScript項目。
創(chuàng)建好后,除了前面提到的那些配置文件之外,我還多了兩個配置文件:tsconfig.json和tslint.json。
這一切太復雜了,所以Google創(chuàng)建了一個工具(Google TypeScript Style,簡稱GTS)來管理TypeScript配置。
我曾嘗試使用這個工具,然而,由于一些模塊相關的錯誤,瀏覽器拒絕運行我的JavaScript文件。我不知道在我使用的無數(shù)的工具中,哪一個可以解決這個問題,我快被這種錯綜復雜的工具逼瘋了,于是我決定尋找其他的解決方案!
在尋找的過程中,我發(fā)現(xiàn)了這篇優(yōu)秀的博客文章(https://itnext.io/you-might-not-need-a-build-toolchain-324edcef7f9a),文中宣稱你不需要構建工具鏈。
這篇文章表明,你可以使用像React這樣的現(xiàn)代工具,就不需要構建工具了!然而不幸的是,一旦你開始使用依賴項,而且你的應用程序包含幾百行以上的JavaScript代碼,那么這種方法就不太實用了。
我又回到了原點。
似乎無論我們做什么,構建/編譯步驟都是一個避無可避的惡魔,而且長期以來在后端的開發(fā)工作中,我們了解了如何使用優(yōu)秀的工具編寫大型應用程序,所以何妨在前端的開發(fā)中也嘗試使用這些工具呢?
畢竟,早在2011年,當我還在做Web開發(fā)時,就有人嘗試這種做法了……例如,2011年我曾使用過GWT(這是一個基于Java的Web工具包)……當然,8年后,基于Java的Web應用程序應該有了很多改進,不是嗎?
于是,我開始檢查都有哪些工具可以用。一個習慣了使用Java世界里優(yōu)秀的工具和良好生態(tài)系統(tǒng)的后端開發(fā)人員能否進軍前端的工作,而不至于被JS世界里的瘋狂湮沒呢?
就讓我們拭目以待吧!
方法
為了在本文中比較每一種備選的方案,我決定仿照上述我提到的博客文章“不需要構建工具鏈”,創(chuàng)建一個非常簡單的計數(shù)器應用程序。
作為參考,以下是用React(沒有JSX)編寫的應用程序的代碼。
我比較不同備選方案的方法非常簡單:
找一個入門教程,然后通過運行演示的應用程序,感受設置的難易程度。
檢查框架與Java開發(fā)人員期望的契合程度。
使用產(chǎn)品/框架提供的最基本的工具創(chuàng)建計數(shù)器應用程序。
衡量應用程序的大小、代碼行數(shù)和性能。
最后一個要點的靈感來自這篇博客文章“前端框架的真實比較”(https://medium.freecodecamp.org/a-realworld-comparison-of-front-end-frameworks-with-benchmarks-2019-update-4be0d3c78075)。
應用程序大小是通過查看瀏覽器的網(wǎng)絡選項卡來確定的(為了避免使用依賴于大量非JS資源的框架,我包含了所有類型的資源)。
對于性能,我使用了Google Chrome自帶的Lighthouse。
以下是使用React的結果,僅供參考。
為了進行比較,我選擇從本地服務器(而不是CDN)上下載并提供React JS文件。應用程序的大小:
性能:
好了,以上就是我們的對比標準。
現(xiàn)在,讓我們來看看最原始的基于Java的Web工具包:GWT。
GWT:Java-source-to-JS,服務器和客戶端框架
網(wǎng)址:http://www.gwtproject.org
GWT是第一個在沒有Applet或插件的情況下,在瀏覽器中使用Java的工具,創(chuàng)建于2006年。這是一項非常成熟的技術,但自2013年以來Google支持的框架不再支持GWT……我記得當時Google將其Web開發(fā)工作的重點放在了Dart上,而Dart作為JS的替代方案與GWT有著直接的競爭關系,而且當時的GWT社區(qū)已被人遺棄。不知怎地,GWT這個項目依然存在,所以我覺得我必須把它包含在這個比較中,這樣才能真正看出現(xiàn)代替代方案的狀況。
如果你想使用GWT,那么可以按照官網(wǎng)的建議下載SDK或安裝Eclipse插件……我已經(jīng)有很多年沒碰過Eclipse了(我改用了IntelliJ),所以我決定下載SDK:
./webAppCreator?-out?gwt-app?com.athaydes.GwtApp這個命令運行得非常快,而且還創(chuàng)建了一個Ant項目(什么東西?!)。我使用Java的時間已經(jīng)超過了10年,而且我錯過了Ant的鼎盛時期——如果我沒記錯的話,Maven是Java的構建工具。
但我不介意Ant!稍后我可以將其轉換為Gradle或Maven構建。而且IntelliJ可以很好地支持Ant項目,所以你可以在IntelliJ中打開這個項目,而且一切都會正常工作。
運行演示應用程序:
ant?devmode這一步可以打開一個Swing應用程序,你可以通過它控制開發(fā)服務器!我感覺它與2009年一模一樣!在瀏覽器上打開這個應用后,我發(fā)現(xiàn)除了一些新鮮的樣式之外,這個應用也幾乎沒有變化。
演示應用會向你展示如何使用GWT最強大的功能:無縫的RPC框架讓開發(fā)人員幾乎忘記了客戶端和服務器之間的區(qū)別,兩者之間的通信猶如調用Java方法一樣簡單。
但是在構建計數(shù)器應用的時候,我們并不需要兩者之間的通信。所以,我做的第一件事就是從入門應用中刪除RPC的代碼。
一般來說,GWT應用程序只包含一個源代碼根,它分為:
客戶端:僅在瀏覽器中運行的客戶端代碼。
服務器:服務器端代碼,即后端。
共享:客戶端和服務器皆可見的代碼。
在這個入門的應用程序中,Java源代碼位于src/目錄下,而Web的源代碼位于war/目錄中。初始頁面的HTML文件是war/GwtApp.index.html。打開這個文件,你可以看到一個非常普通的HTML,但奇怪的是,大部分視圖都已經(jīng)實現(xiàn)了(利用
我想用自己的代碼實現(xiàn)視圖,所以我刪除了這個
在基于小部件的API的幫助下,在GWT中實現(xiàn)用戶界面是一件非常容易的事情。因此,我在5分鐘內就創(chuàng)建計數(shù)器應用(請不要忘記我之前有過使用GWT的經(jīng)驗,即便我?guī)缀跏裁炊枷氩黄饋砹?。但是,當我嘗試重新編譯代碼時,遇到了lambdas的錯誤——ant文件說我們需要使用Java 7!為什么沒人更新呢?!GWT支持Java 8,所以我將其更新到了Java 8,然后一切都正常了。
以下是我在GWT中實現(xiàn)計數(shù)器應用的代碼:
package?com.athaydes.client;import?com.google.gwt.core.client.EntryPoint;
import?com.google.gwt.user.client.ui.*;
import?java.util.function.Consumer;
public?class?GwtApp?implements?EntryPoint?{
????public?void?onModuleLoad()?{
????????RootPanel.get(?"content"?).add(?new?Counter()?);
????}
}
class?Counter?extends?Composite?{
????private?int?value;
????Counter()?{
????????HorizontalPanel?buttonsPanel?=?new?HorizontalPanel();
????????buttonsPanel.setSpacing(?10?);
????????Button?up?=?new?Button(?"Increment"?);
????????Button?down?=?new?Button(?"Decrement"?);
????????Label?out?=?new?Label();
????????Runnable?update?=?()?->?out.setText(?"The?current?count?is?"?+?value?);
????????update.run();
????????Consumer?handler?=?(?increment?)?->?{if?(?increment?)?{value++;
????????????}?else?{value--;
????????????}
????????????update.run();
????????};
????????up.addClickHandler(?clickEvent?->?handler.accept(?true?)?);
????????down.addClickHandler(?clickEvent?->?handler.accept(?false?)?);
????????buttonsPanel.add(?up?);
????????buttonsPanel.add(?down?);
????????VerticalPanel?root?=?new?VerticalPanel();
????????root.setSpacing(?20?);
????????root.add(?buttonsPanel?);
????????root.add(?out?);
????????initWidget(?root?);
????}
}
看起來不錯。實時地重新加載適用于超級開發(fā)模式,可以快速地修復用戶界面中的小問題。
編譯出該應用的生產(chǎn)版本:
ant?build生成的JS文件放在war/gwtapp目錄中。通過war目錄就可以在瀏覽器中運行應用,所以我只需在IntelliJ中打開war/GwtApp.html,然后單擊右上角的瀏覽器圖標,就可以讓IntelliJ啟動一個負責運行HTML文件的HTTP服務器,并在我想要的瀏覽器中打開HTML文件。結果表明,該應用運行良好。
應用程序的大小:
性能:
TeaVM:Java-bytecode-to-JS編譯器
網(wǎng)址:http://teavm.org/
TeaVM這個項目據(jù)稱可以將Java字節(jié)碼轉換成JavaScript和Webassembly。 因為它不需要Java源代碼,所以它也可以用于從Kotlin和Scala(以及其他基于JVM的語言)進行編譯。
如果你想學習使用TeaVM,那么需要使用Maven archetype:
$?mvn?-DarchetypeCatalog=local?\??????????????????-DarchetypeGroupId=org.teavm???-DarchetypeArtifactId=teavm-maven-webapp???-DarchetypeVersion=0.5.1?archetype:generate
這一步會創(chuàng)建一個標準的Java項目,根據(jù)Maven的約定,你可以在提示框中輸入項目的保存目錄。Java源代碼位于src/main/java,而Web的index.html等文件位于src/main/webapp目錄中。
以下是我編寫的計數(shù)器的Java代碼:
package?com.athaydes;import?org.teavm.jso.dom.html.HTMLButtonElement;
import?org.teavm.jso.dom.html.HTMLDocument;
import?org.teavm.jso.dom.html.HTMLElement;
import?java.util.function.Consumer;
public?class?Client?{
????public?static?void?main(?String[]?args?)?{
????????HTMLDocument?document?=?HTMLDocument.current();
????????HTMLElement?div?=?document.createElement(?"h2"?);
????????div.appendChild(?document.createTextNode(?"TeaVM?CounterApp"?)?);
????????document.getBody().appendChild(?div?);
????????div.appendChild(?new?Counter().build()?);
????}
}
class?Counter?{
????private?int?value?=?0;
????HTMLElement?build()?{
????????HTMLDocument?document?=?HTMLDocument.current();
????????HTMLButtonElement?up?=?(?HTMLButtonElement?)?document.createElement(?"button"?);
????????up.appendChild(?document.createTextNode(?"Increment"?)?);
????????HTMLButtonElement?down?=?(?HTMLButtonElement?)?document.createElement(?"button"?);
????????down.appendChild(?document.createTextNode(?"Decrement"?)?);
????????HTMLElement?out?=?document.createElement(?"p"?);
????????Runnable?update?=?()?->?out.setInnerHTML(?"The?current?count?is?"?+?value?);
????????Consumer?handler?=?(?increment?)?->?{if?(?increment?)?{
????????????????value++;
????????????}?else?{
????????????????value--;
????????????}
????????????update.run();
????????};
????????up.listenClick(?(?event?)?->?handler.accept(?true?)?);
????????down.listenClick(?(?event?)?->?handler.accept(?false?)?);
????????update.run();
????????HTMLElement?div?=?document.createElement(?"div"?);
????????div.appendChild(?out?);
????????div.appendChild(?up?);
????????div.appendChild(?down?);return?div;
????}
}
有趣的是,Java Counter組件僅包含34行代碼,比React.js(55行以上的代碼量)少很多!
運行如下命令編譯:
$?mvn?package該命令會像往常一樣編譯所有的Java代碼,并在target/classes目錄中生成.class文件(與普通的Java項目一樣),但它還會在target/-/teavm下創(chuàng)建JavaScript代碼,我的項目名為mytea,因此相應的目錄為:target/mytea-1-0-SNAPSHOT/teavm。
在運行該應用程序時,你只需啟動Web服務器即可將目錄`target/mytea-1-0-SNAPSHOT/掛出來。
應用程序的大小:
性能:
JSweet:帶有庫生態(tài)系統(tǒng)的Java-source-to-JS(和TypeScript)編譯器
網(wǎng)址:http://www.jsweet.org/
JSweet可以將Java源代碼編譯為TypeScript和JavaScript。Java庫可以作為TypeScript庫發(fā)布。與其他備選方案不同,Java代碼可以與JS / TS代碼互相轉換!
如果你想學習使用JSweet,那么我推薦你從GitHub克隆快速入門的項目:
$?git?clone?https://github.com/cincheo/jsweet-quickstart.git$?cd?jsweet-quickstart
$?mvn?generate-sources
同樣,Java項目會使用標準的Maven約定,將Java源代碼放入src/main/java中。然而,Web資源會直接放在webapp目錄下。
與TeaVM不同,JSweet編譯器根本不會生成類文件:這就是為什么你只能運行mvn generate-sources來生成JS代碼,而無法使用更常見的mvn package或mvn install。
最終我寫的Java代碼幾乎與TeaVM一樣(但有一點例外:JSweet API選擇java.util.function.Function作為點擊處理程序,而不是Consumer,因此必須返回一個值,用lambda來編寫這段代碼就會很尷尬,你需要使用大括號并強制返回null):
package?quickstart;import?def.dom.HTMLButtonElement;
import?def.dom.HTMLElement;
import?java.util.function.Consumer;
import?static?def.dom.Globals.document;
public?class?QuickStart?{
????public?static?void?main(?String[]?args?)?{
????????HTMLElement?div?=?document.createElement(?"h2"?);
????????div.appendChild(?document.createTextNode(?"JSweet?CounterApp"?)?);
????????document.body.appendChild(?div?);
????????div.appendChild(?new?Counter().build()?);
????}
}
class?Counter?{
????private?int?value?=?0;
????HTMLElement?build()?{
????????HTMLButtonElement?up?=?(?HTMLButtonElement?)?document.createElement(?"button"?);
????????up.appendChild(?document.createTextNode(?"Increment"?)?);
????????HTMLButtonElement?down?=?(?HTMLButtonElement?)?document.createElement(?"button"?);
????????down.appendChild(?document.createTextNode(?"Decrement"?)?);
????????HTMLElement?out?=?document.createElement(?"p"?);
????????Runnable?update?=?()?->?out.innerText?=?"The?current?count?is?"?+?value;
????????Consumer?handler?=?(?increment?)?->?{if?(?increment?)?{
????????????????value++;
????????????}?else?{
????????????????value--;
????????????}
????????????update.run();
????????};
????????up.onclick?=?(?event?)?->?{
????????????handler.accept(?true?);return?null;
????????};
????????down.onclick?=?(?event?)?->?{
????????????handler.accept(?false?);return?null;
????????};
????????update.run();
????????HTMLElement?div?=?document.createElement(?"div"?);
????????div.appendChild(?out?);
????????div.appendChild(?up?);
????????div.appendChild(?down?);return?div;
????}
}
應用程序的大小:
性能:
CheerpJ:完全在瀏覽器上實現(xiàn)JVM
網(wǎng)址:https://leaningtech.com/cheerpj/
CheerpJ絕對是最瘋狂的選擇(甚至可能是你見過的最瘋狂的項目!)
實際上,它并不是Java到JavaScript的轉換器……其實它是一個完整的Java運行時!沒錯,它可以完成更傳統(tǒng)的JVM可以執(zhí)行的所有操作。線程、文件系統(tǒng)(顯然它通過IndexDB模擬文件系統(tǒng))、反射、類加載、網(wǎng)絡,等等。
如果這還不足以讓你頭暈目眩,那么就讓我們來看看CheerpJ的入門教程。
這個入門教程可以讓你感受如何在沒有插件的情況下,在瀏覽器上運行包含Swing應用(記住Swing,面向桌面系統(tǒng)的多平臺Java UI框架??)的編譯好的jar。
它運行的不是applet,它真的是在瀏覽器中運行Swing代碼!!而且還沒有插件!!
說出來連我自己都不相信,所以讓我們一起來看看這個入門教程吧。
為了方便起見,我將這些步驟進行了如下總結:
下載Swing應用程序的jar。
使用本地Java運行這個jar。
安裝CheerpJ(據(jù)說,你必須手動下載并放在你的主文件夾下)。
確認你安裝好了python3(對啊,我也覺得很奇怪,使用CheerpJ的時候,還需要用到Python)。
運行~/cheerpj_1.3/cheerpjfy.py TextDemo.jar。
創(chuàng)建一個index.html文件。
讓Web服務器指向當前目錄。
目前看起來這個入門教程行不通啊,因為你一直卡在了加載中……但是你需要漫長的等待,長到你開始懷疑人生!但最后終于成功了!
這個Swing應用跟我在本地Java上運行的應用相同,但它嵌入到了瀏覽器的網(wǎng)頁中!
在Ubuntu上運行Swing TextDemo
在瀏覽器中通過CheerpJ運行Swing TextDemo
如果你有現(xiàn)成的Swing應用,那么可能CheerpJ適合你。但是如果你想要寫一個新的應用,那么你可能不想選用CheerpJ。
我嘗試使用CheerpJ對DOM的支持(發(fā)行包中包含cheerpj-dom.jar文件)來實現(xiàn)計數(shù)器應用,但是我在10分鐘內遇到了2個bug。而且這兩個bug很麻煩,我完全無法繼續(xù)……更別提我必須將每個Java String都包裝成對Global.JSString()的調用!
給CheerpJ開發(fā)人員的一點提示:將你的jar放入Maven庫中(Java開發(fā)人員都不愿意將依賴項硬編碼到本地文件),千萬不要放在目錄下,絕對行不通!另外,你需要習慣語言的約定:不要調用Java方法set_onclick,你應該調用setOnClick,謝謝。我準備放棄CheerpJ了,但后來我想起了此次實驗的一項承諾:
使用產(chǎn)品/框架提供的最基本的工具創(chuàng)建計數(shù)器應用程序。無奈,只能硬著頭皮繼續(xù)了。對CheerpJ來說,似乎實現(xiàn)用戶界面的基本工具即是JVM本身!這個JVM提供了一個UI工具包:Swing!
從Java 12開始,Swing是隨JVM一起發(fā)布的唯一UI工具包……JavaFX已經(jīng)成為一個獨立的項目。不管怎樣,CheerpJ只支持Swing。所以,如下是我在純Swing中實現(xiàn)的計數(shù)器應用:
import?javax.swing.*;import?java.awt.*;
import?java.util.function.Consumer;
public?class?Main?implements?Runnable?{
????@Overridepublic?void?run()?{
????????JFrame?frame?=?new?JFrame(?"CheerpJ?Demo"?);
????????frame.setDefaultCloseOperation(?JFrame.EXIT_ON_CLOSE?);
????????frame.setSize(?400,?80?);
????????frame.add(?new?Counter()?);
????????frame.setVisible(?true?);
????}
????public?static?void?main(?String[]?args?)?{
????????SwingUtilities.invokeLater(?new?Main()?);
????}
}
class?Counter?extends?JPanel?{
????private?int?value;
????public?Counter()?{
????????JButton?up?=?new?JButton(?"Increment"?);
????????JButton?down?=?new?JButton(?"Decrement"?);
????????JLabel?out?=?new?JLabel();
????????Runnable?update?=?()?->?out.setText(?"The?current?count?is?"?+?value?);
????????update.run();
????????Consumer?handler?=?(?increment?)?->?{if?(?increment?)?{value++;
????????????}?else?{value--;
????????????}
????????????update.run();
????????};
????????up.addActionListener(?event?->?handler.accept(?true?)?);
????????down.addActionListener(?event?->?handler.accept(?false?)?);
????????JPanel?buttonsPanel?=?new?JPanel();
????????buttonsPanel.add(?up?);
????????buttonsPanel.add(?down?);
????????JLabel?title?=?new?JLabel(?"CheerpJ?CounterApp?(Swing)"?);
????????setLayout(?new?BorderLayout()?);add(?title,?BorderLayout.PAGE_START?);add(?buttonsPanel,?BorderLayout.PAGE_END?);add(?out,?BorderLayout.CENTER?);
????}
}
你完全可以在桌面系統(tǒng)上正常運行:這完全就是一個普通的Swing應用!
首先,我們需要創(chuàng)建普通的jar:
mvn?package然后用Java運行:
java?-jar?cheerpj-swing/target/cheerpj-swing-1.0-SNAPSHOT.jar結果如下:
在Ubuntu中運行計數(shù)器應用
瘋狂的是你也可以在CheerpJ的瀏覽器中運行該應用。
看一看瀏覽器上的“網(wǎng)絡”選項卡,你會發(fā)現(xiàn)非常有趣的東西:它一直在下載東西,顯然每個Java的標準庫包都有一個JS文件,CheerpJ會根據(jù)需要下載它們。
應用程序的大小:
性能:
為了方便你了解該應用有多糟糕,請參照Lighthouse 提供的如下診斷信息:
這是我第一次看到Avoid enourmous network payloads的診斷,我絕對會遵循這個建議!
Vaadin Flow:Java-source-to-JS-source,服務器和客戶端框架
網(wǎng)址:https://vaadin.com/flow
很久以前我就聽說Vaadin是一個基于GWT的框架……但似乎他們最近創(chuàng)建了一個基于Web組件的產(chǎn)品Vaadin Flow。
我喜歡網(wǎng)絡組件,所以我決定試試看。
入門教程的頁面里有幾個選項,可以創(chuàng)建與Spring或CDI等集成的項目。我選擇了我能找到的最基本選項Project Base,因為我想要的只是一個客戶端應用程序。
我按照說明下載了zip,而且只用了幾分鐘就可以讓這些代碼運行了。這是一個熟悉的Maven項目(我希望Gradle成為最受歡迎的選擇,但顯然情況并非如此)......我沒有看到index.html文件,這有點令人驚訝。瀏覽器是如何加載應用程序的呢?
不管怎樣,我們只需要一個命令就可以運行這個應用:mvn jetty:run,然后訪問http://localhost:8080就能看到正在運行的應用。
看一下這個巨大的POM文件(一個hello world應用就有139行的代碼),似乎他們使用了jetty-maven-plugin。
所以,我再一次選用了我最喜歡的選項IntelliJ服務器,來提供index.html文件。然而,情況開始有點混亂,這對我來說有點太神奇了......當然,我是一名Java開發(fā)人員,但也沒關系,我還是可以應付一兩個HTML文件。
在我改代碼的時候,似乎服務器重啟了,所以我感覺它可能在實時重新加載。這很好!但不幸的是,雖然不知道服務器在干什么,但是它并沒有實時地重新加載我的代碼。我試過幾次刷新頁面,卻導致了幾處報錯!!看起來像Vaadin應用不喜歡頁面刷新(應用處于調試模式,不過我估計它背后的工作太多了,結果因自身的復雜性而崩潰)。
但是,編寫UI的Java API非常出色,非常易于使用和學習,顯然是為Java程序員編寫的,讓我感覺賓至如歸,簡直太好了!
如下是我編寫的計數(shù)器應用,你有沒有覺得這段代碼很酷:
package?com.example.test;import?com.vaadin.flow.component.Composite;
import?com.vaadin.flow.component.button.Button;
import?com.vaadin.flow.component.html.Div;
import?com.vaadin.flow.component.html.H2;
import?com.vaadin.flow.component.html.Paragraph;
import?com.vaadin.flow.component.orderedlayout.VerticalLayout;
import?com.vaadin.flow.router.Route;
import?java.util.function.Consumer;
@Route(?""?)
public?class?MainView?extends?VerticalLayout?{
????public?MainView()?{
????????H2?header?=?new?H2(?"Vaadin?Flow?CounterApp"?);
????????add(?header,?new?Counter()?);
????}
}
class?Counter?extends?Composite<Div>?{
????private?int?value;
????Counter()?{
????????Paragraph?out?=?new?Paragraph();
????????Runnable?update?=?()?->?out.setText(?"The?current?count?is?"?+?value?);
????????update.run();
????????Consumer?handler?=?(?increment?)?->?{if?(?increment?)?{
????????????????value++;
????????????}?else?{
????????????????value--;
????????????}
????????????update.run();
????????};
????????Button?up?=?new?Button(?"Increment",?event?->?handler.accept(?true?)?);
????????Button?down?=?new?Button(?"Decrement",?event?->?handler.accept(?false?)?);
????????getContent().add(?out,?up,?down?);
????}
}
為了測量這個應用的性能,我通過如下命令在生產(chǎn)模式下運行了該應用:
$?mvn?jetty:run-exploded?-Pproduction-mode感覺這個頁面非常生氣勃勃,即便沒有經(jīng)過特殊的設計,頁面風格也非常好。
應用程序的大小:
注意:這個Vaadin的計數(shù)器應用至少需要312KB才能運行(主要是因為一個巨大的HTML文件,vaadin-flow-bundle:JS資源的總大小只有46.7KB)……這比我想象的還要多。
性能:
在運行應用時,Chrome在控制臺上顯示了一個警告,這有點讓人擔心。
似乎Vaadin在很早就采用了HTML導入等實驗性的功能,而現(xiàn)在這些功能都被棄用了。很可惜,但是如果他們能夠持續(xù)更新這個產(chǎn)品的話,這應該不是一個大問題。
Vaadin比JSweet和TeaVM慢一點,但公平地說,這個版本的計數(shù)器比其他版本更強大,盡管這并非我所愿(有沒有辦法從Vaadin應用中刪除樣式和字體?)!
Bck2Brwsr:Java-bytecode-to-JS編譯器
網(wǎng)址:http://wiki.apidesign.org/wiki/Bck2Brwsr
Bck2Brwsr始于2012,旨在創(chuàng)建一個能夠快速啟動并百分百在現(xiàn)代瀏覽器中運行的小型Java。
然而,與CheerpJ不同,它未能實現(xiàn)完整的JVM,只有一小部分功能可以在瀏覽器上運行,更類似于TeaVM,因為它也是將Java字節(jié)碼編譯成JS。
apidesign.org上有一個看起來很舊的wiki頁面(http://wiki.apidesign.org/wiki/Bck2Brwsr),說明了如何使用bck2brwsr。頁面上建議的一種做法是使用Bck2BrwsrViaCLI,還有一種是Knockout4Java。
我并不是很想使用Knockout.js(它自2015年左右開始就在JS的世界中失寵了),所以我選擇了CLI。
我按照wiki所說,運行Maven原型創(chuàng)建了一個新項目:
$?mvn?archetype:generate?????-DarchetypeGroupId=com.dukescript.archetype?????-DarchetypeArtifactId=knockout4j-archetype??-DarchetypeVersion=0.26?????-Dwebpath=client-web小心wiki頁面上給出的命令!最后一行少了一個反斜杠,而且命令中的版本是0.16,當前版本應該是0.26。
然后,編譯并打包應用:
$?mvn?package?警告:這一步會打開一個帶有JUnit Browser Runner的彈出窗口。
我沒想到會彈出這個窗口……不過,沒關系,我們繼續(xù),wiki頁面上說我們可以通過以下命令運行帶有FXBrwsr的應用:
$?mvn?-f?client?process-classes?exec:exec但是,我在運行這個命令的時候,收到了如下的錯誤:
Exception?in?thread?"main"?java.lang.IllegalStateException:?Can't?find?any?Fn.Presenter????at?net.java.html.boot.BrowserBuilder.showAndWait(BrowserBuilder.java:255)
????at?com.athaydes.Main.main(Main.java:16)
[INFO]?------------------------------------------------------------------------
[INFO]?BUILD?FAILURE
[INFO]?------------------------------------------------------------------------
我快速搜索了Google,結果什么都沒找到(我猜測他們沒有在Linux上測試),所以我嘗試了一下在真正的瀏覽器中運行應用:
$?mvn?-f?client-web?clean?package?-DskipTests?bck2brwsr:show結果,又遇到了另外一個錯誤:
[ERROR]?Failed?to?execute?goal?on?project?bck2brwsr-web:?Could?not?resolve?dependencies?for?project?com.athaydes:bck2brwsr-web:jar:1.0-SNAPSHOT:?
Could?not?find?artifact?com.athaydes:bck2brwsr-js:jar:bck2brwsr:1.0-SNAPSHOT?->?[Help?1]
這是一個Maven經(jīng)典的問題:有時你需要把你的應用放到某些插件可見的地方……通常你可以通過下述命令解決這個問題:
$?mvn?install然后,再次運行命令啟動應用,看似沒問題,但應用毫無反應。
檢查控制臺,果然出錯誤了:
VM69?bck2brwsr.js:6?Uncaught?Cannot?find?com.athaydes.BrowserMainw?@?VM69?bck2brwsr.js:6
v?@?VM69?bck2brwsr.js:2
r?@?VM69?bck2brwsr.js:2
load?(async)
z?@?VM69?bck2brwsr.js:3
r?@?VM69?bck2brwsr.js:4
w?@?VM69?bck2brwsr.js:6
n.loadClass?@?VM69?bck2brwsr.js:6
(anonymous)?@?index.html:28
我翻看了代碼……希望找到一些可以幫助我了解這個問題的東西,結果卻什么都沒找到……
然而,我找到了大量的XML。準確地說,在4個Maven pom文件中找到了931行XML。
我還發(fā)現(xiàn)該項目包含3個Maven模塊:client、client-web和js。
js模塊包含一個Java類,其中包含一些標記為native的方法,還用@JavaScriptBody進行了注釋,其中包含實現(xiàn)方法的JavaScript代碼,但是嵌入到了Java Strings中。
client模塊包含一個bootstrapping主類以及一個帶有更多注釋的DataModel類,似乎是為了將數(shù)據(jù)模型綁定到視圖,同時嘗試使用js模塊中聲明的函數(shù)。
它引用了另一個名為Data的類,然而源代碼中并沒有這個類……它是在編譯項目時自動生成的。而我卻搞不清楚這個類是由什么生成的。可能深埋在1000行的pom中吧。
client-web模塊包含缺少的類:com.athaydes.BrowserMain。因為這是我們在上述Maven命令中運行的模塊,所以我不明白為什么瀏覽器找不到這個類。
我希望能夠使用DOM API來創(chuàng)建UI,就像之前的一些示例一樣。我想了很多辦法,最終只發(fā)現(xiàn)了一些NetBeans API,這絕對不是我想要的東西。
似乎唯一可以與網(wǎng)頁交互的方法就是通過HTML文本上的data-bind屬性,其背后的支持是Knockout.js!
我以為我已經(jīng)避開了Knockout,但是看看“CLI”頁面上顯示的Maven原型的ID吧!
也許我可以通過可怕的@JavaScriptBody注釋,直接在Java Strings中編寫JavaScript代碼(請別這么干……理智一點),但我并不想知道這樣是否可行。
我覺得做了這么多嘗試就夠了。因為幾乎沒有文檔可以幫助我調試這個問題,在線搜索答案也是浪費時間——根本就沒有答案。
我很抱歉無法在這篇文章中給出有關bck2brwsr性能的實際數(shù)據(jù),雖然我花了一天的時間,卻未能成功。我覺得我可以說除非你有迫不得已的理由,否則就不應該碰任何與這個項目相關的東西,包括DukeScript。
你可能會注意到,整個bck2brwsr文檔甚至源代碼中多次引用了DukeScript。DukeScript的入門頁面中顯示的示例與我使用的Maven原型創(chuàng)建的示例完全相同,如此看來這兩個項目似乎密切相關,盡管Dukescript創(chuàng)始人說bck2brwsr只是項目的一小部分,而且也屬于實驗性質,另外他們也支持TeaVM。
結論
讓我們看看最后的結果:
我沒有將Bck2brwsr包含在內,因為我未能調試成功。如果有人能告訴我問題所在,那么我會更新下面的結果。性能:
* FCP = First Contentful Paint(此值用于打破性能相同的工具之間的聯(lián)系)
應用程序的大小:
代碼行數(shù):
代碼行數(shù)不包括導入和注釋。
總結
問題:性能至關重要?
答案:那么你應該選擇JSweet或TeaVM。
問題:你喜歡占用空間較小的方案?
答案:那么JSweet可以輕松勝任,但TeaVM也相當不錯。
問題:你希望維護的代碼庫最小?
答案:那么Vaadin Flow非常棒。其他方案都非常接近,所以這個因素不會產(chǎn)生太大的影響......但它們都能夠輕松擊敗React!
問題:你想要一些盡可能接近普通Java的東西?
答案:如果你關心UI組件的話,可以選擇Vaadin Flow;如果你關心業(yè)務邏輯的話,則可以選擇TeaVM。
問題:你希望盡可能接近JS生態(tài)系統(tǒng),但仍使用Java工具?
答案:那么JSweet非常適合你。
問題:你想要的東西是Java,但希望在瀏覽器中運行?
答案:那么JSweet非常適合你。
問題:你想嘗試一些與Java不同的東西,而不是JS?
答案:Elm是一種現(xiàn)成的函數(shù)式編程語言,旨在創(chuàng)建Web應用程序。它有很棒的工具,包括一個很棒的IntelliJ插件,所以非常適合那些一直想要功能的Java開發(fā)人員!另外一個理想的選擇是Dart,它與Java非常相似,但有很多語法糖,所以常見的功能都很容易實現(xiàn)。Ant帶有很棒的工具,包括實時重新加載的服務器,還包括類似于Angular和React等的框架(如果你需要的話)。
如果你對JVM備選方案與Dart的比較感到好奇,那么我可以告訴你我已經(jīng)將Dart的實現(xiàn)添加到了我的GitHub代碼庫中。比較結果如下:
應用程序大小:79KB,性能:100(FCP:1.4s),代碼行數(shù):31。
本文中顯示的所有代碼都上傳到了如下GitHub代碼庫中,包括React.js和Dart實現(xiàn)。
https://github.com/renatoathaydes/jvm-alternatives-to-js
原文:https://renato.athaydes.com/posts/comparing-jvm-alternatives-to-js.html
本文為CSDN翻譯,轉載請注明來源出處。
【END】
作為碼一代,想教碼二代卻無從下手:
聽說少兒編程很火,可它有哪些好處呢?
孩子多大開始學習比較好呢?又該如何學習呢?
最新的編程教育政策又有哪些呢?
下面給大家介紹CSDN新成員:極客寶寶(ID:geek_baby)
戳他了解更多↓↓↓
?熱 文?推 薦?
??李彥宏候選工程院院士;陌陌回應探探下架;拼多多回應“刷單”質疑 | 極客頭條
??華為硬核招聘程序員!| 極客頭條
??他 25 歲進貝爾實驗室,32 歲創(chuàng)建信息論,40 歲辦達特茅斯會議 | 人物志
?真の硬核粉絲!小學生也參加楊超越杯,作品優(yōu)秀!
??阿里半跪過,任正非差點跳樓,京東被騙光錢:成年人的生活哪有容易二字?
?不改變比特幣, 如何擴容?
?強推!盤點阿里巴巴 15 款開發(fā)者工具 | 程序員硬核評測
?17篇論文入選CVPR 2019,百度AI都在關注什么?(附論文地址)
? 她說:為啥程序員都特想要機械鍵盤?這答案我服!
System.out.println("點個在看吧!");
console.log("點個在看吧!");print("點個在看吧!");printf("點個在看吧!\n");
cout?<"點個在看吧!"?<Console.WriteLine("點個在看吧!");
Response.Write("點個在看吧!");alert("點個在看吧!")echo "點個在看吧!"
你點的每個“在看”,我都認真當成了喜歡
總結
以上是生活随笔為你收集整理的Dreamwear如何创建javascript_JavaScript 太糟糕,JVM 有妙招!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bing搜索引擎入口_互联网流量入口——
- 下一篇: python开发基础戴歆第四章_第一阶段