Skip to content
This repository has been archived by the owner on May 23, 2019. It is now read-only.

Commit

Permalink
Update #97: add JSX support for Play devel mode, and JSX debug direct…
Browse files Browse the repository at this point in the history
… to client.
  • Loading branch information
hdsdi3g committed Apr 4, 2015
1 parent 0fcc553 commit 65e6965
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 7 deletions.
89 changes: 88 additions & 1 deletion app/controllers/AsyncJS.java
Expand Up @@ -16,14 +16,101 @@
*/
package controllers;

import hd3gtv.log2.Log2;
import hd3gtv.mydmam.web.JSXTransformer;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;

import org.mozilla.javascript.JavaScriptException;

import play.data.validation.Required;
import play.mvc.Controller;
import play.mvc.With;

@With(Secure.class)
public class AsyncJS extends Controller {

// Secure.checkview()

// TODO

public static void index() throws Exception {
// String js = JSXTransformer.global.transform("React.renderComponent(\n<h1>Hello, world!</h1>,\ndocument.getElementById('example')\n);");
}

public static void dynamicCompileJSX(@Required String ressource_name) {
try {
String jsx_compiled = JSXTransformer.getJSXContentFromURLList(ressource_name, true);
response.setHeader("Content-Length", jsx_compiled.length() + "");
response.setHeader("Content-Type", "text/javascript");
renderText(jsx_compiled);
} catch (Exception e) {
if (e instanceof JavaScriptException) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(baos);
pw.println("/** JSX ERROR */");
pw.println("new function(){");
pw.println(" $(document).ready(function() {");
pw.println(" var message = {}");
pw.println(" message.from = \"" + ressource_name + "\";");
pw.println(" message.text = \"" + e.getMessage().replaceAll("\"", "'") + "\";");
pw.println(" ");
pw.println(" ");
pw.println(" jsx_error_messages.push(message);");
pw.println(" });");
pw.println("}();");
// e.printStackTrace();
pw.close();

String error_message = new String(baos.toByteArray());
response.setHeader("Content-Length", error_message.length() + "");
response.setHeader("Content-Type", "text/javascript");
renderText(error_message);
} else {
Log2.log.error("JSX Transformer Error", e);
}
}
}
/*
http://facebook.github.io/react/docs/getting-started.html
*
if (Play.mode == Mode.PROD) {
} else {
}
Play, 2 modes pour JS
- debug JS
- prod
React
3 JS:
- min prod = prod
- debug Devel = devel
- jsx transf = devel
Jsx dans dossier à part non pub
JS non compiles dans un dossier à part non pub
Groovy/views déclare soit le ctrler avec les noms des jsx/JS en param, soit les liens publiques.
+ les Lib en auto
Check avec un module fait exprès.
Mode devel:
Appel tous les JS via un vrai ctrl Play
Chaque JSX est compile in Fly et le JS est envoyé in Fly
Mode prod:
Au boot
Compile les JSX
Les optimises avec les autres JS
Assemble tout dans un fichier unique.
Todo: i18n avec React, avec les params.
Todo: transformation JSX dynamique depuis groovy
Ajax: une classe contrôleur unique, avec des helpers pour les Validations et les Gson, qui fourni une liste de points de comm a JS en se basant sur les droits du ctrl (Check).
Surchargeable par module ?
Via une déclaration de f via une interface qui fait tout en un (de/serial, throw).
*
* */
}
140 changes: 140 additions & 0 deletions app/hd3gtv/mydmam/web/JSXTransformer.java
@@ -0,0 +1,140 @@
/*
* This file is part of MyDMAM.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* Copyright (C) hdsdi3g for hd3g.tv 2015
*
* Imported and forked from https://gist.github.com/mingfang/3784a0a6e58c24dda687
*
*/
package hd3gtv.mydmam.web;

import hd3gtv.log2.Log2;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.commonjs.module.ModuleScriptProvider;
import org.mozilla.javascript.commonjs.module.Require;
import org.mozilla.javascript.commonjs.module.RequireBuilder;
import org.mozilla.javascript.commonjs.module.provider.ModuleSourceProvider;
import org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider;
import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider;

import play.mvc.Router;
import play.vfs.VirtualFile;
import controllers.AsyncJS;

public class JSXTransformer {

public static final String JSXTRANSFORMER_PATH = "/public/javascripts/lib/JSXTransformer.js";
public static final String JSX_SRC = "/app/react";

public static final JSXTransformer global;

static {
global = new JSXTransformer();
}

private Context ctx;
private Scriptable exports;
private Scriptable topLevelScope;
private Function transform;
private boolean is_init = false;

private JSXTransformer() {
try {
File jsxtransformer_file = VirtualFile.fromRelativePath(JSXTRANSFORMER_PATH).getRealFile().getAbsoluteFile();
if (jsxtransformer_file.exists() == false) {
throw new FileNotFoundException(JSXTRANSFORMER_PATH);
}

ctx = Context.enter();
RequireBuilder builder = new RequireBuilder();

List<URI> uris = new ArrayList<URI>();
URI uri = jsxtransformer_file.getParentFile().getAbsoluteFile().toURI().resolve("");
uri = new URI(uri + "/");
uris.add(uri);

ModuleSourceProvider url_module_script_provider = new UrlModuleSourceProvider(uris, null);

ModuleScriptProvider sc_module_script_provider = new SoftCachingModuleScriptProvider(url_module_script_provider);

builder.setModuleScriptProvider(sc_module_script_provider);

topLevelScope = ctx.initStandardObjects();
Require require = builder.createRequire(ctx, topLevelScope);

exports = require.requireMain(ctx, jsxtransformer_file.getName());
transform = (Function) exports.get("transform", topLevelScope);
is_init = true;
} catch (Exception e) {
Log2.log.error("Can't load JSXTransformer", e);
} finally {
Context.exit();
}
}

public String transform(String jsx) throws InstantiationError {
if (is_init == false) {
throw new InstantiationError("JSXTransformer is not instantiated correctly");
}
Context.enter();
try {
NativeObject result = (NativeObject) transform.call(ctx, topLevelScope, exports, new String[] { jsx });
return result.get("code").toString();
} finally {
Context.exit();
}
}

public static List<String> getJSXURLList() {
List<String> list = new ArrayList<String>();

List<VirtualFile> jsx_vfiles = VirtualFile.fromRelativePath(JSX_SRC).list();

VirtualFile jsx_file;
HashMap<String, Object> args = new HashMap<String, Object>();
for (int pos = 0; pos < jsx_vfiles.size(); pos++) {
jsx_file = jsx_vfiles.get(pos);
if (jsx_file.getName().endsWith(".jsx") == false) {
continue;
}
args.put("ressource_name", jsx_file.getName());
list.add(Router.reverse(AsyncJS.class.getName() + "." + "dynamicCompileJSX", args).url);
}

Collections.sort(list);
return list;
}

public static String getJSXContentFromURLList(String ressource_name, boolean transfrom) throws FileNotFoundException {
VirtualFile v_file = VirtualFile.fromRelativePath(JSX_SRC + "/" + ressource_name);
if (v_file.exists() == false) {
throw new FileNotFoundException(JSX_SRC + " / " + ressource_name);
}
if (transfrom == false) {
v_file.contentAsString();
}
return global.transform(v_file.contentAsString());
}
}
8 changes: 3 additions & 5 deletions app/hd3gtv/mydmam/web/JsCompile.java
Expand Up @@ -36,11 +36,9 @@
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.mozilla.javascript.ErrorReporter;
import org.mozilla.javascript.EvaluatorException;

import play.Play;
import play.vfs.VirtualFile;
import yuiforkorgmozillajavascript.ErrorReporter;

import com.yahoo.platform.yui.compressor.JavaScriptCompressor;

Expand Down Expand Up @@ -242,7 +240,7 @@ public void error(String arg0, String arg1, int arg2, String arg3, int arg4) {
Log2.log.error("Rhino error during javascript parsing", null, dump);
}

public EvaluatorException runtimeError(String arg0, String arg1, int arg2, String arg3, int arg4) {
public yuiforkorgmozillajavascript.EvaluatorException runtimeError(String arg0, String arg1, int arg2, String arg3, int arg4) {
Log2Dump dump = new Log2Dump();
dump.add("arg0", arg0);
dump.add("arg1", arg1);
Expand Down Expand Up @@ -289,7 +287,7 @@ private static void compile(VirtualFile sourcefile, VirtualFile binaryfile) thro
in.close();

OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(binaryfile.getRealFile()));
compressor.compress(out, null, 200, true, Play.mode.isDev(), true, false);
compressor.compress(out, 200, true, Play.mode.isDev(), true, false);
out.close();

compiled_db.put(binaryfile.getName(), new Db(sourcefile));
Expand Down
6 changes: 6 additions & 0 deletions app/react/helloworld.jsx
@@ -0,0 +1,6 @@
$(document).ready(function() {
React.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
});
23 changes: 22 additions & 1 deletion app/views/maingrid.html
Expand Up @@ -52,16 +52,29 @@
<script src="@{'/public/javascripts/lib/es5-shim-2.0.8.min.js'}"></script>
<![endif]-->

%{ if (play.mode.toString() == "DEV"){ }%
<script src="@{'/public/javascripts/lib/react-with-addons.js'}" type="text/javascript" charset="UTF-8"></script>
#{list hd3gtv.mydmam.web.JSXTransformer.getJSXURLList(), as:'item'}
<script src="&{item}" type="text/javascript" charset="UTF-8"></script>
#{/list}
%{ } else { }%
<script src="@{'/public/javascripts/lib/react-with-addons.min.js'}" type="text/javascript" charset="UTF-8"></script>
%{ } }%

#{list hd3gtv.mydmam.web.JsCompile.getURLlist(), as:'item'}
#{script src:item, charset:'utf-8' /}
#{/list}
<script type="text/javascript" charset="UTF-8"><!-- #{include 'routes.js'/} --></script>
<script src="@{Application.i18n()}" type="text/javascript" charset="UTF-8"></script>

#{get 'moreScripts' /}
</head>

<body>

<script type="text/javascript" charset="UTF-8">
var jsx_error_messages = [];

<!--
$(document).ready(function() {
$(function () {
Expand All @@ -87,10 +100,14 @@
$(this).remove();
}
});
//
//data-deleteifempty="mainadminmenu">
//<ul class="dropdown-menu" id="mainadminmenu">

if (jsx_error_messages.length > 0) {
for (pos = 0; pos < jsx_error_messages.length; pos++) {
console.log("Error in " + jsx_error_messages[pos].from + " from server side:\n" + jsx_error_messages[pos].text);
}
}
});
});
-->
Expand Down Expand Up @@ -295,5 +312,9 @@
<div class="container-fluid" style="text-align:center; margin-top: 2em;">
<small class="muted"><a href="http://mydmam.org" style="color: #999999;">MyDMAM</a> &{'site.aboutfooter'}</small>
</div>


<div id="example"></div>

</body>
</html>
1 change: 1 addition & 0 deletions conf/routes
Expand Up @@ -10,6 +10,7 @@ GET /favicon.ico 404

# Map static resources from the /app/public folder to the /public path
GET /public/ staticDir:public
GET /raw-jsx/{ressource_name} AsyncJS.dynamicCompileJSX

GET /login Secure.login
POST /login Secure.authenticate
Expand Down
File renamed without changes.

0 comments on commit 65e6965

Please sign in to comment.