From bfbf7932ee0ea1de12f93aa69d5b8eba95183e44 Mon Sep 17 00:00:00 2001 From: Shadaj Laddad Date: Sun, 12 Nov 2017 12:33:05 -0800 Subject: [PATCH] Initial commit --- .gitignore | 5 ++ .travis.yml | 18 ++++ README.markdown | 79 ++++++++++++++++++ build.sbt | 10 +++ project/build.properties | 1 + project/giter8.sbt | 1 + src/main/g8/build.sbt | 21 +++++ src/main/g8/default.properties | 3 + src/main/g8/hot-launcher.js | 5 ++ src/main/g8/opt-launcher.js | 1 + src/main/g8/project/build.properties | 1 + src/main/g8/project/plugins.sbt | 3 + src/main/g8/public/favicon.ico | Bin 0 -> 3870 bytes src/main/g8/public/index.html | 37 ++++++++ src/main/g8/public/manifest.json | 15 ++++ src/main/g8/src/main/resources/App.css | 28 +++++++ src/main/g8/src/main/resources/index.css | 5 ++ src/main/g8/src/main/resources/logo.svg | 7 ++ .../g8/src/main/scala/$package$/App.scala | 36 ++++++++ .../g8/src/main/scala/$package$/Main.scala | 35 ++++++++ src/main/g8/webpack-fastopt.config.js | 46 ++++++++++ src/main/g8/webpack-opt.config.js | 48 +++++++++++ 22 files changed, 405 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 README.markdown create mode 100644 build.sbt create mode 100644 project/build.properties create mode 100644 project/giter8.sbt create mode 100644 src/main/g8/build.sbt create mode 100644 src/main/g8/default.properties create mode 100644 src/main/g8/hot-launcher.js create mode 100644 src/main/g8/opt-launcher.js create mode 100644 src/main/g8/project/build.properties create mode 100644 src/main/g8/project/plugins.sbt create mode 100644 src/main/g8/public/favicon.ico create mode 100644 src/main/g8/public/index.html create mode 100644 src/main/g8/public/manifest.json create mode 100644 src/main/g8/src/main/resources/App.css create mode 100644 src/main/g8/src/main/resources/index.css create mode 100644 src/main/g8/src/main/resources/logo.svg create mode 100644 src/main/g8/src/main/scala/$package$/App.scala create mode 100644 src/main/g8/src/main/scala/$package$/Main.scala create mode 100644 src/main/g8/webpack-fastopt.config.js create mode 100644 src/main/g8/webpack-opt.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9a4191 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +target/ +boot/ +lib_managed/ +src_managed/ +project/plugins/project/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..64235ba --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: scala + +# These directories are cached to S3 at the end of the build +cache: + directories: + - $HOME/.ivy2/cache + - $HOME/.sbt/boot/ + +jdk: + - oraclejdk8 + +script: + ## This runs the template with the default parameters, and runs test within the templated app. + - sbt -Dfile.encoding=UTF8 -J-XX:ReservedCodeCacheSize=256M test + + # Tricks to avoid unnecessary cache updates + - find $HOME/.sbt -name "*.lock" | xargs rm + - find $HOME/.ivy2 -name "ivydata-*.properties" | xargs rm diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..bf8bff3 --- /dev/null +++ b/README.markdown @@ -0,0 +1,79 @@ +# Create React Scala App +Create [React](https://facebook.github.io/react/) apps in [Scala](https://scala-lang.org/) (via [Slinky](https://github.com/shadaj/slinky)) with no build configuration + +Based on https://github.com/facebookincubator/create-react-app + +## Quick Overview +Make sure you have SBT and NPM installed. + +```sh +sbt new shadaj/create-react-scala-app.g8 +... follow instructions to create your app + +cd my-app/ +sbt ";fastOptJS::startWebpackDevServer;~fastOptJS" +``` + +Then open http://localhost:8080 to see your app. +When you're ready to deploy to production, create a minified bundle with `sbt fullOptJS::webpack` + +### Get Started Immediately +You **don’t** need to install or configure tools like Webpack or Babel. +They are preconfigured and hidden so that you can focus on the code. + +Just create a project, and you’re good to go. + +## Getting Started +### Installation +To use create-react-scala-app, you'll need SBT, which is the primary build tool, and NPM, which is used to pull in JavaScript dependencies and bundle your application with Webpack. + +**You’ll need to have Node >= 6 on your machine.** You can use [nvm](https://github.com/creationix/nvm#installation) to easily switch Node versions between different projects. + +**This tool doesn’t assume a Node backend.** The Node installation is only required for Create React App itself. + +### Creating an App +To create a new app, run: `sbt new shadaj/create-react-scala-app.g8`, follow the instructions that follow, then `cd my-app`. + +This will create a folder `my-app` inside the current folder. +Inside that directory, it will generate the initial project structure: +``` +my-app +├── build.sbt +├── hot-launcher.js +├── opt-launcher.js +├── webpack-fastopt.config.js +├── webpack-opt.config.js +├── project +│ └── build.properties +│ └── plugins.sbt +├── public +│ └── favicon.ico +│ └── index.html +│ └── manifest.json +└── src + └── main + └── resources + └── App.css + └── index.css + └── logo.svg + └── scala + └── hello/world + └── App.scala + └── Main.scala +``` + +No configuration or complicated folder structures, just the files you need to build your app. +Once the installation is done, you can run some commands inside the project folder: + +### `sbt ";fastOptJS::startWebpackDevServer;~fastOptJS"` +Runs the app in development mode with hot-reloading enabled. +Open http://localhost:8080 to see your app + +The page will automatically reload if you make changes to the code. You will see compilation and Webpack errors in your console. + +### `sbt fullOptJS::webpack` +Builds the app for production to the `build` folder. It correctly bundles React in production mode and optimizes the build for the best performance. It also minifies the build using UglifyJS. + +**Note:** there is currently a bug that causes execution of this command to always end in an exception. It is safe to ignore this exception, since the build folder will still be correctly generated. + +Your app is ready to be deployed. diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..6c81b82 --- /dev/null +++ b/build.sbt @@ -0,0 +1,10 @@ +organization := "me.shadaj" +name := "create-react-scala-app.g8" + +test in Test := { + val _ = (g8Test in Test).toTask("").value +} + +scriptedLaunchOpts ++= List("-Xms1024m", "-Xmx1024m", "-XX:ReservedCodeCacheSize=128m", "-XX:MaxPermSize=256m", "-Xss2m", "-Dfile.encoding=UTF-8") + +resolvers += Resolver.url("typesafe", url("http://repo.typesafe.com/typesafe/ivy-releases/"))(Resolver.ivyStylePatterns) diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..c091b86 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.16 diff --git a/project/giter8.sbt b/project/giter8.sbt new file mode 100644 index 0000000..70a8882 --- /dev/null +++ b/project/giter8.sbt @@ -0,0 +1 @@ +addSbtPlugin("org.foundweekends.giter8" %% "sbt-giter8" % "0.10.0") diff --git a/src/main/g8/build.sbt b/src/main/g8/build.sbt new file mode 100644 index 0000000..9bc05c7 --- /dev/null +++ b/src/main/g8/build.sbt @@ -0,0 +1,21 @@ +enablePlugins(ScalaJSBundlerPlugin) + +name := "$name$" + +npmDependencies in Compile += "react" -> "15.6.1" +npmDependencies in Compile += "react-dom" -> "15.6.1" +npmDependencies in Compile += "react-proxy" -> "1.1.8" + +npmDevDependencies in Compile += "file-loader" -> "1.1.5" +npmDevDependencies in Compile += "style-loader" -> "0.19.0" +npmDevDependencies in Compile += "css-loader" -> "0.28.7" +npmDevDependencies in Compile += "html-webpack-plugin" -> "2.30.1" +npmDevDependencies in Compile += "copy-webpack-plugin" -> "4.2.0" + +libraryDependencies += "me.shadaj" %%% "slinky-web" % "0.1.1" +libraryDependencies += "me.shadaj" %%% "slinky-hot" % "0.1.1" + +webpackConfigFile in fastOptJS := Some(baseDirectory.value / "webpack-fastopt.config.js") +webpackConfigFile in fullOptJS := Some(baseDirectory.value / "webpack-opt.config.js") + +webpackDevServerExtraArgs in fastOptJS := Seq("--inline", "--hot") diff --git a/src/main/g8/default.properties b/src/main/g8/default.properties new file mode 100644 index 0000000..4bc922d --- /dev/null +++ b/src/main/g8/default.properties @@ -0,0 +1,3 @@ +name=my-app +package=hello.world +verbatim=*.ico *.html *.css diff --git a/src/main/g8/hot-launcher.js b/src/main/g8/hot-launcher.js new file mode 100644 index 0000000..04cbb8e --- /dev/null +++ b/src/main/g8/hot-launcher.js @@ -0,0 +1,5 @@ +require("./$name$-fastopt.js").entrypoint.main(); + +if (module.hot) { + module.hot.accept(); +} diff --git a/src/main/g8/opt-launcher.js b/src/main/g8/opt-launcher.js new file mode 100644 index 0000000..c40552b --- /dev/null +++ b/src/main/g8/opt-launcher.js @@ -0,0 +1 @@ +require("./$name$-opt.js").entrypoint.main(); diff --git a/src/main/g8/project/build.properties b/src/main/g8/project/build.properties new file mode 100644 index 0000000..9abea12 --- /dev/null +++ b/src/main/g8/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.0.3 diff --git a/src/main/g8/project/plugins.sbt b/src/main/g8/project/plugins.sbt new file mode 100644 index 0000000..ca47b61 --- /dev/null +++ b/src/main/g8/project/plugins.sbt @@ -0,0 +1,3 @@ +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.21") + +addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.9.0") diff --git a/src/main/g8/public/favicon.ico b/src/main/g8/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a11777cc471a4344702741ab1c8a588998b1311a GIT binary patch literal 3870 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 baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ literal 0 HcmV?d00001 diff --git a/src/main/g8/public/index.html b/src/main/g8/public/index.html new file mode 100644 index 0000000..3e36d7e --- /dev/null +++ b/src/main/g8/public/index.html @@ -0,0 +1,37 @@ + + + + + + + + + + + React App + + + +
+ + + diff --git a/src/main/g8/public/manifest.json b/src/main/g8/public/manifest.json new file mode 100644 index 0000000..ef19ec2 --- /dev/null +++ b/src/main/g8/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": "./index.html", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/src/main/g8/src/main/resources/App.css b/src/main/g8/src/main/resources/App.css new file mode 100644 index 0000000..dcde9cd --- /dev/null +++ b/src/main/g8/src/main/resources/App.css @@ -0,0 +1,28 @@ +.App { + text-align: center; +} + +.App-logo { + animation: App-logo-spin infinite 20s linear; + height: 80px; +} + +.App-header { + background-color: #222; + height: 150px; + padding: 20px; + color: white; +} + +.App-title { + font-size: 1.5em; +} + +.App-intro { + font-size: large; +} + +@keyframes App-logo-spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} diff --git a/src/main/g8/src/main/resources/index.css b/src/main/g8/src/main/resources/index.css new file mode 100644 index 0000000..b4cc725 --- /dev/null +++ b/src/main/g8/src/main/resources/index.css @@ -0,0 +1,5 @@ +body { + margin: 0; + padding: 0; + font-family: sans-serif; +} diff --git a/src/main/g8/src/main/resources/logo.svg b/src/main/g8/src/main/resources/logo.svg new file mode 100644 index 0000000..6b60c10 --- /dev/null +++ b/src/main/g8/src/main/resources/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/g8/src/main/scala/$package$/App.scala b/src/main/g8/src/main/scala/$package$/App.scala new file mode 100644 index 0000000..53a3282 --- /dev/null +++ b/src/main/g8/src/main/scala/$package$/App.scala @@ -0,0 +1,36 @@ +package $package$ + +import me.shadaj.slinky.core.StatelessComponent +import me.shadaj.slinky.web.html._ + +import scala.scalajs.js +import scala.scalajs.js.annotation.{JSImport, ScalaJSDefined} + +@JSImport("resources/app.css", JSImport.Default) +@js.native +object AppCSS extends js.Object + +@JSImport("resources/logo.svg", JSImport.Default) +@js.native +object ReactLogo extends js.Object + +object App extends StatelessComponent { + type Props = Unit + + private val css = AppCSS + + @ScalaJSDefined + class Def(jsProps: js.Object) extends Definition(jsProps) { + def render() = { + div(className := "App")( + header(className := "App-header")( + img(src := ReactLogo.asInstanceOf[String], className := "App-logo", alt := "logo"), + h1(className := "App-title")("Welcome to React (with Scala.js!)") + ), + p(className := "App-intro")( + "To get started, edit ", code("App.scala"), " and save to reload." + ) + ) + } + } +} diff --git a/src/main/g8/src/main/scala/$package$/Main.scala b/src/main/g8/src/main/scala/$package$/Main.scala new file mode 100644 index 0000000..7c1c789 --- /dev/null +++ b/src/main/g8/src/main/scala/$package$/Main.scala @@ -0,0 +1,35 @@ +package $package$ + +import scala.scalajs.js +import scala.scalajs.js.annotation.{JSExportTopLevel, JSImport} +import scala.scalajs.LinkingInfo + +import me.shadaj.slinky.core._ +import me.shadaj.slinky.web.ReactDOM +import me.shadaj.slinky.hot + +import org.scalajs.dom + +@JSImport("resources/index.css", JSImport.Default) +@js.native +object IndexCSS extends js.Object + +object Main { + val css = IndexCSS + + @JSExportTopLevel("entrypoint.main") + def main(): Unit = { + if (LinkingInfo.developmentMode) { + hot.initialize() + } + + val container = Option(dom.document.getElementById("root")).getOrElse { + val elem = dom.document.createElement("div") + elem.id = "root" + dom.document.body.appendChild(elem) + elem + } + + ReactDOM.render(App(), container) + } +} diff --git a/src/main/g8/webpack-fastopt.config.js b/src/main/g8/webpack-fastopt.config.js new file mode 100644 index 0000000..23d699e --- /dev/null +++ b/src/main/g8/webpack-fastopt.config.js @@ -0,0 +1,46 @@ +var path = require("path"); +var HtmlWebpackPlugin = require('html-webpack-plugin'); +var CopyWebpackPlugin = require('copy-webpack-plugin'); + +module.exports = { + entry: { + "$name$-fastopt": [ path.resolve(__dirname, "./hot-launcher.js") ] + }, + output: { + path: __dirname, + filename: "[name]-bundle.js" + }, + resolve: { + alias: { + "resources": path.resolve(__dirname, "../../../../src/main/resources") + } + }, + module: { + rules: [ + { + test: /\\.css\$/, + use: [ 'style-loader', 'css-loader' ] + }, + // "file" loader for svg + { + test: /\\.svg\$/, + use: [ + { + loader: 'file-loader', + query: { + name: 'static/media/[name].[hash:8].[ext]' + } + } + ] + } + ] + }, + plugins: [ + new CopyWebpackPlugin([ + { from: path.resolve(__dirname, "../../../../public") } + ]), + new HtmlWebpackPlugin({ + template: path.resolve(__dirname, "../../../../public/index.html") + }) + ] +} diff --git a/src/main/g8/webpack-opt.config.js b/src/main/g8/webpack-opt.config.js new file mode 100644 index 0000000..d135d99 --- /dev/null +++ b/src/main/g8/webpack-opt.config.js @@ -0,0 +1,48 @@ +var webpack = require("webpack"); +var path = require("path"); + +var HtmlWebpackPlugin = require('html-webpack-plugin'); +var CopyWebpackPlugin = require('copy-webpack-plugin'); + +module.exports = { + "entry": { + "$name$-opt": [ path.resolve(__dirname, "./opt-launcher.js") ] + }, + "output": { + "path": path.resolve(__dirname, "../../../../build"), + "filename": "[name]-bundle.js" + }, + resolve: { + alias: { + "resources": path.resolve(__dirname, "../../../../src/main/resources") + } + }, + module: { + rules: [ + { + test: /\\.css\$/, + use: [ 'style-loader', 'css-loader' ] + }, + // "file" loader for svg + { + test: /\\.svg\$/, + use: [ + { + loader: 'file-loader', + query: { + name: 'static/media/[name].[hash:8].[ext]' + } + } + ] + } + ] + }, + plugins: [ + new CopyWebpackPlugin([ + { from: path.resolve(__dirname, "../../../../public") } + ]), + new HtmlWebpackPlugin({ + template: path.resolve(__dirname, "../../../../public/index.html") + }) + ] +}