Scala.js'yi NPM ve Browserify ile Kullanma

Yayınlanan: 2022-03-11

Scala dilinin JavaScript'e derleyicisi olan Scala.js'yi kullanırsanız, modern JavaScript dünyasında Scala.js'nin standart bağımlılık yönetimini çok sınırlayıcı bulabilirsiniz. Scala.js, WebJars ile bağımlılıkları yönetirken, JavaScript geliştiricileri NPM kullanarak bağımlılıkları yönetir. NPM tarafından üretilen bağımlılıklar sunucu tarafında olduğundan, genellikle tarayıcı kodu oluşturmak için Browserify veya Webpack kullanan ek bir adım gerekir.

Bu yazıda, Scala.js'nin NPM'de bulunan çok sayıda JavaScript modülüyle nasıl entegre edileceğini anlatacağım. Burada açıklanan tekniklerin çalışan bir örneği için bu GitHub deposunu kontrol edebilirsiniz. Bu örneği kullanarak ve bu gönderiyi okuyarak, NPM kullanarak JavaScript kitaplıklarınızı toplayabilecek, Browserify kullanarak bir paket oluşturabilecek ve sonucu kendi Scala.js projenizde kullanabileceksiniz. Her şey SBT tarafından yönetildiğinden, tüm bunlar Node.js'yi yüklemeden bile.

Browserify ve Scala.js

Browserify'ın büyüsü Java dünyasında da işe yarayabilir!
Cıvıldamak

Scala.js için Bağımlılıkları Yönetme

Bugün, JavaScript'i derleyen dillerde uygulama yazmak çok yaygın bir uygulama haline geliyor. Giderek daha fazla insan, bugün ES6 kullanmanıza izin veren CoffeeScript veya TypeScript gibi genişletilmiş JavaScript dillerine veya Babel gibi aktarıcılara geçiyor. Aynı zamanda, Google Web Toolkit (Java'dan JavaScript'e bir derleyici) çoğunlukla kurumsal uygulamalar için kullanılır. Bu nedenlerden dolayı, bir Scala geliştiricisi olarak artık Scala.js'yi kullanmayı garip bir seçim olarak görmüyorum. Derleyici hızlıdır, üretilen kod verimlidir ve genel olarak aynı dili hem ön uçta hem de arka uçta kullanmanın bir yoludur.

Bununla birlikte, JavaScript dünyasında Scala araçlarını kullanmak henüz yüzde 100 doğal değil. Bazen JavaScript ekosisteminden Scala ekosistemine kadar olan boşluğu doldurmanız gerekir. Bir dil olarak Scala.js, JavaScript ile mükemmel bir birlikte çalışabilirliğe sahiptir. Scala.js, Scala dilinden JavaScript'e yönelik bir derleyici olduğundan, Scala kodunu mevcut JavaScript koduna arayüzlemek çok kolaydır. En önemlisi, Scala.js size, yazılmamış JavaScript kitaplıklarına (TypeScript ile yaptığınıza benzer şekilde) erişmek için yazılmış arabirimler (veya cepheler) oluşturma yeteneği verir. Java, Scala ve hatta Haskell gibi güçlü bir şekilde yazılan dillere alışkın olan geliştiriciler için JavaScript çok gevşek yazılmıştır. Eğer böyle bir geliştiriciyseniz, muhtemelen asıl sebep, Scala.js'yi kullanmak isteyebilmenizin nedeni, yazılmamış bir dilin üzerine (kesinlikle) yazılmış bir dil almaktır.

SBT'ye dayanan ve hala biraz açık bırakılan standart Scala.js araç zincirindeki bir sorun şudur: Projenize ek JavaScript kitaplıkları gibi bağımlılıklar nasıl dahil edilir? SBT, WebJars üzerinde standart hale gelir, bu nedenle bağımlılıklarınızı yönetmek için WebJars kullanmanız gerekir. Ne yazık ki, deneyimlerime göre yetersiz olduğunu kanıtladı.

WebJar ile İlgili Sorun

Belirtildiği gibi, JavaScript bağımlılıklarını almanın standart Scala.js yolu WebJars'a dayanır. Sonuçta Scala bir JVM dilidir. Scala.js, öncelikle program oluşturmak için SBT'yi kullanır ve son olarak SBT, JAR bağımlılıklarını yönetmede mükemmeldir.

Bu nedenle WebJar formatı, JVM dünyasında JavaScript bağımlılıklarını içe aktarmak için tam olarak tanımlandı. WebJar, basit JAR dosyasının yalnızca derlenmiş Java sınıflarını içerdiği web varlıklarını içeren bir JAR dosyasıdır. Bu nedenle, Scala.js'nin fikri, JavaScript bağımlılıklarınızı WebJar bağımlılıklarını ekleyerek içe aktarmanız gerektiğidir, Scala'nın JAR bağımlılıkları eklemesine benzer şekilde.

Güzel Fikir, Çalışmaması Dışında

Webjar'larla ilgili en büyük sorun, rastgele bir JavaScript kitaplığındaki rastgele bir sürümün WebJar olarak nadiren bulunabilmesidir. Aynı zamanda, JavaScript kitaplıklarının büyük çoğunluğu NPM modülleri olarak mevcuttur. Ancak, otomatik bir npm-to-webjar paketleyicisi ile NPM ve WebJars arasında varsayılan bir köprü vardır. Bu yüzden NPM modülü olarak kullanılabilen bir kitaplığı içe aktarmaya çalıştım. Benim durumumda, bir web sayfasında Minecraft benzeri dünyalar oluşturmak için bir kütüphane olan VoxelJS idi. Kitaplığı bir WebJar olarak istemeye çalıştım, ancak açıklayıcıda lisans alanı olmadığı için köprü başarısız oldu.

WebJar kitaplığı çalışmıyor

Bu sinir bozucu deneyimle diğer kütüphanelerde başka nedenlerle de karşılaşabilirsiniz. Basitçe söylemek gerekirse, vahşi doğada her kitaplığa WebJar olarak erişemezsiniz. JavaScript kitaplıklarına erişmek için WebJars'ı kullanmanız gereken gereksinim çok sınırlayıcı görünüyor.

NPM'yi girin ve Browserify

Daha önce belirttiğim gibi, JavaScript kitaplıklarının çoğu için standart paketleme biçimi, Node.js'nin herhangi bir sürümünde bulunan Node Paket Yöneticisi veya NPM'dir. NPM kullanarak, neredeyse tüm mevcut JavaScript kitaplıklarına kolayca erişebilirsiniz.

NPM'nin Düğüm paket yöneticisi olduğunu unutmayın. Düğüm, V8 JavaScript motorunun sunucu tarafı uygulamasıdır ve sunucu tarafında Node.js tarafından kullanılacak paketleri kurar. Olduğu gibi, NPM tarayıcı için işe yaramaz. Ancak, NPM paketi olarak da dağıtılan her yerde bulunan Browserify aracı sayesinde, NPM'nin kullanışlılığı tarayıcı uygulamalarıyla çalışmak için bir süre uzatıldı.

Browserify, basitçe söylemek gerekirse, tarayıcı için bir paketleyicidir. Bir tarayıcı uygulamasında kullanılabilen bir "paket" üreten NPM modüllerini toplayacaktır. Pek çok JavaScript geliştiricisi bu şekilde çalışır - paketleri NPM ile yönetir ve ardından web uygulamasında kullanmak için bunları Tarayıcıya koyarlar. Webpack gibi aynı şekilde çalışan başka araçlar olduğunu unutmayın.

Boşluğu SBT'den NPM'ye Doldurmak

Az önce tarif ettiğim nedenlerden dolayı istediğim şey, NPM ile web'den bağımlılıkları yüklemek, tarayıcı için bağımlılıkları toplamak için Browserify'ı çağırmak ve ardından bunları Scala.js ile kullanmaktı. Görev beklediğimden biraz daha karmaşık çıktı, ancak yine de mümkün. Aslında işi ben yaptım ve burada anlatıyorum.

Basit olması açısından, SBT içinde çalıştırmanın mümkün olduğunu düşündüğüm için Browserify'ı da seçtim. Webpack ile denemedim, ancak bunun da mümkün olduğunu düşünüyorum. Neyse ki, bir boşlukta başlamak zorunda değildim. Halihazırda yerinde birkaç parça var:

  • SBT zaten NPM'yi destekliyor. Play Framework için geliştirilen sbt-web eklentisi, NPM bağımlılıklarını yükleyebilir.
  • SBT, JavaScript'in yürütülmesini destekler. sbt-jsengine eklentisi sayesinde Node araçlarını Node'un kendisini kurmadan çalıştırabilirsiniz.
  • Scala.js, oluşturulan bir paketi kullanabilir. Scala.js'de, uygulamanıza isteğe bağlı JavaScript kitaplıklarını dahil etmek için bir birleştirme işlevi vardır.

Bu özellikleri kullanarak, NPM bağımlılıklarını indirebilen ve ardından bir bundle.js dosyası oluşturarak Browserify'ı çağırabilen bir SBT görevi oluşturdum. Prosedürü derleme zincirine entegre etmeye çalıştım ve her şeyi otomatik olarak çalıştırabilirim, ancak her derlemede paketlemeyi işlemek zorunda kalmak çok yavaş. Ayrıca, bağımlılıkları her zaman değiştirmezsiniz; bu nedenle, bağımlılıkları değiştirdiğinizde arada bir manuel olarak bir paket oluşturmanız gerekir.

Bu yüzden benim çözümüm bir alt proje oluşturmaktı. Bu alt proje, JavaScript kitaplıklarını NPM ve Browserify ile indirir ve paketler. Ardından, bağımlılıkların toplanmasını gerçekleştirmek için bir bundle komutu ekledim. Ortaya çıkan paket, Scala.js uygulamasında kullanılacak kaynaklara eklenir.

JavaScript bağımlılıklarınızı her değiştirdiğinizde bu "paket"i manuel olarak çalıştırmanız gerekir. Belirtildiği gibi, derleme zincirinde otomatik değildir.

Paketleyici Nasıl Kullanılır

Örneğimi kullanmak istiyorsanız, aşağıdakileri yapın: önce, her zamanki Git komutuyla depoyu kontrol edin.

 git clone https://github.com/sciabarra/scalajs-browserify/

Ardından bundle klasörünü Scala.js projenize kopyalayın. Paketleme için bir alt projedir. Ana projeye bağlanmak için build.sbt dosyanıza aşağıdaki satırları eklemelisiniz:

 val bundle = project.in(file("bundle")) jsDependencies += ProvidedJS / "bundle.js" addCommandAlias("bundle", "bundle/bundle")

Ayrıca, project/plugins.sbt dosyanıza aşağıdaki satırları eklemelisiniz:

 addSbtPlugin("com.typesafe.sbt" % "sbt-web" % "1.1.1") addSbtPlugin("com.typesafe.sbt" % "sbt-js-engine" % "1.1.3")

Bittiğinde, bağımlılıklarınızı toplamak için kullanabileceğiniz yeni bir komutunuz var, bundle . src/main/resources klasörünüzün altında bir bundle.js dosyası oluşturacaktır.

Paket, Scala.js Uygulamanıza Nasıl Dahil Edilir?

Az önce açıklanan bundle komutu, NPM ile bağımlılıkları toplar ve ardından bir bundle.js oluşturur. fastOptJS veya fullOptJS komutlarını çalıştırdığınızda, ScalaJS bir myproject-jsdeps.js , JavaScript bağımlılığı olarak belirttiğiniz tüm kaynakları, dolayısıyla ayrıca bundle.js de oluşturur. Uygulamanıza paketlenmiş bağımlılıkları dahil etmek için aşağıdaki eklentileri kullanmanız gerekir:

 <script src="target/scala-2.11/myproject-jsdeps.js"></script> <script src="target/scala-2.11/myproject-fastopt.js"></script> <script src="target/scala-2.11/myproject-launcher.js"></script>

Paketiniz artık myproject-jsdeps.js bir parçası olarak mevcuttur. Paket hazır ve görevimizi biraz bitirdik (bağımlılıkları içe aktarıp tarayıcıya dışa aktarıyoruz). Bir sonraki adım, farklı bir sorun olan JavaScript kitaplıklarını kullanmak, bir Scala.js kodlama sorunu. Tamamlanması için, şimdi Scala.js'de paketin nasıl kullanılacağını ve içe aktardığımız kitaplıkları kullanmak için cepheler oluşturacağımızı tartışacağız.

Scala.js ile sunucu ve istemci arasında kod paylaşabilirsiniz.

Scala.js ile sunucu ve istemci arasında kolayca kod paylaşabilirsiniz.
Cıvıldamak

Scala.js Uygulamanızda Genel JavaScript Kitaplığı Kullanma

Özetlemek gerekirse, bir paket oluşturmak ve bu paketi Scala.js'ye eklemek için NPM ve Browserify'ın nasıl kullanılacağını gördük. Ancak genel bir JavaScript kitaplığını nasıl kullanabiliriz?

Yazının geri kalanında ayrıntılı olarak açıklayacağımız tam süreç:

  • NPM'den kitaplıklarınızı seçin ve bunları bundle/package.json içine ekleyin.
  • Bunları bir kitaplık modülü dosyasında, bundle/lib.js içinde require ile yükleyin.
  • Bundle nesnesini Scala.js'de yorumlamak için Scala.js cepheleri yazın.
  • Son olarak, yeni yazılan kitaplıkları kullanarak uygulamanızı kodlayın.

Bağımlılık Ekleme

NPM kullanarak, bağımlılıklarınızı standart olan package.json dosyasına dahil etmeniz gerekir.

Diyelim ki jQuery ve Loadash gibi iki ünlü kütüphaneyi kullanmak istiyorsunuz. Bu örnek yalnızca tanıtım amaçlıdır, çünkü jQuery için uygun bir modüle sahip Scala.js için bir bağımlılık olarak kullanılabilen mükemmel bir sarmalayıcı zaten vardır ve Lodash, Scala dünyasında işe yaramaz. Yine de, bunun iyi bir örnek olduğunu düşünüyorum, ancak sadece bir örnek olarak alın.

Bu nedenle, npmjs.com web sitesine gidin ve kullanmak istediğiniz kitaplığı bulun ve bir sürüm de seçin. Diyelim ki jquery-browserify sürümünü ve lodash 4.3.0 sürümünü seçtiniz. Ardından, packages.json dosyanızın dependencies bloğunu aşağıdaki gibi güncelleyin:

 "dependencies": { "browserify": "13.0.0", "jquery-browserify": "1.8.1", "lodash": "4.3.0" }

Paketi oluşturmak için gerekli olduğundan, browserify her zaman saklayın. Yine de, onu pakete dahil etmeniz gerekmez.

NPM'niz kuruluysa, bundle dizininden yazabileceğinizi unutmayın:

 npm install --save jquery-browserify lodash

Ayrıca package.json da güncelleyecektir. NPM kurulu değilse endişelenmeyin. SBT, Node.js ve NPM'nin Java sürümünü yükleyecek, gerekli JAR'ları indirecek ve çalıştıracaktır. Tüm bunlar, SBT'den bundle komutunu çalıştırdığınızda yönetilir.

Kitaplığı Dışa Aktarma

Artık paketleri nasıl indireceğimizi biliyoruz. Sonraki adım, Browserify'a bunları bir pakette toplaması ve uygulamanın geri kalanı için kullanılabilir hale getirmesi talimatını vermektir.

Browserify, tarayıcı için Node.js davranışını taklit eden bir request toplayıcısıdır; bu, bir yerde kitaplığınızı içe aktarma require olması require anlamına gelir. Bu kitaplıkları Scala.js'ye aktarmamız gerektiğinden, paket ayrıca Bundle adlı bir üst düzey JavaScript nesnesi oluşturuyor. Yani yapmanız gereken, bir JavaScript nesnesini dışa aktaran ve tüm kitaplıklarınızı bu nesnenin alanları olarak gerektiren lib.js düzenlemek.

Scala.js jQuery ve Lodash kitaplıklarına dışa aktarmak istiyorsak, kodda bu şu anlama gelir:

 module.exports = { "jquery": require("jquery-browserify"), "lodash": require("lodash") }

Şimdi, komut bundle çalıştırmanız yeterlidir; kitaplık indirilecek, toplanacak ve Scala.js uygulamanızda kullanılmaya hazır olacak şekilde pakete yerleştirilecektir.

Pakete Erişmek

Şimdiye kadar:

  • Paket alt projesini Scala.js projenize yüklediniz ve doğru şekilde yapılandırdınız.
  • İstediğiniz herhangi bir kitaplık için onu package.json içine eklediniz.
  • Onları lib.js .
  • bundle komutunu çalıştırdınız.

Sonuç olarak, artık bu nesnenin alanları olarak kullanılabilen kitaplıklar için tüm giriş noktalarını sağlayan bir Bundle üst düzey JavaScript nesnesine sahipsiniz.

Artık Scala.js ile kullanmaya hazırsınız. En basit durumda, kütüphanelere erişmek için şöyle bir şey yapabilirsiniz:

 @js.native object Bundle extends js.Object { def jquery : js.Any = js.native def lodash: js.Any = js.native }

Bu kod, kitaplıklara Scala.js'den erişmenizi sağlar. Ancak, Scala.js ile yapmanız gereken yol bu değil, çünkü kitaplıklar hala yazılmamış. Bunun yerine, yazılan "cepheler" veya sarmalayıcılar yazmalısınız, böylece orijinal olarak yazılmamış JavaScript kitaplıklarını yazılı olarak pullu bir şekilde kullanabilirsiniz.

Scala.js'de sarmak istediğiniz belirli JavaScript kitaplığına bağlı olduğundan, cepheleri nasıl yazacağınızı burada söyleyemem. Tartışmayı tamamlamak için sadece bir örnek göstereceğim. Daha fazla ayrıntı için lütfen resmi Scala.js belgelerine bakın. Ayrıca, mevcut cephelerin listesine bakabilir ve ilham almak için kaynak kodunu okuyabilirsiniz.

Şimdiye kadar keyfi, hala eşlenmemiş kitaplıklar için süreci ele aldık. Makalenin geri kalanında zaten mevcut bir cepheye sahip kütüphaneye atıfta bulunuyorum, bu yüzden tartışma sadece bir örnek.

JavaScript API'sini Scala.js'de sarmak

JavaScript'te require kullandığınızda, birçok farklı şey olabilen bir nesne elde edersiniz. Bir fonksiyon veya bir nesne olabilir. Hatta yalnızca bir dize veya bir boole olabilir, bu durumda require yalnızca yan etkiler için çağrılır.

Yaptığım örnekte jquery , ek yöntemler sağlayan bir nesne döndüren bir işlevdir. Tipik kullanım jquery(<selector>).<method> şeklindedir. Bu bir basitleştirmedir, çünkü jquery $.<method> kullanımına da izin verir, ancak bu basitleştirilmiş örnekte tüm bu durumları ele almayacağım. Genel olarak, karmaşık JavaScript kitaplıkları için tüm API'lerin statik Scala türleriyle kolayca eşlenemeyeceğine dikkat edin. JavaScript nesnesine dinamik (türlenmemiş) bir arayüz sağlayan js.Dynamic başvurmanız gerekebilir.

Bu nedenle, yalnızca daha yaygın kullanım durumunu yakalamak için Bundle nesnesinde jquery tanımladım:

 def jquery : js.Function1[js.Any, Jquery] = js.native

Bu işlev bir jQuery nesnesi döndürür. Benim durumumda bir özelliğin bir örneği tek bir yöntemle tanımlanmıştır (bir basitleştirme, kendinizinkini ekleyebilirsiniz):

 @js.native trait Jquery extends js.Object { def text(arg: js.Any): Jquery = js.native }

Lodash kitaplığı için, doğrudan çağırabileceğiniz bir işlevler koleksiyonu olduğundan, kitaplığın tamamını bir JavaScript nesnesi olarak modelliyoruz:

 def lodash: Lodash = js.native

lodash özelliğinin aşağıdaki gibi olduğu durumlarda (ayrıca bir basitleştirme, yöntemlerinizi buraya ekleyebilirsiniz):

 @js.native trait Lodash extends js.Object { def camelCase(arg: js.Any): String = js.native }

Bu tanımları kullanarak, artık her ikisi de NPM'den yüklenen ve daha sonra tarayıcı ile taranan temel jQuery ve Lodash kitaplıklarını kullanarak Scala kodunu yazabiliriz:

 object Main extends JSApp { def main(): Unit = { import Bundle._ jquery("#title").text(lodash.camelCase("This is a test")) } }

Tam örneği buradan kontrol edebilirsiniz.

Çözüm

Ben bir Scala geliştiricisiyim ve hem sunucu hem de istemci için aynı dili kullanabildiğim için Scala.js'yi keşfettiğimde heyecanlandım. Scala, Java'dan çok JavaScript'e benzediğinden, Scala.js tarayıcıda oldukça kolay ve doğaldır. Ayrıca, zengin kitaplıklar, makrolar ve güçlü IDE'ler ve oluşturma araçları koleksiyonu olarak Scala'nın güçlü özelliklerini de kullanabilirsiniz. Diğer önemli avantajlar, sunucu ve istemci arasında kod paylaşabilmenizdir. Bu özelliğin yararlı olduğu birçok durum vardır. Javascript için Coffeescript, Babel veya Typescript gibi bir aktarıcı kullanıyorsanız, Scala.js kullanırken çok fazla fark görmeyeceksiniz, ancak yine de birçok avantajı var. İşin sırrı, her dünyanın en iyisini almak ve birlikte güzel bir şekilde çalışmalarını sağlamaktır.

İlgili: Neden Scala Öğrenmeliyim?