├── project
├── build.properties
├── plugins.sbt
└── bintray.sbt
├── version.sbt
├── .jvmopts
├── src
├── sbt-test
│ └── sbt-reactjs
│ │ ├── reactfail
│ │ ├── project
│ │ │ ├── build.properties
│ │ │ └── plugins.sbt
│ │ ├── build.sbt
│ │ ├── test
│ │ └── src
│ │ │ └── main
│ │ │ └── assets
│ │ │ ├── hello.jsx
│ │ │ └── js
│ │ │ └── more.jsx
│ │ └── reacttask
│ │ ├── project
│ │ ├── build.properties
│ │ └── plugins.sbt
│ │ ├── test
│ │ ├── src
│ │ └── main
│ │ │ └── assets
│ │ │ ├── hello.jsx
│ │ │ └── js
│ │ │ └── more.jsx
│ │ ├── build.sbt
│ │ └── out
│ │ └── more.js
└── main
│ ├── resources
│ └── jsx.js
│ └── scala
│ └── com
│ └── github
│ └── ddispaltro
│ └── reactjs
│ └── SbtReactJs.scala
├── .gitignore
├── scripted.sbt
├── .travis.yml
├── LICENSE
├── .github
└── workflows
│ └── scala.yml
└── README.md
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=1.9.1
2 |
--------------------------------------------------------------------------------
/version.sbt:
--------------------------------------------------------------------------------
1 | ThisBuild / version := "0.6.9-SNAPSHOT"
2 |
--------------------------------------------------------------------------------
/.jvmopts:
--------------------------------------------------------------------------------
1 | -Dfile.encoding=UTF8
2 | -Xms1g
3 | -Xmx2g
4 | -Xss2m
5 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reactfail/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=1.9.1
2 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reacttask/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=1.9.1
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .idea
3 | .bloop
4 | .bsp
5 | .metals
6 | .vscode
7 | metals.sbt
8 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reactfail/build.sbt:
--------------------------------------------------------------------------------
1 | lazy val root = (project in file(".")).enablePlugins(SbtWeb)
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reactfail/test:
--------------------------------------------------------------------------------
1 | -> assets
2 | $ absent target/web/reactjs/main/js/more.js
3 | $ absent target/web/reactjs/main/hello.js
4 |
--------------------------------------------------------------------------------
/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | addSbtPlugin("com.typesafe.sbt" % "sbt-web-build-base" % "1.2.3")
2 |
3 | addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.6")
--------------------------------------------------------------------------------
/scripted.sbt:
--------------------------------------------------------------------------------
1 | enablePlugins(SbtWebBase)
2 | scriptedLaunchOpts := {
3 | scriptedLaunchOpts.value ++
4 | Seq("-Xmx1024M", "-Dplugin.version=" + version.value)
5 | }
6 |
7 | scriptedBufferLog := false
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | jdk: openjdk8
2 | language: scala
3 | scala:
4 | - 2.12.11
5 | cache:
6 | directories:
7 | - $HOME/.ivy2/cache
8 | - $HOME/.sbt
9 |
10 | script:
11 | - sbt test scripted
12 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reacttask/test:
--------------------------------------------------------------------------------
1 | > assets
2 | $ exists target/web/reactjs/main/js/more.js
3 | $ exists target/web/reactjs/main/hello.js
4 | $ must-mirror target/web/reactjs/main/js/more.js out/more.js
5 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reactfail/src/main/assets/hello.jsx:
--------------------------------------------------------------------------------
1 | var HelloMessage = React.createClass({
2 | render: function() {
3 | return
Hello {this.props.name}
, mountNode);
8 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reacttask/src/main/assets/hello.jsx:
--------------------------------------------------------------------------------
1 | class HelloMessage extends React.Component {
2 | render() {
3 | return Hello {this.props.name}
;
4 | }
5 | }
6 |
7 | ReactDOM.render(, mountNode);
8 |
--------------------------------------------------------------------------------
/project/bintray.sbt:
--------------------------------------------------------------------------------
1 | /*resolvers += Resolver.url(
2 | "bintray-sbt-plugin-releases",
3 | url("http://dl.bintray.com/content/sbt/sbt-plugin-releases"))(
4 | Resolver.ivyStylePatterns)*/
5 |
6 | //addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.6")
7 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reactfail/src/main/assets/js/more.jsx:
--------------------------------------------------------------------------------
1 | export var MoreMessage = React.createClass({
2 | render: function() {
3 | return Hello {this.props.name}
;
4 | }
5 | });
6 |
7 | ReactDOM.render(, mountNode);
8 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reacttask/build.sbt:
--------------------------------------------------------------------------------
1 | lazy val root = (project in file(".")).enablePlugins(SbtWeb)
2 |
3 | ReactJsKeys.harmony := true
4 |
5 | ReactJsKeys.stripTypes := true
6 |
7 | ReactJsKeys.sourceMapInline := true
8 |
9 | ReactJsKeys.es6module := true
10 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reacttask/src/main/assets/js/more.jsx:
--------------------------------------------------------------------------------
1 | export var MoreMessage = React.createClass({
2 | render () {
3 | var names: Array = this.props.names;
4 | return {names.map((name) => {name})}
;
5 | }
6 | });
7 |
8 | ReactDOM.render(, mountNode);
9 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reactfail/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | {
2 | val pluginVersion = System.getProperty("plugin.version")
3 | if(pluginVersion == null)
4 | throw new RuntimeException("""|The system property 'plugin.version' is not defined.
5 | |Specify this property using the scriptedLaunchOpts -D.""".stripMargin)
6 | else addSbtPlugin("com.github.ddispaltro" % "sbt-reactjs" % pluginVersion)
7 | }
8 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reacttask/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | {
2 | val pluginVersion = System.getProperty("plugin.version")
3 | if(pluginVersion == null)
4 | throw new RuntimeException("""|The system property 'plugin.version' is not defined.
5 | |Specify this property using the scriptedLaunchOpts -D.""".stripMargin)
6 | else addSbtPlugin("com.github.ddispaltro" % "sbt-reactjs" % pluginVersion)
7 | }
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This software is licensed under the Apache 2 license, quoted below.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with
4 | the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
5 |
6 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
7 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
8 | language governing permissions and limitations under the License.
9 |
--------------------------------------------------------------------------------
/.github/workflows/scala.yml:
--------------------------------------------------------------------------------
1 | name: Scala CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Set up JDK 1.8
17 | uses: actions/setup-java@v1
18 | with:
19 | java-version: 1.8
20 | - name: Run tests
21 | run: sbt scripted
22 | - name: Cache
23 | uses: actions/cache@v2.0.0
24 | with:
25 | # A list of files, directories, and wildcard patterns to cache and restore
26 | path: |
27 | ~/.ivy2/cache
28 | ~/.sbt
29 | # An explicit key for restoring and saving the cache
30 | key: sbt-cache
31 |
--------------------------------------------------------------------------------
/src/sbt-test/sbt-reactjs/reacttask/out/more.js:
--------------------------------------------------------------------------------
1 | export var MoreMessage = React.createClass({displayName: "MoreMessage",
2 | render:function () {
3 | var names = this.props.names;
4 | return React.createElement("div", null, names.map(function(name) {return React.createElement("span", null, name);}));
5 | }
6 | });
7 |
8 | ReactDOM.render(React.createElement(MoreMessage, {names: ["John", "Mary"]}), mountNode);
9 |
10 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbbnVsbF0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sSUFBSSxpQ0FBaUMsMkJBQUE7RUFDMUMsTUFBTSxDQUFBLFFBQUEsSUFBSSxDQUFDO0lBQ1QsSUFBSSxLQUFLLGtCQUFrQixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztJQUM1QyxPQUFPLG9CQUFBLEtBQUksRUFBQSxJQUFDLEVBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFBLENBQUMsSUFBSSxDQUFBLEtBQUssQ0FBQSxPQUFBLG9CQUFBLE1BQUssRUFBQSxJQUFDLEVBQUMsSUFBWSxDQUFBLEVBQUEsQ0FBUSxDQUFBLENBQUM7R0FDOUQ7QUFDSCxDQUFDLENBQUMsQ0FBQzs7QUFFSCxRQUFRLENBQUMsTUFBTSxDQUFDLG9CQUFDLFdBQVcsRUFBQSxDQUFBLENBQUMsS0FBQSxFQUFLLENBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFFLENBQUEsQ0FBRyxDQUFBLEVBQUUsU0FBUyxDQUFDLENBQUMiLCJmaWxlIjoidHJhbnNmb3JtZWQuanMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgdmFyIE1vcmVNZXNzYWdlID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICByZW5kZXIgKCkge1xuICAgIHZhciBuYW1lczogQXJyYXk8c3RyaW5nPiA9IHRoaXMucHJvcHMubmFtZXM7XG4gICAgcmV0dXJuIDxkaXY+e25hbWVzLm1hcCgobmFtZSkgPT4gPHNwYW4+e25hbWV9PC9zcGFuPil9PC9kaXY+O1xuICB9XG59KTtcblxuUmVhY3RET00ucmVuZGVyKDxNb3JlTWVzc2FnZSBuYW1lcz17W1wiSm9oblwiLCBcIk1hcnlcIl19IC8+LCBtb3VudE5vZGUpO1xuIl19
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ReactJS Source Compiler
2 |
3 | 
4 |
5 | - The master series is for React 0.14.x
6 | - The [0.4.x](https://github.com/ddispaltro/sbt-reactjs/tree/0.4.x) series is for React 0.12
7 | - The [0.3.x](https://github.com/ddispaltro/sbt-reactjs/tree/0.3.x) series is for React 0.11
8 | - The [0.2.x](https://github.com/ddispaltro/sbt-reactjs/tree/0.2.x) series is for React 0.10
9 |
10 | This plugin hooks your JSX files in to the Asset compilation phase.
11 | It uses the autoPlugin feature with `0.13.5` to make the setup dead-simple.
12 |
13 | To use this plugin use the addSbtPlugin command within your project's
14 | plugins.sbt (or as a global setting) i.e.:
15 |
16 | ```scala
17 | addSbtPlugin("com.github.ddispaltro" % "sbt-reactjs" % "0.6.8")
18 | ```
19 |
20 | Your project's build file also needs to enable sbt-web plugins. For example with build.sbt:
21 |
22 | ```scala
23 | lazy val root = (project in file(".")).enablePlugins(SbtWeb)
24 | ```
25 |
26 | ## Options
27 |
28 | - `harmony`: Turns on JS transformations such as ES6 Classes etc.
29 | - `stripTypes`: Strips out type annotations.
30 | - `sourceMapInline`: Embed inline sourcemap in transformed source
31 |
32 | The artifact is hosted as part of the [community plugins](http://www.scala-sbt.org/0.13.5/docs/Community/Bintray-For-Plugins.html)
33 | via [bintray service](https://bintray.com/ddispaltro/sbt-plugins/sbt-reactjs/view).
34 |
35 |
36 | ## License
37 |
38 | `sbt-reactjs` is licensed under the [Apache License, Version 2.0](./LICENSE)
39 |
--------------------------------------------------------------------------------
/src/main/resources/jsx.js:
--------------------------------------------------------------------------------
1 | /*global process, require */
2 |
3 | (function () {
4 |
5 | "use strict";
6 |
7 | var args = process.argv,
8 | fs = require("fs"),
9 | mkdirp = require("mkdirp"),
10 | path = require("path"),
11 | jsx = require('react-tools');
12 |
13 | var SOURCE_FILE_MAPPINGS_ARG = 2;
14 | var TARGET_ARG = 3;
15 | var OPTIONS_ARG = 4;
16 |
17 | var sourceFileMappings = JSON.parse(args[SOURCE_FILE_MAPPINGS_ARG]);
18 | var target = args[TARGET_ARG];
19 | var options = JSON.parse(args[OPTIONS_ARG]);
20 |
21 | var sourcesToProcess = sourceFileMappings.length;
22 | var results = [];
23 | var problems = [];
24 |
25 | function compileDone() {
26 | if (--sourcesToProcess === 0) {
27 | console.log("\u0010" + JSON.stringify({results: results, problems: problems}));
28 | }
29 | }
30 |
31 | function throwIfErr(e) {
32 | if (e) throw e;
33 | }
34 |
35 | function endsWith(str, suffix) {
36 | return str.indexOf(suffix, str.length - suffix.length) !== -1;
37 | }
38 |
39 | sourceFileMappings.forEach(function (sourceFileMapping) {
40 |
41 | var input = sourceFileMapping[0];
42 | var outputFile = sourceFileMapping[1].replace(".jsx", ".js");
43 | var output = path.join(target, outputFile);
44 |
45 | fs.readFile(input, "utf8", function (e, contents) {
46 | throwIfErr(e);
47 |
48 | try {
49 | var compileResult = jsx.transform(contents, options);
50 |
51 | mkdirp(path.dirname(output), function (e) {
52 | throwIfErr(e);
53 |
54 | var js = compileResult.code;
55 | if (js === undefined) {
56 | js = compileResult;
57 | }
58 |
59 | fs.writeFile(output, js, "utf8", function (e) {
60 | throwIfErr(e);
61 |
62 | results.push({
63 | source: input,
64 | result: {
65 | filesRead: [input],
66 | filesWritten: [output]
67 | }
68 | });
69 |
70 | compileDone();
71 | });
72 | });
73 |
74 | } catch (err) {
75 | problems.push({
76 | message: err.message,
77 | severity: "error",
78 | lineNumber: err.lineNumber,
79 | characterOffset: err.column - 1,
80 | lineContent: contents.split("\n")[err.lineNumber - 1],
81 | source: input
82 | });
83 | results.push({
84 | source: input,
85 | result: null
86 | });
87 |
88 | compileDone();
89 | }
90 | });
91 | });
92 | })();
93 |
--------------------------------------------------------------------------------
/src/main/scala/com/github/ddispaltro/reactjs/SbtReactJs.scala:
--------------------------------------------------------------------------------
1 | package com.github.ddispaltro.reactjs
2 |
3 | import sbt._
4 | import sbt.Keys._
5 | import com.typesafe.jse._
6 |
7 | import scala.collection.{JavaConversions, immutable}
8 | import com.typesafe.npm.NpmLoader
9 | import com.typesafe.sbt.web.pipeline.Pipeline
10 | import akka.util.Timeout
11 |
12 | import scala.concurrent.{Await, ExecutionContext, Future}
13 | import com.typesafe.sbt.web.{CompileProblems, SbtWeb, incremental}
14 |
15 | import scala.concurrent.duration._
16 | import com.typesafe.sbt.jse.{SbtJsEngine, SbtJsTask}
17 | import com.typesafe.jse.Engine.JsExecutionResult
18 | import akka.actor.ActorRef
19 | import akka.pattern.ask
20 |
21 | import scala.util.control.Exception._
22 | import com.typesafe.sbt.web.incremental.{OpInputHash, OpInputHasher, OpSuccess}
23 | import spray.json._
24 | import DefaultJsonProtocol._
25 |
26 | import scala.collection.mutable.ListBuffer
27 | import org.mozilla.javascript.Context
28 | import org.mozilla.javascript.Function
29 | import org.mozilla.javascript.NativeObject
30 | import org.mozilla.javascript.Scriptable
31 | import org.mozilla.javascript.commonjs.module.Require
32 | import org.mozilla.javascript.commonjs.module.RequireBuilder
33 | import org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider
34 | import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider
35 | import com.typesafe.jse.Engine.JsExecutionResult
36 | import com.typesafe.sbt.web.Import.WebKeys
37 |
38 |
39 | object Import {
40 |
41 |
42 |
43 | object ReactJsKeys {
44 |
45 | val reactJs = TaskKey[Seq[File]]("reactjs", "Perform ReactJS JSX compilation on the asset pipeline.")
46 |
47 | val timeout = SettingKey[FiniteDuration]("reactjs-timeout", "How long before timing out JS runtime.")
48 | val harmony = SettingKey[Boolean]("reactjs-harmony", "Support harmony features.")
49 | val es6module = SettingKey[Boolean]("reactjs-es6module", "Support ES6 modules.")
50 | val stripTypes = SettingKey[Boolean]("reactjs-strip-types", "Strips out type annotations.")
51 | val sourceMapInline = SettingKey[Boolean]("reactjs-source-map-inline", "Embed inline sourcemap in transformed source.")
52 | }
53 |
54 | }
55 |
56 | object SbtReactJs extends AutoPlugin {
57 |
58 | override def requires = SbtJsTask
59 |
60 | override def trigger = AllRequirements
61 |
62 | val autoImport = Import
63 |
64 | import SbtWeb.autoImport._
65 | import WebKeys._
66 | import SbtJsTask.autoImport.JsTaskKeys._
67 | import autoImport.ReactJsKeys._
68 |
69 |
70 |
71 | val reactJsScriptUnscopedSettings = Seq(
72 |
73 | includeFilter := "*.jsx",
74 |
75 | jsOptions := JsObject(
76 | "harmony" -> JsBoolean(harmony.value),
77 | "es6module" → JsBoolean(es6module.value),
78 | "stripTypes" -> JsBoolean(stripTypes.value),
79 | "sourceMap" -> JsBoolean(sourceMapInline.value)
80 | ).toString()
81 | )
82 |
83 | override def buildSettings = inTask(reactJs)(
84 | SbtJsTask.jsTaskSpecificUnscopedBuildSettings ++ Seq(
85 | moduleName := "reactjs",
86 | shellFile := getClass.getClassLoader.getResource("jsx.js")
87 | )
88 | )
89 |
90 | override def projectSettings = Seq(
91 | harmony := false,
92 | es6module := false,
93 | stripTypes := false,
94 | sourceMapInline := false
95 | ) ++ inTask(reactJs)(
96 | SbtJsTask.jsTaskSpecificUnscopedProjectSettings ++
97 | inConfig(Assets)(reactJsScriptUnscopedSettings) ++
98 | inConfig(TestAssets)(reactJsScriptUnscopedSettings) ++
99 | Seq(
100 | Assets / taskMessage := "ReactJS compiling",
101 | TestAssets / taskMessage := "ReactJS test compiling"
102 | )
103 | ) ++ SbtJsTask.addJsSourceFileTasks(reactJs) ++ Seq(
104 | Assets / reactJs := (Assets / reactJs).dependsOn(Assets / webModules, Assets / nodeModules).value,
105 | TestAssets / reactJs := (TestAssets / reactJs).dependsOn(TestAssets / webModules, TestAssets / nodeModules).value
106 | )
107 |
108 |
109 |
110 | }
111 |
--------------------------------------------------------------------------------