first commit
This commit is contained in:
commit
be847a4cd3
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
logs
|
||||||
|
project/project
|
||||||
|
project/target
|
||||||
|
target
|
||||||
|
tmp
|
||||||
|
.history
|
||||||
|
dist
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
/out
|
||||||
|
.idea_modules
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
/RUNNING_PID
|
||||||
|
.settings
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# hidden cross project folders
|
||||||
|
shared/.js
|
||||||
|
shared/.jvm
|
||||||
|
|
||||||
|
# temp files
|
||||||
|
.~*
|
||||||
|
*~
|
||||||
|
*.orig
|
||||||
|
|
||||||
|
# eclipse
|
||||||
|
.scala_dependencies
|
||||||
|
.buildpath
|
||||||
|
.cache
|
||||||
|
.target
|
||||||
|
bin/
|
||||||
|
|
||||||
|
.bloop
|
||||||
|
.metals
|
1
.scalafmt.conf
Normal file
1
.scalafmt.conf
Normal file
@ -0,0 +1 @@
|
|||||||
|
version = "2.4.2"
|
1
Procfile
Normal file
1
Procfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
web: server/target/universal/stage/bin/server -Dhttp.port=$PORT -Dconfig.file=server/conf/heroku.conf
|
58
build.sbt
Normal file
58
build.sbt
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
lazy val server = (project in file("server"))
|
||||||
|
.settings(commonSettings)
|
||||||
|
.settings(
|
||||||
|
scalaJSProjects := Seq(client),
|
||||||
|
pipelineStages in Assets := Seq(scalaJSPipeline),
|
||||||
|
pipelineStages := Seq(digest, gzip),
|
||||||
|
// triggers scalaJSPipeline when using compile or continuous compilation
|
||||||
|
compile in Compile := ((compile in Compile) dependsOn scalaJSPipeline).value,
|
||||||
|
libraryDependencies ++= Seq(
|
||||||
|
"com.vmunier" %% "scalajs-scripts" % "1.1.4",
|
||||||
|
guice,
|
||||||
|
specs2 % Test
|
||||||
|
),
|
||||||
|
// Compile the project before generating Eclipse files, so that generated .scala or .class files for views and routes are present
|
||||||
|
EclipseKeys.preTasks := Seq(compile in Compile)
|
||||||
|
)
|
||||||
|
.enablePlugins(PlayScala)
|
||||||
|
// .enablePlugins(SbtWeb)
|
||||||
|
.enablePlugins(WebScalaJSBundlerPlugin)
|
||||||
|
.dependsOn(sharedJvm)
|
||||||
|
|
||||||
|
lazy val client = (project in file("client"))
|
||||||
|
.settings(commonSettings)
|
||||||
|
.settings(
|
||||||
|
scalaJSUseMainModuleInitializer := true,
|
||||||
|
libraryDependencies ++= Seq(
|
||||||
|
"org.scala-js" %%% "scalajs-dom" % "1.0.0",
|
||||||
|
"com.github.japgolly.scalajs-react" %%% "core" % "1.7.0",
|
||||||
|
"com.github.japgolly.scalajs-react" %%% "extra" % "1.7.0",
|
||||||
|
// "com.github.japgolly.scalajs-react" %%% "test" % "1.7.0",
|
||||||
|
),
|
||||||
|
scalacOptions ++= Seq("-Ymacro-annotations","-deprecation"),
|
||||||
|
useYarn := true,
|
||||||
|
stFlavour := Flavour.Japgolly,
|
||||||
|
Compile / npmDependencies ++= Seq(
|
||||||
|
"react" -> "16.13.1",
|
||||||
|
"react-dom" -> "16.13.1",
|
||||||
|
"@types/react" -> "16.9.34",
|
||||||
|
"@types/react-dom" -> "16.9.6"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.enablePlugins(ScalaJSPlugin)
|
||||||
|
.enablePlugins(ScalaJSBundlerPlugin)
|
||||||
|
.enablePlugins(ScalablyTypedConverterPlugin)
|
||||||
|
.dependsOn(sharedJs)
|
||||||
|
|
||||||
|
lazy val shared = crossProject(JSPlatform, JVMPlatform)
|
||||||
|
.crossType(CrossType.Pure)
|
||||||
|
.in(file("shared"))
|
||||||
|
.settings(commonSettings)
|
||||||
|
.jsConfigure(_.enablePlugins(ScalaJSWeb))
|
||||||
|
lazy val sharedJvm = shared.jvm
|
||||||
|
lazy val sharedJs = shared.js
|
||||||
|
|
||||||
|
lazy val commonSettings = Seq(
|
||||||
|
scalaVersion := "2.13.2",
|
||||||
|
organization := "com.example"
|
||||||
|
)
|
@ -0,0 +1,92 @@
|
|||||||
|
package com.example.playscalajsreact
|
||||||
|
|
||||||
|
import com.example.playscalajsreact.shared.SharedMessages
|
||||||
|
import org.scalajs.dom
|
||||||
|
import japgolly.scalajs.react._
|
||||||
|
import japgolly.scalajs.react.vdom.html_<^._
|
||||||
|
import japgolly.scalajs.react.extra._
|
||||||
|
import com.example.playscalajsreact.model.HelloWorldSJSRComponent
|
||||||
|
import japgolly.scalajs.react.extra.router._
|
||||||
|
import japgolly.scalajs.react.extra.router.StaticDsl.Route
|
||||||
|
|
||||||
|
|
||||||
|
object ScalaJSExample {
|
||||||
|
|
||||||
|
def main(args: Array[String]): Unit = {
|
||||||
|
|
||||||
|
sealed trait Page
|
||||||
|
case object Home extends Page
|
||||||
|
case object Hello extends Page
|
||||||
|
case class Person(user: String) extends Page
|
||||||
|
case class ID(id: Int) extends Page
|
||||||
|
|
||||||
|
case class Menu(name: String, route: Page)
|
||||||
|
|
||||||
|
val mainMenu = Vector(
|
||||||
|
Menu("Home", Home),
|
||||||
|
Menu("Hello", Hello)
|
||||||
|
)
|
||||||
|
|
||||||
|
def layout(c: RouterCtl[Page], r: Resolution[Page]) =
|
||||||
|
<.ul(
|
||||||
|
// c.link(Home)("Home"),
|
||||||
|
// c.link(Hello)("Hello"),
|
||||||
|
mainMenu.toTagMod { item =>
|
||||||
|
{
|
||||||
|
<.li(
|
||||||
|
^.key := item.name,
|
||||||
|
item.name,
|
||||||
|
c setOnClick item.route
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
r.render()
|
||||||
|
)
|
||||||
|
|
||||||
|
val x = <.ol(
|
||||||
|
^.id := "my-list",
|
||||||
|
^.lang := "en",
|
||||||
|
^.margin := 8.px,
|
||||||
|
<.li("Item 1"),
|
||||||
|
<.li("Item 2"),
|
||||||
|
HelloWorldSJSRComponent("Hello", 18)
|
||||||
|
)
|
||||||
|
|
||||||
|
val routerConfig = RouterConfigDsl[Page].buildConfig { dsl =>
|
||||||
|
import dsl._
|
||||||
|
import japgolly.scalajs.react.vdom.Implicits._
|
||||||
|
|
||||||
|
case class Item(category: String, itemId: java.util.UUID) extends Page
|
||||||
|
// val r =
|
||||||
|
// ("category" / string("[a-z]+") / "item" / int.caseClassDebug[ID])
|
||||||
|
|
||||||
|
// FIXME uncomment this block to get an error - Companion object not found for class Product
|
||||||
|
// case class Product(category: Int, item: Int) extends Page
|
||||||
|
// val r: Route[Product] = ("cat" / int / "item" / int).caseClass[Product]
|
||||||
|
|
||||||
|
// val testRoute =
|
||||||
|
// ("user" / string("[a-z0-9]{1,20}") / "age" / int).pmap {
|
||||||
|
// case (a, b) => {}
|
||||||
|
// }
|
||||||
|
(emptyRule
|
||||||
|
| staticRoute(root, Home) ~> render(x)
|
||||||
|
// FIXME uncomment this block to get an error - Companion object not found for class Person
|
||||||
|
// | dynamicRouteCT("user" / string("[a-z0-9]{1,20}").caseClass[Person]) ~> dynRender(
|
||||||
|
// (page: Person) => {
|
||||||
|
// HelloWorldSJSRComponent(page.user, 0)
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
| staticRoute("#hello", Hello) ~> render(<.div("TODO"))
|
||||||
|
| staticRedirect("#hey") ~> redirectToPage(Hello)(SetRouteVia.HistoryReplace))
|
||||||
|
.notFound(redirectToPage(Home)(SetRouteVia.HistoryReplace))
|
||||||
|
.renderWith(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// x.renderIntoDOM(dom.document.getElementById("app"))
|
||||||
|
val router = Router(BaseUrl.fromWindowOrigin / "index.html", routerConfig)
|
||||||
|
router().renderIntoDOM(dom.document.getElementById("app"))
|
||||||
|
|
||||||
|
dom.document.getElementById("scalajsShoutOut").textContent =
|
||||||
|
SharedMessages.itWorks
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.example.playscalajsreact.model
|
||||||
|
|
||||||
|
// import slinky.core.annotations.react
|
||||||
|
// import slinky.core.StatelessComponent
|
||||||
|
// import slinky.web.html.h1
|
||||||
|
import japgolly.scalajs.react._
|
||||||
|
// @react class HelloWorldComponentSlinky extends StatelessComponent {
|
||||||
|
// case class Props(name: String, age: Int)
|
||||||
|
|
||||||
|
// def render = {
|
||||||
|
// h1(s"Hello ${props.name} ${props.age}")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
object HelloWorldSJSRComponent {
|
||||||
|
import japgolly.scalajs.react.vdom.html_<^._
|
||||||
|
case class Props(name: String, age: Int)
|
||||||
|
|
||||||
|
private val component = ScalaComponent
|
||||||
|
.builder[Props]("HelloWorldComponent")
|
||||||
|
.render_P(p => {
|
||||||
|
<.p(p.name + p.age)
|
||||||
|
})
|
||||||
|
.build
|
||||||
|
|
||||||
|
def apply(name: String, age: Int) = {
|
||||||
|
component(Props(name, age))
|
||||||
|
}
|
||||||
|
}
|
4004
client/yarn.lock
Normal file
4004
client/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
project/build.properties
Normal file
1
project/build.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
sbt.version=1.3.8
|
4
project/metals.sbt
Normal file
4
project/metals.sbt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// DO NOT EDIT! This file is auto-generated.
|
||||||
|
// This file enables sbt-bloop to create bloop config files.
|
||||||
|
|
||||||
|
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.0-RC1-229-b7c15aa9")
|
28
project/plugins.sbt
Normal file
28
project/plugins.sbt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Comment to get more information during initialization
|
||||||
|
logLevel := Level.Warn
|
||||||
|
|
||||||
|
// Resolvers
|
||||||
|
resolvers += "Typesafe repository" at "https://repo.typesafe.com/typesafe/releases/"
|
||||||
|
|
||||||
|
resolvers += Resolver.bintrayRepo("oyvindberg", "converter")
|
||||||
|
|
||||||
|
// for Scala.js 1.x.x
|
||||||
|
addSbtPlugin("org.scalablytyped.converter" % "sbt-converter" % "1.0.0-beta13")
|
||||||
|
|
||||||
|
// Sbt plugins
|
||||||
|
|
||||||
|
// Use Scala.js v1.x
|
||||||
|
addSbtPlugin("com.vmunier" % "sbt-web-scalajs" % "1.0.11")
|
||||||
|
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.0.1")
|
||||||
|
// addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.18.0")
|
||||||
|
addSbtPlugin("ch.epfl.scala" % "sbt-web-scalajs-bundler" % "0.18.0")
|
||||||
|
|
||||||
|
// If you prefer using Scala.js v0.6.x, uncomment the following plugins instead:
|
||||||
|
// addSbtPlugin("com.vmunier" % "sbt-web-scalajs" % "1.1.0-0.6")
|
||||||
|
// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.33")
|
||||||
|
|
||||||
|
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.2")
|
||||||
|
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0")
|
||||||
|
addSbtPlugin("com.typesafe.sbt" % "sbt-gzip" % "1.0.2")
|
||||||
|
addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.1.4")
|
||||||
|
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4")
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.example.playscalajsreact.controllers
|
||||||
|
|
||||||
|
import javax.inject._
|
||||||
|
|
||||||
|
import com.example.playscalajsreact.shared.SharedMessages
|
||||||
|
import play.api.mvc._
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class Application @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
|
||||||
|
|
||||||
|
def index = Action {
|
||||||
|
Ok(views.html.index(SharedMessages.itWorks))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
server/app/views/index.scala.html
Normal file
9
server/app/views/index.scala.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@(message: String)
|
||||||
|
|
||||||
|
@main("Play with Scala.js") {
|
||||||
|
<h2>Play and Scala.js share a same message</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Play shouts out: <em>@message</em></li>
|
||||||
|
<li>Scala.js shouts out: <em id="scalajsShoutOut"></em></li>
|
||||||
|
</ul>
|
||||||
|
}
|
19
server/app/views/main.scala.html
Normal file
19
server/app/views/main.scala.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
@(title: String)(content: Html)
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>@title</title>
|
||||||
|
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
|
||||||
|
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
|
||||||
|
<!-- <script src="../../../client/target/scala-2.13/client-jsdeps.js"></script> -->
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
@content
|
||||||
|
@scalajs.html.scripts("client", routes.Assets.versioned(_).toString, name => getClass.getResource(s"/public/$name") != null)
|
||||||
|
<!-- <script src="client-fastopt-bundle.js" defer></script> -->
|
||||||
|
</body>
|
||||||
|
</html>
|
6
server/conf/application.conf
Normal file
6
server/conf/application.conf
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
play.i18n.langs=["en"]
|
||||||
|
|
||||||
|
play.assets {
|
||||||
|
path = "/public"
|
||||||
|
urlPrefix = "/assets"
|
||||||
|
}
|
8
server/conf/heroku.conf
Normal file
8
server/conf/heroku.conf
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
include "application"
|
||||||
|
|
||||||
|
play.http.secret.key="kUNSMzxg/<?qU1I_l?:2KXhV?5_ma=g7d2UsH;`wHc?fJKYj24YyT]KtCk8I2ZTL"
|
||||||
|
|
||||||
|
play.filters.hosts {
|
||||||
|
# Allow requests to herokuapp.com and its subdomains.
|
||||||
|
allowed += ".herokuapp.com"
|
||||||
|
}
|
10
server/conf/routes
Normal file
10
server/conf/routes
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Routes
|
||||||
|
# This file defines all application routes (Higher priority routes first)
|
||||||
|
# ~~~~
|
||||||
|
|
||||||
|
# Home page
|
||||||
|
GET / com.example.playscalajsreact.controllers.Application.index
|
||||||
|
|
||||||
|
# Prefix must match `play.assets.urlPrefix`
|
||||||
|
GET /assets/*file controllers.Assets.at(file)
|
||||||
|
GET /versionedAssets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
BIN
server/public/images/favicon.png
Normal file
BIN
server/public/images/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 687 B |
0
server/public/stylesheets/main.css
Normal file
0
server/public/stylesheets/main.css
Normal file
27
server/test/ApplicationSpec.scala
Normal file
27
server/test/ApplicationSpec.scala
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import org.junit.runner._
|
||||||
|
import org.specs2.runner._
|
||||||
|
import play.api.test._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add your spec here.
|
||||||
|
* You can mock out a whole application including requests, plugins etc.
|
||||||
|
* For more information, consult the wiki.
|
||||||
|
*/
|
||||||
|
@RunWith(classOf[JUnitRunner])
|
||||||
|
class ApplicationSpec() extends PlaySpecification {
|
||||||
|
|
||||||
|
"Application" should {
|
||||||
|
|
||||||
|
"send 404 on a bad request" in new WithApplication {
|
||||||
|
route(app, FakeRequest(GET, "/boum")) must beSome.which (status(_) == NOT_FOUND)
|
||||||
|
}
|
||||||
|
|
||||||
|
"render the index page" in new WithApplication {
|
||||||
|
val home = route(app, FakeRequest(GET, "/")).get
|
||||||
|
|
||||||
|
status(home) must equalTo(OK)
|
||||||
|
contentType(home) must beSome.which(_ == "text/html")
|
||||||
|
contentAsString(home) must contain ("shouts out")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.example.playscalajsreact.shared
|
||||||
|
|
||||||
|
object SharedMessages {
|
||||||
|
def itWorks = "It works!"
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user