Upload
spring-by-pivotal
View
384
Download
0
Embed Size (px)
Citation preview
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
SPRINGONE2GXWASHINGTON, DC
Grooscript in ActionBy Jorge Franco Leza
@jfrancoleza
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
About me
2
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Thank you!
3
3 years since first commit
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Agenda• Introduction to grooscript• Convert your groovy code to javascript• Support• PhantomJs and tools• Gradle plugin• Demo• Grails plugin• Working with javascript• Require.js• Future
4
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Introduction to grooscript• Library (jar)• Groovy 2.0+ to javascript ECMA 5• Apache 2 license• Source code http://github.com/chiquitinxx/grooscript• Converted code needs grooscript.js to run• Tools around: gradle and grails plugins, npm and bower packages• Documentation http://grooscript.org/doc.html• Demos http://github.com/chiquitinxx/grooscript-demos• Try live! http://grooscript.org/conversions.html
5
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Why grooscript?• You have all java / groovy tools to create code in the client side.• Javascript is fast.• Enjoy javascript! Create your own magic.• Don’t repeat code in two languages, isomorphic code.• Use groovy templates everywhere.• Single development environment.• Stop learning “to javascript” things.• Static type if you want to.• But… mainly… because it is…
6
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Groovy
7
Readable
Concise
Expressive
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
ASTS
8
@Component class Counter implements Colorable { Integer number void init() { number = null } void render() { div(class: "widget bg-${randomColor()}") { if (number) { p 'Number of books' em number.toString() a(href:"#", class:"button", onclick: 'bookPresenter.showBooks()') { yield 'Show' } } else { p 'Counting books...' } } } }
AST’sGetter / Setters
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
List and maps
9
def start() { def countries = loadCountries(). findAll { it.population > 100000}. unique { it.alpha3Code } countries.each { country -> customSigma.addNode id: country.alpha3Code,
x: country.latlng[1], color: ‘purple’ } countries.each { country -> country.borders?.each { border -> this.&hello(border) } } updateNumberCountries countries.size() customSigma.refresh()}
Lists and maps
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
DSL's
10
server { get('/') { render Templates.applyTemplate('index.gtpl') } on('login') { data, socket -> if (data.name && !socket.login) { socket.login = data.name socket.emit 'loginok', [name: data.name] socket.broadcast.emit 'loginok', [name: data.name] } } on('msg') { data, socket -> if (data.msg && socket.login) { socket.broadcast.emit 'msg', [msg: data.msg] } } on('disconnect') { socket -> if (socket.login) { socket.broadcast.emit 'off', [name: socket.login] } }}.start()
Dsl’s
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Metaprogramming
11
class Hello { def methodMissing(String name, args) { println "Hello ${name}!" }}
def hello = new Hello()hello.Groovy()hello.Javascript()hello.grooscript()
Metaprogramming
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Functional
12
def plus2 = { it + 2 }def times3 = { it * 3 }
def times3plus2 = plus2 << times3
assert times3plus2(3) == 11
def plus2times3 = times3 << plus2
assert plus2times3.curry(5)() == 21
Functional
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Convert your groovy code to javascript
13
@Grab('org.grooscript:grooscript:1.2.0')
import org.grooscript.GrooScript
String result = GrooScript.convert ''' def sayHello = { println "Hello ${it}!" } ['Groovy','JavaScript','GrooScript'].each sayHello'''
new File(‘out.js’) << result
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Convert your groovy code to javascript
14
Let’s see it in action
http://grooscript.org/doc.html
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Conversion options• classpath• customization { -> ast(TypeChecked)}• initialText, finalText• recursive• mainContextScope [''$'', ‘'window'', ''myFunction'']• addGsLib• requireJsModule• consoleInfo• includeDependencies
15
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Support• Groovy core• Classes, numbers, lists, maps, sets, date, ranges, closures, (g)strings,
operators, groovy truth, Expando, categories, traits, beans, switch, metaprogramming, enum, equals, multiple assignment, optional params, default constructor, pointer methods, operator overload, regular expressions, @Delegate, @Category, …
• Dsl’s. (@DelegatesTo)• Ast’s at semantic analysis phase.• Packaging in js with require.js.• Be groovier!
16
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Not supported• Not groovy-core (json, builders, I/O, …)• Java / Groovy Types (Thread, LinkedHashMap, Stack, Optional, …) • Super except constructors.• Methods with same name (overload), classes with same name.• Java 8 stuff not supported by groovy• Module extensions, complex metaprogramming, groovy AST’s after Semantic
Phase
17
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Annotations
18
import org.grooscript.asts.GsNotConvert
@GsNotConvertclass ClassNotConvert { def a}
class A {@GsNotConvertdef methodNoConvert() {
‘No!’}
def hello() {println ‘Hello!’
}}
import org.grooscript.asts.GsNative
class Data {@GsNativevoid saySomething(String smt) {/*
console.log(smt);*/}
@GsNativedef five() {/*
return 5;*/ 1 + 1 + 3}
}
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
PhantomJs test
19
@GrabConfig(systemClassLoader = true)@Grab(‘org.grooscript:grooscript:1.2.0’)
import org.grooscript.asts.PhantomJsTest
//Need phantomjs installedSystem.setProperty(‘PHANTOMJS_HOME’, ‘path/to/phantomjs’)
@PhantomJsTest(url = 'http://beta.groovy-lang.org/') void testCountLinks() { def links = $('a') assert links.size() > 40, "Number of links: ${links.size()}" links.toArray().collect { it.toString() }.each { link -> println link }}
testCountLinks()
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Javascript libs• grooscript.js (87 kb) (8 kb minified and gziped)• grooscript.min.js (33 kb)• grooscript-tools.js (14 kb) (GQuery, HtmlBuilder, Observable)
20
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
HtmlBuilder
21
given:def result = HtmlBuilder.build { body { ul(class: 'list', id: 'mainList') { 2.times { number -> li number + 'Hello!' } } }}
expect:result == "<body><ul class='list' id=‘mainList'><li>0Hello!</li><li>1Hello!</li></ul></body>"
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
GQuery
22
import org.grooscript.jquery.GQueryImpl
def result = new Result()def gQuery = new GQueryImpl()gQuery.onReady { gQuery.doRemoteCall(“${JSON_ADDRESS}”, 'GET', null, { res -> gQuery('.result').html('OK') result = res }, { result = 'FAIL!' }, Result)}
https://github.com/chiquitinxx/grooscript/blob/master/src/main/groovy/org/grooscript/jquery/GQuery.groovy
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Observable
23
given:def result = []Observable.from([1, 5, 9, 12, 3, 8]). filter { it < 5 }. map { 'H' * it }. subscribe { event -> result << event }
expect:result == ['H', 'HHH']
https://github.com/chiquitinxx/grooscript/blob/master/src/test/groovy/org/grooscript/rx/ObservableSpec.groovy
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Gradle plugin• Starting guide http://grooscript.org/starting_gradle.html• Listen to changes and does conversions in background.• Groovy templates in the client side.• Can use with your grails 3+ application.• Create require.js modules.• Notification of changes using websockets.• Thread tasks can block execution.• Info about tasks http://grooscript.org/gradle/tasks.html
24
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
task convertConvert groovy files to javascript. Can add conversion options.
25
grooscript { source = ['src/main/groovy'] destination = 'js'}
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/ 26
task convertThread
grooscript { source = [‘src/main/groovy/presenters'] destination = 'js' classpath = ['src/groovy'] initialText = '//Converted file' recursive = true
blockExecution = true}
Listen to changes in groovy files, and convert them to javascript when modified. Can block gradle execution.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/ 27
task initStaticWeb
"## build.gradle$## src $## main "## groovy % $## Presenter.groovy $## webapp "## index.html $## js "## app $## lib "## grooscript-tools.js "## grooscript.min.js $## jquery.min.js
Creates a static web project to starting play with grooscript.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/ 28
task templatesJs
class Templates {
static Map<String, Closure> templates
static String applyTemplate(String name, model = [:]) { Closure cl = templates[name] cl.delegate = model cl(model) }}
Convert groovy templates to a javascript file.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/ 29
task templatesThread
templates { templatesPath = 'templates' templates = ['main.gtpl', 'little/small.tpl'] destinationFile = 'js/Templates.js' classpath = ['src/groovy'] customTypeChecker = 'aCustomTypeCheckerFile.groovy'}
Listen to changes in groovy templates and generate a new javascript template file when something changes. Can block gradle execution.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/ 30
task spyChanges
spy { files = ['Templates.js'] onChanges = { list ->
springWebsocketTo 'http://localhost:8080/demo' data 'templates' onChannel '/app/reload'
}}
Listen to file changes and execute groovy code when files change. Can send a message using websockets.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/ 31
task requireJs
requireJs { sourceFile = 'src/main/groovy/MyApp.groovy' destinationFolder = 'src/main/resources/web/js/app'}
Convert groovy file to require.js javascript module. Also all dependencies are converted.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
task requireJsThread
32
requireJs { sourceFile = ‘starting/InitialFile.groovy' classpath = ['src/main/groovy'] destinationFolder = ‘js/app'
blockExecution = true}
Listen to changes in groovy file or any dependency file, and generate require.js javascript modules when files change. Also can block execution.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/ 33
Demo gradle books
More action
https://github.com/chiquitinxx/books-demo
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Grails plugin• A grails 2 version, 0.8 https://grails.org/plugin/grooscript.• Grails 3 version, version 1.1.2, documentation http://grooscript.org/grails3-
plugin.• Adding tags for your gsp’s.• Converting files with gradle plugin in grails 3+.• Using your domain classes in your gsp’s. *experimental*• Uses asset pipeline and cache plugins, also jquery for some tags.• Requires <asset:javascript src="grooscript-grails.js"/>• Events in your gsp's with groovy.• Websockets support using spring websockets.• Templating in your gsp’s with HtmlBuilder.
34
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
grooscript:code
35
<grooscript:code> [‘groovy’, ‘javascript’].each {
println “Hello $it” }</grooscript:code>
<asset:script>… js code …
</asset:script>
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
grooscript:template
36
<grooscript:template onLoad=“false" functionName=“refreshList"> ul { data.each { book -> li { p 'Id: ' + book.id + ' Name: ' + book.title } } }</grooscript:template>
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
websockets
37
<grooscript:initSpringWebsocket> println 'Connected! Websocket is up!’ GrooscriptGrails.sendWebsocketMessage("/app/hello", “Hello!")</grooscript:initSpringWebsocket><grooscript:onServerEvent path="/topic/books" type="Book"> data.each { book -> $("#helloDiv").append '<p>'+book.coolFormat()+'</p>' }</grooscript:onServerEvent>
Use spring websockets in your gsp’s. Have to include client libraries.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
events
38
<grooscript:code> $(document).ready { def eventData = 'Application started.' gsEvents.sendMessage('newEvent', eventData) gsEvents.onEvent('delete', { book -> $('#deleteEvent').html 'Deleted ' + book.title }) }</grooscript:code><grooscript:onEvent name="newEvent"> console.log event</grooscript:onEvent>
Manage events in the client using groovy.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
grooscript:remoteModel
39
<grooscript:remoteModel domainClass="Book"/><grooscript:code> import rest.Book
Book.list().then { list -> $('#bookList').html '' list.each addBook }</grooscript:code>
Use your domain classes from your gsp’s. Domain classes annotated with @Resource, using json.
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Demo grails 3
40
Final action
https://github.com/chiquitinxx/circles
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Working with javascript
41
class MyClass {} function MyClass() { … }
var myClass = MyClass();// NO var myClass = new MyClass();var myClass = MyClass({prop1: ‘value’, prop2: 12 });myClass.method();// NO myClass.metaprogrammingMethod();myClass.method(numberOrStringOrList);// beware maps! myClass.method({ a: 1, b: 2 });
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Combine both worlds
42
import static org.grooscript.GrooScript.toJavascriptimport static org.grooscript.GrooScript.toGroovy
def map = [x: 1, y: 2]
//point is a javascript objectpoint.init(map) //[BAD] Passing a groovy object to javascript, can failpoint.init(toJavascript(map)) //[GOOD] You now are passing {x: 1, y: 2}
//point has a method info() that returns a javascript objectdef badData = point.info() //[BAD] You will have a 'javascript' objectdef goodData = toGroovy(point.info()) //[GOOD] goodData as a 'groovy' object
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Tips• Keep your groovy code tested.• If you use @GsNative, keep that code in isolated classes, that can be easy to
mock them.• Don’t abuse @GsNative, is untested code.• You can activate debug console info in javascript with gs.consoleInfo = true;• You can test dom manipulation with jsoup.• Try to stay functional, don’t abuse ‘this’ or variables from other contexts.• Curry functions to inject variables rather than expecting them to be available
after callbacks hell.
43
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Require.js• Javascript file and module loader.• Can be used in browser, rhino and Node.js environments.• Optimization using google closure compiler.
44
requirejs.config({ baseUrl: 'jsModules', paths: { lib: 'js/lib' }});
requirejs(['lib/grooscript.min'], function() { requirejs(['Initial']);});
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Require.js
45
import org.grooscript.GrooScript
Map conversionOptions = [classpath: 'src/main/groovy']GrooScript.convertRequireJs('src/main/groovy/Initial.groovy', 'jsModules', conversionOptions)
define(function() { function Initial() { … } return Initial;});
class Initial {}
src/main/groovy/Initial.groovy jsModules/Initial.js
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Require.js
46
define(['lib/data'], function (data) {
function Require() { //.. gSobject.data = data; //..
return gSobject; };
return Require;});
package files
import org.grooscript.asts.RequireJsModule
class Require { @RequireJsModule(path = 'lib/data') def data}
src/main/groovy/files/Require.groovy jsModules/files/Require.js
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Future
47
ECMAScript 2015
Unless otherwise indicated, these sl ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/ 48
Q & A