ScalaJs: Javascript para paganos backend (Parte I)

No tengo ni idea de front. Lo reconozco. Soy uno de esos cavernícolas backend que se niega no puede salir de su cueva backend. Sin embargo, la gente de ScalaJs ha desarrollado algo que acerca un poco más el mundo del frontend a gente como yo.

iZcUNxH

ScalaJs: ¿Qué es?

ScalaJs es una librería que permite traducir código Scala a código Javascript. Así de simple. Además, de cara a los desarrolladores de front, permite integrarse con las principales librerías JS como AngularJs o React.
¿Qué ofrece entonces que no haga ya JS? Codificar front usando un lenguaje fuertemente tipado.
49775773
Gracias a esto, sé lo que devuelve mi expresión (olvida los null, NaN y resultados mágicos).
Si bien es cierto que al principio generaba excesivo boilerplate al compilar las fuentes Scala a JS, el optimizador de ScalaJS ha mejorado bastante desde sus inicios.

Mi primer proyecto ScalaJs

Desde Scalera, hemos contratado a un mono probado en nuestras carnes la librería y queremos daros las principales claves para montar vuestro primer mini-proyecto ScalaJs basado en canvas. El ejemplo en el que nos hemos basado, podéis encontrarlo aquí.

Montando el proyecto SBT

Una vez creado el scaffolding básico,

scalajs-example/
  project/
    build.sbt
  src/main/
    resources/
    scala/scalera/scalajs/example
  build.sbt

Tendremos que añadir dos plugins a nuestro proyecto (en project/build.sbt):

  • sbt-scalajs : Nos permitirá invocar desde SBT directamente a la tarea de optimización que generará el fichero JS a partir de las fuentes Scala
  • workbench : Plugin desarrollado por Li Haoyi que permite desplegar tu proyecto ScalaJS en local de manera muy sencilla. Solo con arrancar SBT, ejecuta un servidor web en localhost que despliega tu aplicación 🙂

Nuestro fichero debería quedar como sigue:

resolvers += "spray repo" at "http://repo.spray.io"
resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.1")
addSbtPlugin("com.lihaoyi" % "workbench" % "0.2.3")

El tema de añadir los resolvers es necesario para el plugin de workbench, según ha detectado gente que lo ha probado.

Definiendo el build.sbt

Aparte de indicar el nombre del proyecto, la organización y demás…

import com.lihaoyi.workbench.Plugin._
enablePlugins(ScalaJSPlugin)
workbenchSettings

organization := "scalera"
version := "1.0"
scalaVersion := "2.11.2"
name := "scalajs-example"

libraryDependencies ++= Seq(
  "org.scala-js" %%% "scalajs-dom" % "0.8.0",
  "com.lihaoyi" %%% "scalatags" % "0.5.3")

bootSnippet := "scalera.scalajs.example.Boot().main(document.getElementById('canvas'));"
updateBrowsers <<= updateBrowsers.triggeredBy(fastOptJS in Compile)

es necesario habilitar el plugin de sbt-scalajs e importar las settings de workbench. Posteriormente, añadiremos en las dependencias las librerías auxiliares que usaremos (scalajs-dom para realizar operaciones sobre el dom de manera fácil y scalatags para usar un DSL sencillo para escribir etiquetas XML/HTML).

Adicionalmente, indicaremos un par de cosas más:

  • bootSnippet : El snippet que indica el punto de entrada a la aplicación.
  • updateBrowser : Indicamos que propiciaremos un reseteo (parcial) del contenido del browser cuando se llame a la tarea de fastOptJS.

Añadiendo código Scala

Ya tenemos creado el proyecto SBT en el cual se enmarcará nuestra aplicación, añadamos pues algo de lógica creando el fichero src/main/scalera/scalajs/example/Boot.scala:

package scalera.scalajs.example
 
import scala.scalajs.js.annotation.JSExport
 
import org.scalajs.dom
import org.scalajs.dom.html
 
@JSExport
object Boot {
 
  @JSExport
  def main(canvas: html.Canvas): Unit = {
 
    println("Hello world!")
 
    val ctx = canvas.getContext("2d")
      .asInstanceOf[dom.CanvasRenderingContext2D]
 
    val width = ctx.canvas.width
 
    val height = ctx.canvas.height
 
    def run: Unit = {
      ctx.clearRect(0, 0, width, height)
      ctx.fillStyle = "black"
      ctx.fillRect(0, 0, width, height)
    }
 
    dom.setInterval(() => run, 1000)
 
  }
}

Imports aparte, lo que llama la atención de este snippet, es lo siguiente:

  • Los @JSExport. Básicamente sirven para indicar a ScalaJs, qué elementos deben exportarse a javascript, de manera que sean accesibles desde cualquier otro script JS que importe el fichero generado (o desde el HTML).
  • El println("Hello world!"). La pregunta del millón es, ¿esto donde se imprimirá? En la consola del browser, my friends.
  • El context ctx representa la selección del canvas que vamos a usar.
  • El método run borra la superficie del canvas, selecciona el estilo de relleno a ‘negro’ y pinta un rectángulo en la superficie del canvas.
  • dom.setInterval(() => run, 1000) : Causa la ejecución del método run cada segundo.

Ya nos falta poco…

Algo de HTML no hace daño…

Vale, ¿cómo visualizamos el pedazo de aplicación que acabamos de crear? Tendremos que crear un index.html, aunque sea básico, que invoque nuestro main.

Creamos dicho fichero en src/main/resources con un contenido muy simple:

<!DOCTYPE html>
<html>
<head>
 <title>Scalera Scalajs-example</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body style="margin: 0px">


<div>
 <canvas style="display: block;padding:0;margin:auto;width=800" id="canvas" width="800" height="600"/>
</div>


<script type="text/javascript" src="../scalera-scalajs-example-fastopt.js"></script>
<script type="text/javascript" src="/workbench.js"></script>
<script>
 scalera.scalajs.example.Boot().main(document.getElementById('canvas'));
</script>
</body>
</html>

Como veis, el HTML lo único que hace es declarar un canvas e importar 3 scripts:

  • ../scalera-scalajs-example-fastopt.js : El fichero JS generado a partir nuestras fuentes Scala.
  • /workbench.js : el script que carga el plugin de workbench.
  • Un script anónimo que carga el objeto Boot (exportado a JS mediante la etiqueta @JSExport) y ejecuta el método main pasándole el canvas que hemos declarado más arriba

Demo

Para probar que funciona nuestro proyecto, bastará con ejecutar sbt sobre el directorio raiz de nuestro proyecto, y el plugin de workbench se encargará de levantar el servidor web.

Podremos acceder a la url http://localhost:12345/target/scala-2.11/classes/index.html y veremos, en primer lugar, que se ha pintado un precioso cuadro que cambia de color cada segundo en todo el canvas, y por otra parte, si abrimos la consola del navegador, veremos que ha impreso nuestro brutal Hello world!

Vale, ¿y lo malo?

A pesar de la pinta que tiene nuestro proyecto de ejemplo, al implementarlo nos encontramos con algunas dificultades que tenemos que mencionar (para que no os sintáis engañados):

  • Usar dependencias scala: ScalaJs no puede usar clases/objetos de dependencias que no tengan la naturaleza de proyecto ScalaJs a su vez. Limita bastante pero tiene sentido si piensas que ScalaJs tiene que ser capaz de migrar a JS todo código Scala involucrado en un @JSExport
  • Testing : ¿ScalaJS y Scalatest juntos? Con dificultad. Pero échale un vistazo a uTest

Conclusiones

ScalaJs mola. No queremos decir con esto que sea mejor que desarrollar nativamente en JS, ni óptimo, pero sí que facilita que gente totalmente atea en materia de front se acerque un poco más a este mundillo y que ofrece muchas posibilidades.

En futuros posts veremos algunos ejemplos sobre como usar el CanvasRenderingContext2D o sobre el funcionamiento de las anotaciones @JSExport.

¡Agur de limón! 🙂

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s