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