From f6d80fc206e9040da46f4f795bdac4b77adec37a Mon Sep 17 00:00:00 2001 From: Sanjana Date: Mon, 23 Mar 2026 01:04:14 +0530 Subject: [PATCH] chore: add missing alt tags to images for accessibility --- README.md | 4 +- pages/index.html | 2 +- posts/2016-05-28.md | 1274 ++++++++--------- posts/2016-08-01.md | 330 ++--- posts/2016-10-03.md | 764 +++++----- posts/2016-11-14.md | 234 +-- ...-publish-grails-plugin-to-maven-central.md | 2 +- 7 files changed, 1305 insertions(+), 1305 deletions(-) diff --git a/README.md b/README.md index 8569380ef8f..07cb56fe02d 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ The process to deploy Grails 3.1 applications to JBoss 6.4 EAP is largely simila If you write often to Grails's blog, we recommend you to create a [Text Expander](https://textexpander.com) snippet: - ![](docs/textexpander.png) + ![TextExpander snippet example](docs/textexpander.png) #### Title Metadata @@ -223,7 +223,7 @@ image: 2018-05-23.jpg Place the images at `assets/bgimages` -![](docs/blogimages.png) +![Blog images directory structure](docs/blogimages.png) ### Tags diff --git a/pages/index.html b/pages/index.html index 55bdf126a81..8ec5fac4560 100644 --- a/pages/index.html +++ b/pages/index.html @@ -84,7 +84,7 @@

REST APIs, REACT, ANGULAR

developers to build REST APIs or modern web applications with a JavaScript frontend.

- + Grails Plugins Logo

Plugins

Developers can build plugins that extend and enhance the Grails framework, or they can access existing plugins published by a vibrant plugin community.

diff --git a/posts/2016-05-28.md b/posts/2016-05-28.md index 0b425d0350f..514f2958678 100644 --- a/posts/2016-05-28.md +++ b/posts/2016-05-28.md @@ -1,637 +1,637 @@ -title: Using React with the Grails® framework -date: May 28, 2016 -description: React is a powerful and exciting library, and it’s a great choice for Grails® applications. -author: Zachary Klein -image: 2016-05-28.jpg -CSS: [%url]/stylesheets/prism.css -JAVASCRIPT: [%url]/javascripts/prism.js ---- - -# [%title] - -[%author] - -[%date] - -Tags: #react #javascript #gradle - -**React**, the JavaScript library from Facebook, has become a popular view technology for building dynamic, testable and performant user interfaces. While not a full-fledged framework like Angular or Ember, React’s focus on functional component-based views with no (or minimal) internal state makes it a great choice when building single page applications (SPA) or even dynamic subcomponents within a page-based application. - -Because it doesn't make assumptions about data-flow or controller logic outside of rendering the view, React relies on the developer to either provide these features directly in JavaScript or use another framework as a backend to support the React-based UI. - -It is this flexibility, in part, that makes React an appealing choice as a modern JavaScript view layer for **Grails**® applications. Grails provides a robust backend built upon Spring Boot, GORM, and the Groovy programming language, as well as excellent support for generating restful endpoints that can be consumed by our React application. Since Grails 3 is also based upon Gradle, we can leverage [Gradle’s Node plugin](https://github.com/srs/gradle-node-plugin) to unify our build and testing pipeline for both Grails and React, without needing to complicate our deployment processes. - -Finally, **JSX** (React's XML-like syntax for defining components and page markup) is a powerful and flexible way to create dynamic views. In the author's opinion, creating components in JSX is quite analogous to defining custom GSP tags in a Grails taglib: a function which receives state via props (GSP `attrs`) and typically (but not always) renders markup based on that state. In React's case, these components are re-rendered upon every change to the app's state, rather than being limited to page-load. This stateless component model should be understandable to Grails developers who have written [custom GSP tags](https://objectcomputing.com/resources/publications/sett/december-2015-custom-gsp-tags-grails-best-kept-secret/), and JSX takes this to the next level. - -In this article, we'll demonstrate how to integrate React into a Grails 3 application, using some of Grail’s restful features to get up and running quickly. We’ll spend a bit of time getting our project set up, and get to know some of the players in a React codebase. - -There are plenty of resources available to teach you React and restful API design, so I’m going to focus primarily on the “missing pieces” of combining React with a Grails application[1]. At the completion of this article, we'll list some resources to further your understanding of React. You'll be able to take this foundation and follow along with the same documentation, tutorials and other resources available to React developers. - -## Building Our Foundation - -Let’s start with a brand new Grails 3.1.6 application, using the default web profile: - -``` - grails create-app com.ociweb.TodoList -``` - -Having run the `create-app` command, we already have a fully functioning backend application and server ready to go, and we can start up our app using the run-app command. View your new Grails application at [http://localhost:8080](http://localhost:8080/). - -Let’s create our data model. - -``` - grails create-domain-class com.ociweb.Todo - grails create-domain-class com.ociweb.TodoList -``` - -```groovy -//grails-app/domain/com/ociweb/Todo.groovy - package com.ociweb - - class Todo { - - String name - - static belongsTo = [todoList: TodoList] - } -``` - -```groovy -//grails-app/domain/com/ociweb/TodoList.groovy - package com.ociweb - - class TodoList { - - String name - - static hasMany = [ todos: Todo ] - - static constraints = { - todos nullable: true - } - } -``` - -Now we have our domain model ready to go. By default Grails will provide us with an H2 database (in memory for development and test environments, as a file in production). - -Of course Grails supports all the major databases, including MySQL, Postgres, Oracle, and even NoSQL data stores like **Mongo**. Thanks to the flexibility of GORM, changing datasources is as simple as adding a couple dependencies or lines of configuration. - -Let’s switch to Mongo for this demonstration (this step is optional). - -Specify the mongo plugin in your `build.gradle` file: - -```groovy -//build.gradle - - buildscript { - //… - dependencies { - //… - classpath "org.grails.plugins:hibernate4:5.0.0.BUILD-SNAPSHOT" - - dependencies { - //… - compile "org.grails.plugins:mongodb:5.0.0.BUILD-SNAPSHOT" - compile "org.grails.plugins:hibernate4:5.0.0.BUILD-SNAPSHOT" -``` - -Now in our domain classes, add this static property to store the domain object in mongo: - -```groovy - //grail-app/domain/com/ociweb/Todo.groovy & TodoList.groovy - -//... - static mapWith="mongo" -``` - -The plugin assumes you have mongodb installed and that mongod is running at port 27017; you can configure these to match your environment ([see the plugin documentation for details](https://gorm.grails.org/latest/mongodb/manual/index.html)). - -## Defining Our API - -Finally, we need to define a restful API for our React application. - -API design is a broad subject and not in scope of this article. However, Grails gives us a jumpstart to getting our API off the ground, providing endpoints for standard CRUD operations with minimal configuration. This is done by declaring our domain classes as resources, either by marking with the `@Resource` annotation or specifying the resource class within our URLMappings. - -Let's use the `@Resource` annotation for this example. - -```groovy -//grails-app/domain/com/ociweb/Todo.groovy - import grails.rest.Resource - - @Resource(uri='/api/todos', formats=['json']) - class Todo { - //... -``` - -```groovy -//grails-app/domain/com/ociweb/TodoList.groovy - - @Resource(uri='/api/todoList', formats=['json']) - class TodoList { - //... -``` - -Note that we specify the content-type we wish to expose - we’ll use JSON. - -Finally, let’s add some initial data in `Bootstrap.groovy`: - -```groovy -//grails-app/init/BootStrap.groovy - - import com.ociweb.* - - class BootStrap { - - def init = { servletContext -> - - if(!Todo.list()) { - log.info "Creating todos..." - def todoList = new TodoList(name: "Bob's List").save() - - [[name: "Task 1", todoList: todoList], - [name: "Task 2", todoList: todoList], - [name: "Task 3", todoList: todoList]].each { props -> - def todo = new Todo() - todo.properties = props - todo.save(flush: true) - } - - } - } - def destroy = { - } - } -``` - -Restart the application to load the new data. - -Now using a rest client application or a command-line utility like cURL, we can test drive our new API. - -``` - ~ curl -i -H "Accept: application/json" localhost:8080/api/todos - - HTTP/1.1 200 OK - Server: Apache-Coyote/1.1 - X-Application-Context: application:development - Content-Type: application/json;charset=UTF-8 - Transfer-Encoding: chunked - Date: Sun, 15 May 2016 06:03:56 GMT - - [{"id":1,"list":{"id":1},"name":"Task 1"},{"id":2,"list":{"id":1},"name":"Task 2"}, - {"id":3,"list":{"id":1},"name":"Task 3"}] -``` - -``` - ~ curl -i -H "Accept: application/json" localhost:8080/api/todoList/1 - - HTTP/1.1 200 OK - Server: Apache-Coyote/1.1 - X-Application-Context: application:development - Content-Type: application/json;charset=UTF-8 - Transfer-Encoding: chunked - Date: Sun, 15 May 2016 06:06:00 GMT - - {"id":1,"name":"Bob's List","todos":[{"id":3},{"id":1},{"id":2}] - } -``` - -There you go, we have a fully functioning restful API, backed by Mongo, and my coffee isn’t even cold yet. - -Now that we have our backend largely ready to go, we’re ready to set up React. - -> Question: Why Do This? -> -> Why not use separate backend and front-end apps? In a microservice architecture, the work we’ve done might be sufficient - we could now build a separate React/node-based front-end application independent of our Grails backend. This is a great strategy, and [Grails 3.1 ships with a profile](https://grails.apache.org/docs/latest/guide/profiles.html#creatingProfiles) tailored to this use case (web-api). Another option is to take advantage of Gradle multi-project builds, with separate projects for the backend and front-end. Both of these options require another server to run the React app. -> -> In this article, however, we’re considering the use of React as the “view” (the V in MVC) in a standard Grails application. And although we’re sharing a project directory, the React code and Grails artifacts are independent, and will communicate at runtime via our restful API just as if they were separate apps. The only thing tying these two apps together is the same Gradle build, which gives us the benefits described earlier in the article (in fact, it would be quite easy to split out the React app in future by simply moving the `src/main/js` and `src/test/js` directories into their own project, and configuring up a new server). -> -> There’s many situations where a team may want to bring React into a Grails application, and it can be done in a way that allows for full developer productivity for both Grails and Node/React developers. Read on to see how! - -## Upgrading Our Build - -React is most commonly used in combination with [node.js](https://nodejs.org/), and even if you aren’t intending to use node in particular, it still makes sense to have it installed if you intend to do any serious work with a Javascript library like React. - -The reason? You will use `npm` (which most surely [does _not_ stand for Node Package Manager](https://www.quora.com/I-keep-hearing-NPM-doesnt-stand-for-Node-Package-Manager-what-does-it-stand-for)) to download and install React and any other libraries you choose to use alongside it. `npm` can also be used to run scripts to build and test your React code, and it is the “handle” that will allow us to integrate our React code with our Gradle-based deployment. - -Once we have our React application set up, it will _not_ be necessary for all developers to run node on their machines – we’ll take care of making that happen seamlessly as part of the Gradle build. However, any developer who is set up with node will be able to use `npm` and other node tools just as if they were working within a “plain” node application. This gives us the best of both worlds: Backend Grails developers can do their work without relying upon node and `npm`, while frontend developers can use node and their preferred development tools. The only requirement for all team members will be a Gradle installation to run the Grails project. - -In addition to installing node in your development environment, we will need to install the [gradle-node plugin](https://github.com/srs/gradle-node-plugin) in our Grails application. This plugin will be the key to managing our `npm` tasks without relying upon local installations of node. Install the plugin by adding the plugin in `build.gradle`: - -```groovy - //build.gradle - - plugins { - id "com.moowork.node" version "0.12" - } - - node { - version = '5.10.1' - npmVersion = '3.8.3' - distBaseUrl = 'https://nodejs.org/dist' - download = true - } -``` - -## Setting Up Our React Environment - -For the next few steps, we'll use a local installation of `npm`. If you don't have it installed yet, I _highly_ recommend [nvm](https://github.com/creationix/nvm) to simplify installation and managing of node versions (if you've used `gvm`/`sdkman` for managing Grails/Groovy/Gradle versions, you'll like `nvm`). We'll be using the latest version of node 5.x as of the time of writing, which is 5.10.1\. Please refer to [the Readme in the Github repository](https://github.com/ZacharyKlein/sett-todolist/blob/master/README.md) for the versions of all node packages that are used. For a simple example like this, newer versions of any of the packages shouldn't cause a problem. - -Assuming you've installed `npm`, let's initialize our project. Run this command from your Grails project directory - you can accept the defaults for now; it's easy to fill in the details later): - -``` - npm init -``` - -Now we’re ready to install React and other dependencies. - -``` - npm install react react-dom --save - - npm install babel-core babel-preset-es2015 babel-preset-react babel-loader webpack --save-dev -``` - -There are plenty of options when setting up a React application, but these are the basics. - -Of course we need React and ReactDOM to render our app in the browser (React can also be used natively on mobile platforms like iOS, using [ReactNative](https://facebook.github.io/react-native/) instead of ReactDOM). - -In addition, because we’ll be using JSX to write our components, we’ll need to use a **transpiler** to convert our React code into “plain vanilla” Javascript. Modern Javascript frameworks are moving much faster than web browsers, and many of the Javascript APIs commonly used in React projects are not yet standard in browsers. - -[babel](https://babeljs.io/) is a popular transpiler with many “presets” supporting different versions of Javascript syntax. - -To enable these presets, create a `.babelrc` file in the project root directory with this content: - -```javascript - { - "presets": [ - "react", - "es2015" - ] - } -``` -This will ensure that babel uses the presets we’ve installed when transpiling our code. - -Of course, if we’re going to run our code through a transpiler, that means we need a build step to do the work. Typically in Grails applications, the asset pipeline plugin is the tool of choice for processing static assets like Javascript files. While there is a [Babel plugin](https://github.com/errbuddy/babel-asset-pipeline) for the Grails asset pipeline, we are going to take a different approach and use **webpack **for this purpose; this will give us more flexibility in processing our React code and is in keeping with typical React projects. - -## Webpack - -[Webpack](https://webpack.github.io "Webpack on GitHub") represents a family of tools called “bundlers” and is a very popular choice for building React applications. It’s also a powerful and complex tool, but we can get started with a fairly minimal configuration. - -Here’s the big picture: Webpack will be responsible for running our React code through “loaders” for processing, and then output the finished product as a “bundle”. There are [loaders for nearly every conceivable asset type](https://webpack.js.org/loaders/) you may want to access in your React application, including LESS, SASS, markdown, images, urls, generic files, and even Java properties files (such as `i18n/messages.properties` files). In our case, the babel-loader all we need to configure right now. We will configure webpack to drop this bundle into the `grails-app/assets/javascripts` directory in our Grails application, so it can be served just like another Javascript file. - -Here's our `webpack.config.js` file: - -```javascript - var path = require('path'); - - module.exports = { - entry: { - index: './src/main/js/index.js' - }, - output: { - path: './grails-app/assets/javascripts', - publicPath: '/assets/', - filename: 'bundle.js' - }, - module: { - loaders: [ - { - test: /\.js$/, - include: path.join(__dirname, 'src/main/js'), - loader: 'babel', - query: { - presets: ['es2015', 'react'] - } - } - ] - } - }; -``` - -Don't be intimidated by this configuration; it’s actually fairly simple. The syntax is plain Javascript, which can be a bit confusing for a Grails developer accustomed to a DSL for config. The key points are that we’re defining where to find our React source files (`src/main/js/index.js`), where to output them (`grails-app/assets/javascripts`), and how to process them via the babel loader. You can learn more about configuring webpack [from the documentation](https://webpack.js.org/concepts/), but this should get you started. - -> Where Is `/src/main/js`? -> -> Typically in a Grails application, Javascript files, like other static assets, live in the `grails-app/assets/` directory, which is where the asset pipeline picks them up. However, it is far more typical in a React application to keep the source files separate from the distributed bundle within a `src` directory, which makes sense, given that they contain “source code” for an application and are not really “assets” in the sense that Twitter Bootstrap or jQuery might be. -> -> In addition, we will want to write tests for our React code, and it really doesn't make sense for tests to live in an “assets” directory structure. This is simply a matter of preference; in this article, we will store our React source code under `src/main/js` (in keeping with Grails' conventional `src/main/java` and `src/main/groovy` source structure), and our tests under `src/test/js`. These directories won’t exist by default, so we’ll need to create them ourselves. - -We will also want to add a couple of “scripts” to our `package.json` file in order to run webpack via `npm` (and later automate these with Gradle). In the `scripts` section, add these two lines: - -```javascript - "scripts": { - "watch": "webpack --watch --colors --progress", - "bundle": "webpack", -``` - -Now we can call these scripts using `npm`. Why do we have two scripts that both run webpack? The “bundle” version runs webpack and generates the bundle once (analogous to `grails war`), while the “watch” version will run webpack in “watch” mode, where the tool will automatically regenerate the bundle every time it detects a change to the source files (similar to `grails run-app`, with reloading of changed classes). We also enable some pretty formatting to ensure developer happiness. - -You can now run these scripts like so: - -``` - npm run bundle -``` - -However, you'll likely get an error saying "Entry module could not be found." - -Yep, we haven't added the "entry" file we specified earlier in our `src/main/js` directory yet. Let's do that. - -Create `index.js` and add a simple `alert()` statement: - -```javascript -//src/main/js/index.js - alert('Hello!'); -``` - -Now if you run `npm run bundle`, you’ll get output like this: - -```javascript - Hash: bc17d737c7738edc00a5 - Version: webpack 1.13.0 - Time: 727ms - Asset Size Chunks Chunk Names - bundle.js 1.43 kB 0 [emitted] index - + 1 hidden modules -``` - -And if you check your `grails-app/assets/javascripts` directory, you should see your shiny new `bundle.js`! - -Finally we need to load this bundle on our page. We’ll use a Grails controller and GSP view in this demonstration, but this could easily be a plain HTML page as well. Create a new controller `AppController`, and create an `index.gsp` page in the `grails-app/views/app` directory with this content: - -``` - grails create-controller com.ociweb.AppController -``` - -```groovy -//grail-app/views/index.gsp - - - - Todo List - - -
- - - -``` - -(Note that if we had used a plain HTML page, we would not be able to use the tag) - -Browse to [`http://localhost:8080/app`](http://localhost:8080/app), and you should see your `alert()` statement. - -> webpack-dev-server -> -> Webpack also includes a simple server called _webpack-dev-server_, which will operate similarly to “watch” mode but is actually able to instantly reload the bundle/s on your page, so that you can see your app update when you save your source file [without refreshing the browser](https://gaearon.github.io/react-hot-loader/getstarted/). This is a powerful feature, but it can be tricky to set up and is outside the scope of this article. I’ve created [a starter application available on Github](https://github.com/ZacharyKlein/grails-react-starter)[2] that demonstrates use of the webpack-dev-server within a Grails application. - -## Enter Gradle - -We’re almost done with our setup steps. With our current configuration, we can bundle our React code and output it to the asset pipeline, so the Grails app can serve it to our views. We also have a restful backend provided by our Grails app. Now we just need to make use of the Gradle node plugin [3] to automate the webpack bundling process when we 1\. start the Grails app, and 2\. package the Grails app as a WAR or JAR file. - -Add these two lines to the end of your `build.gradle`: - -```groovy -//build.gradle - - processResources.dependsOn(['npmInstall', 'npm_run_bundle']) - - assetCompile.dependsOn(['npmInstall', 'npm_run_bundle']) -``` - -And that’s it! All we’ve done here is “hooked” a pair of `npm` tasks into our Gradle build process. - -The first is `npmInstall`, which is the equivalent of `npm install`, and is typically the first command you’d run when setting up an existing node-based project. `npm install` will read the `package.json` file and install any missing dependencies in your development environment. - -The second task should look familiar – it’s our `bundle` script we just used a moment ago. The Gradle node plugin supports this syntax for _any_ script that you would normally run with `npm`. So any custom scripts you write in the future can be called via `npm_run_[your new script]`. - -Of course, you can run these scripts yourself through Gradle, using the included Gradle wrapper: - -``` - ./gradlew npm_run_watch -``` - -Other than the delay from spinning up Gradle, this will have the same effect as running `npm run watch` directly. This also means that developers without node installed can run these tasks without adding anything to their build environment - Gradle will handle those details seamlessly and OS-independently. - -When developing with React, typically you will run the Grails app _and_ run webpack in “watch” mode, using `npm` or Gradle. As you make changes to your Javascript sources, webpack will automatically regenerate the `bundle.js`, and you can load the changes by refreshing your page. - -![](2016-05-28-img01.png) -_Development Workflow with Grails & Webpack (`grails run-app` in the left terminal; `./gradlew npm_run_watch` in the right)_ - -Returning to our new `build.gradle` steps, you'll notice that we've attached these tasks to Grails' `processResources` (which runs every time the Grails app is started) and `assetCompile` (which runs when the app is packaged) tasks as dependencies. In this case, we just want to make sure the bundle is generated when the app is run, and when we build our WAR/JAR file, so that we’re always using our latest `bundle.js`. This also means you can exclude `bundle.js` from your version control if you’d prefer. - -Now you can build your Grails application on a Continuous Integration server that knows nothing about node or React. Gradle will handle installing node (local to the project), downloading `npm` dependencies, and running scripts like our webpack bundle, all without any changes to your build and deployment process. - -## Defining our Components - -As we mentioned in the introduction to this article, React provides an [expressive XML-like syntax](https://facebook.github.io/react/docs/jsx-in-depth.html) for defining our components. Let’s take a look at a simple JSX component that will render a Todo instance. - -```javascript - // /src/main/js/todo.js - - import React from 'react'; - - function Todo(props) { - - const todo = props.todo; - - return( -
  • - - { todo.name } -
  • - ); - } -``` - -Again, this is not an in depth explanation of React and JSX, but you can learn a lot from a simple example like this one. As you can see, our component is a simple Javascript function, which takes an object (key/value pairs, similar to a Groovy map) that contains all attributes that are passed into this component. - -To use our new component, we just need to render it to our page (note that we have implemented a `toggleComplete`function yet, so we’re skipping that property for now - our component will still render but it won’t do anything yet): - - -```javascript - // /src/main/js/index.js - - import React from 'react'; - import ReactDOM from 'react-dom'; - import Todo from './todo'; - - //Call to render our component into the DOM… - ReactDOM.render( -
    - -

    Our first Todo!

    -{% raw %} - -{% endraw %} -
    , document.getElementById('app')); // ...into this element on the page -``` - -Compare this to a custom GSP tag that might render similar output server-side: - -```groovy - //Hypothetical GSP taglib - - def todo = { attrs -> - - def todo = attrs.todo - - out << """ -
  • - - ${todo.name} -
  • - """ - } - - -``` - -Of course this is not an entirely fair comparison. [GSP tags provide much more functionality](https://objectcomputing.com/resources/publications/sett/december-2015-custom-gsp-tags-grails-best-kept-secret/) than simply rendering of attributes, but Grails developers should find the syntax of JSX to be quite friendly and understandable coming from GSPs. - -JSX allows us to write Javascript expressions bound by curly braces, supports namespacing of components, and can make large, complex UIs easier to visualize while coding [4]. However, JSX is optional. You can write React components entirely in plain Javascript, but the resulting code is more verbose. - -> Word of Warning -> -> This article is not intended as a comprehensive introduction to React. For developers new to Javascript, there are plenty of pitfalls to be had when learning this library. Understanding function context, "binding" [5], and passing functional callbacks into child components are key skills when writing clean code in React. These concepts are not React-specific – they are in fact plain Javascript – but they can be confusing to Groovy and Java programmers. There are many resources for learning React, and we will list a few of them at the end of this article. - -## Calling the API - -Now that we have our React app integrated into our Grails project and served up via the asset pipeline, we can start to build out our application and write components that consume our restful API. Because React is a view library, it doesn’t offer specialized features for communicating with a restful API. Developers are encouraged to use native Javascript APIs or other libraries to supply this functionality. The example project from this article uses the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) [6]. The full code is available on Github, so we won’t go over it here. - -The app allows a user to create new todo lists and add new todo items to them. All changes are saved to the mongo database. It also makes use of [JSON Views](https://views.grails.org/latest/) to customize the JSON output from our endpoints. - -No update or delete functions are provided at this time. Those features are left as an exercise to the reader. - -[https://github.com/ZacharyKlein/sett-todolist](https://github.com/ZacharyKlein/sett-todolist) - -![](2016-05-28-img02.png) - -Completed TodoList app - -## Testing - -One of the benefits of creating a user interface in React is testability. Because React encourages the use of stateless components, testing their functionality is often as simple as providing props and making assertions against their output. Let’s look at a simple test for our component, and then see how the Gradle node plugin can help us run our tests as part of our build. - -There are many options for testing Javascript code. [7,8] In this example we'll use the [mocha test framework](https://mochajs.org/), React’s own [testing utilities](https://facebook.github.io/react/docs/test-utils.html), and `expect.js` to provide assertions. - -Again, because React is focused on building our view layer, we’re mostly concerned with testing that our components output the correct content from their props. This is _not_ an in-depth look at testing React components, but it will give you a place to start. - -First, let’s install some dependencies: - -``` - npm install mocha expect react-addons-test-utils --save-dev -``` - -And add this "test" script to our `package.json` file: - -``` - ”test": "mocha './src/test/js/*.spec.js' --compilers js:babel-core/register" -``` - -Here's a simple test for our component: - -```javascript - // /src/test/js/lot.spec.js - - import React from 'react'; - import TestUtils from 'react-addons-test-utils'; - import expect from 'expect'; - import Todo from '../../main/js/todo'; - - describe('Todo', () => { - it('should have expected content', () => { - - const todo = {name: 'Task 1', complete: false, id: 1, list: { id: 1 }}; - - const renderer = TestUtils.createRenderer(); - - renderer.render( - ); - - const output = renderer.getRenderOutput(); - - //We expect the to output an
  • element - expect(output.type).toBe('li'); - - const children = output.props.children; - const [input, span] = children; - - //We expect the first element in our
  • to be an input - expect(input.type).toBe('input'); - - const todoName = span.props.children; - - //We expect the span to contain the name of the todo - expect(todoName).toBe(todo.name); - }); - }); -``` - -There’s a lot to unpack here that is beyond the scope of this article, so I’ll refer you to the resources at the bottom of the page for more detail. But the big picture is fairly simple. We’ve created a “mock” todo object, and used it to populate our component, which is then “rendered” using `TestUtils.createRenderer()` (`TestUtils` also includes features for simulating clicks and other user interactions with your components). At that point, we’re simply traversing the “DOM” and making assertions about the expected content. - -To run this test, use `npm` to run our new `test` script: - -``` - npm run test -``` - -```javascript - > todo-list@1.0.0 test /Users/zak/Dev/TodoList - > mocha './src/test/js/*.spec.js' --compilers js:babel-core/register - - Todo - ✓ should have expected content - - 1 passing (15ms) -``` - -Finally, we can add this test script to our Gradle build using the same techniques we explored earlier. - -```groovy - //build.gradle - - //Run React tests - task mochaTest(dependsOn: ['npmInstall', 'npm_run_test']) - - check.dependsOn(mochaTest) -``` - -Now we can run our React tests via Gradle with `./gradlew mochaTest`, and they will also be run as part of the `check` task (which runs Grails unit and integration tests together). - -## Conclusion - -React is a powerful and exciting library, and it’s a great choice for Grails applications. While there’s some bootstrapping necessary to get started, with a project structure like we’ve demonstrated you should be able to take advantage of the many resources available for learning React and associated libraries and tools, without having to “translate” into a Grails-specific flavor. In addition, front-end developers unfamiliar with Grails should find it much easier to work using their favorite node-based tools and development environments. The only requirement to firing up the backend is Java and the Gradle wrapper that is included in the Grails project. With React’s tooling standardized around `npm`, and Grails’ build process managed by `Gradle`, it’s quite straightforward to set up a combined development and deployment pipeline, one that allows both frameworks to be used as designed. - -> Postscript -> -> As mentioned earlier in the article, I've created a [starter project](https://github.com/ZacharyKlein/grails-react-starter) with React integrated in a Grails application, using the same structure described above. It also provides a working configuration for the `webpack-dev-server`, including a custom taglib to switch between the “hot load” bundle and the static bundle from the Grails asset pipeline. React-Bootstrap and loading of images and CSS are also demonstrated. The project is available on Github. [2] - -## References - -* [1] Sample App: [https://github.com/ZacharyKlein/sett-todolist](https://github.com/ZacharyKlein/sett-todolist) -* [2] Grails-React Starter: [https://github.com/ZacharyKlein/grails-react-starter](https://github.com/ZacharyKlein/grails-react-starter) -* [3] Gradle-node-plugin: [https://github.com/srs/gradle-node-plugin](https://github.com/srs/gradle-node-plugin) -* [4] JSX and “Separation of concerns”: [https://blog.andrewray.me/youre-missing-the-point-of-jsx/](https://blog.andrewray.me/youre-missing-the-point-of-jsx/) -* [5] Why and how to bind methods in your React component classes?: [https://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/](https://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/) -* [6] Fetch API: [https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) -* [7] How we unit test React components using expect-jsx: [https://blog.algolia.com/how-we-unit-test-react-components-using-expect-jsx](https://blog.algolia.com/how-we-unit-test-react-components-using-expect-jsx/) -* [8] How React Components Make UI Testing Easy [https://www.toptal.com/react/how-react-components-make-ui-testing-easy](https://www.toptal.com/react/how-react-components-make-ui-testing-easy) - -## Resources - -* OCI Training in React Web Development: [https://ocitraining.com/react-web-development](https://ocitraining.com/react-web-development/) -* Egghead.io video courses on React and related technologies: [https://egghead.io/q/react](https://egghead.io/q/react) -* Navigating the React.JS Ecosystem: [https://www.toptal.com/react/navigating-the-react-ecosystem](https://www.toptal.com/react/navigating-the-react-ecosystem) -* An excellent set of sample React apps written and maintained by my OCI colleague, Mark Volkmann: [https://github.com/mvolkmann/react-examples](https://github.com/mvolkmann/react-examples) -* RubyC presentation by [Alex Coles](https://alexbcoles.com/), “Beyond the Asset Pipeline” (Rails-specific talk, but much of the discussion is relevant to the Grails asset pipeline as well): [https://youtu.be/CNv9ewmQys8](https://youtu.be/CNv9ewmQys8) -* How to Use Webpack with Rails (also Rails-specific, but many of the techniques described are relevant to Grails projects): [https://clarkdave.net/2015/01/how-to-use-webpack-with-rails/](https://clarkdave.net/2015/01/how-to-use-webpack-with-rails/) - -## Documentation - -* React Documentation: [https://facebook.github.io/react/docs/getting-started.html](https://github.com/ZacharyKlein/grails-react-starter) -* React Test-Utils: [https://facebook.github.io/react/docs/test-utils.html](https://facebook.github.io/react/docs/test-utils.html) -* JSX Documentation: [https://facebook.github.io/react/docs/jsx-in-depth.html](https://github.com/ZacharyKlein/grails-react-starter) -* Webpack Documentation: [https://webpack.js.org/concepts/](https://webpack.js.org/concepts/) +title: Using React with the Grails® framework +date: May 28, 2016 +description: React is a powerful and exciting library, and it’s a great choice for Grails® applications. +author: Zachary Klein +image: 2016-05-28.jpg +CSS: [%url]/stylesheets/prism.css +JAVASCRIPT: [%url]/javascripts/prism.js +--- + +# [%title] + +[%author] + +[%date] + +Tags: #react #javascript #gradle + +**React**, the JavaScript library from Facebook, has become a popular view technology for building dynamic, testable and performant user interfaces. While not a full-fledged framework like Angular or Ember, React’s focus on functional component-based views with no (or minimal) internal state makes it a great choice when building single page applications (SPA) or even dynamic subcomponents within a page-based application. + +Because it doesn't make assumptions about data-flow or controller logic outside of rendering the view, React relies on the developer to either provide these features directly in JavaScript or use another framework as a backend to support the React-based UI. + +It is this flexibility, in part, that makes React an appealing choice as a modern JavaScript view layer for **Grails**® applications. Grails provides a robust backend built upon Spring Boot, GORM, and the Groovy programming language, as well as excellent support for generating restful endpoints that can be consumed by our React application. Since Grails 3 is also based upon Gradle, we can leverage [Gradle’s Node plugin](https://github.com/srs/gradle-node-plugin) to unify our build and testing pipeline for both Grails and React, without needing to complicate our deployment processes. + +Finally, **JSX** (React's XML-like syntax for defining components and page markup) is a powerful and flexible way to create dynamic views. In the author's opinion, creating components in JSX is quite analogous to defining custom GSP tags in a Grails taglib: a function which receives state via props (GSP `attrs`) and typically (but not always) renders markup based on that state. In React's case, these components are re-rendered upon every change to the app's state, rather than being limited to page-load. This stateless component model should be understandable to Grails developers who have written [custom GSP tags](https://objectcomputing.com/resources/publications/sett/december-2015-custom-gsp-tags-grails-best-kept-secret/), and JSX takes this to the next level. + +In this article, we'll demonstrate how to integrate React into a Grails 3 application, using some of Grail’s restful features to get up and running quickly. We’ll spend a bit of time getting our project set up, and get to know some of the players in a React codebase. + +There are plenty of resources available to teach you React and restful API design, so I’m going to focus primarily on the “missing pieces” of combining React with a Grails application[1]. At the completion of this article, we'll list some resources to further your understanding of React. You'll be able to take this foundation and follow along with the same documentation, tutorials and other resources available to React developers. + +## Building Our Foundation + +Let’s start with a brand new Grails 3.1.6 application, using the default web profile: + +``` + grails create-app com.ociweb.TodoList +``` + +Having run the `create-app` command, we already have a fully functioning backend application and server ready to go, and we can start up our app using the run-app command. View your new Grails application at [http://localhost:8080](http://localhost:8080/). + +Let’s create our data model. + +``` + grails create-domain-class com.ociweb.Todo + grails create-domain-class com.ociweb.TodoList +``` + +```groovy +//grails-app/domain/com/ociweb/Todo.groovy + package com.ociweb + + class Todo { + + String name + + static belongsTo = [todoList: TodoList] + } +``` + +```groovy +//grails-app/domain/com/ociweb/TodoList.groovy + package com.ociweb + + class TodoList { + + String name + + static hasMany = [ todos: Todo ] + + static constraints = { + todos nullable: true + } + } +``` + +Now we have our domain model ready to go. By default Grails will provide us with an H2 database (in memory for development and test environments, as a file in production). + +Of course Grails supports all the major databases, including MySQL, Postgres, Oracle, and even NoSQL data stores like **Mongo**. Thanks to the flexibility of GORM, changing datasources is as simple as adding a couple dependencies or lines of configuration. + +Let’s switch to Mongo for this demonstration (this step is optional). + +Specify the mongo plugin in your `build.gradle` file: + +```groovy +//build.gradle + + buildscript { + //… + dependencies { + //… + classpath "org.grails.plugins:hibernate4:5.0.0.BUILD-SNAPSHOT" + + dependencies { + //… + compile "org.grails.plugins:mongodb:5.0.0.BUILD-SNAPSHOT" + compile "org.grails.plugins:hibernate4:5.0.0.BUILD-SNAPSHOT" +``` + +Now in our domain classes, add this static property to store the domain object in mongo: + +```groovy + //grail-app/domain/com/ociweb/Todo.groovy & TodoList.groovy + +//... + static mapWith="mongo" +``` + +The plugin assumes you have mongodb installed and that mongod is running at port 27017; you can configure these to match your environment ([see the plugin documentation for details](https://gorm.grails.org/latest/mongodb/manual/index.html)). + +## Defining Our API + +Finally, we need to define a restful API for our React application. + +API design is a broad subject and not in scope of this article. However, Grails gives us a jumpstart to getting our API off the ground, providing endpoints for standard CRUD operations with minimal configuration. This is done by declaring our domain classes as resources, either by marking with the `@Resource` annotation or specifying the resource class within our URLMappings. + +Let's use the `@Resource` annotation for this example. + +```groovy +//grails-app/domain/com/ociweb/Todo.groovy + import grails.rest.Resource + + @Resource(uri='/api/todos', formats=['json']) + class Todo { + //... +``` + +```groovy +//grails-app/domain/com/ociweb/TodoList.groovy + + @Resource(uri='/api/todoList', formats=['json']) + class TodoList { + //... +``` + +Note that we specify the content-type we wish to expose - we’ll use JSON. + +Finally, let’s add some initial data in `Bootstrap.groovy`: + +```groovy +//grails-app/init/BootStrap.groovy + + import com.ociweb.* + + class BootStrap { + + def init = { servletContext -> + + if(!Todo.list()) { + log.info "Creating todos..." + def todoList = new TodoList(name: "Bob's List").save() + + [[name: "Task 1", todoList: todoList], + [name: "Task 2", todoList: todoList], + [name: "Task 3", todoList: todoList]].each { props -> + def todo = new Todo() + todo.properties = props + todo.save(flush: true) + } + + } + } + def destroy = { + } + } +``` + +Restart the application to load the new data. + +Now using a rest client application or a command-line utility like cURL, we can test drive our new API. + +``` + ~ curl -i -H "Accept: application/json" localhost:8080/api/todos + + HTTP/1.1 200 OK + Server: Apache-Coyote/1.1 + X-Application-Context: application:development + Content-Type: application/json;charset=UTF-8 + Transfer-Encoding: chunked + Date: Sun, 15 May 2016 06:03:56 GMT + + [{"id":1,"list":{"id":1},"name":"Task 1"},{"id":2,"list":{"id":1},"name":"Task 2"}, + {"id":3,"list":{"id":1},"name":"Task 3"}] +``` + +``` + ~ curl -i -H "Accept: application/json" localhost:8080/api/todoList/1 + + HTTP/1.1 200 OK + Server: Apache-Coyote/1.1 + X-Application-Context: application:development + Content-Type: application/json;charset=UTF-8 + Transfer-Encoding: chunked + Date: Sun, 15 May 2016 06:06:00 GMT + + {"id":1,"name":"Bob's List","todos":[{"id":3},{"id":1},{"id":2}] + } +``` + +There you go, we have a fully functioning restful API, backed by Mongo, and my coffee isn’t even cold yet. + +Now that we have our backend largely ready to go, we’re ready to set up React. + +> Question: Why Do This? +> +> Why not use separate backend and front-end apps? In a microservice architecture, the work we’ve done might be sufficient - we could now build a separate React/node-based front-end application independent of our Grails backend. This is a great strategy, and [Grails 3.1 ships with a profile](https://grails.apache.org/docs/latest/guide/profiles.html#creatingProfiles) tailored to this use case (web-api). Another option is to take advantage of Gradle multi-project builds, with separate projects for the backend and front-end. Both of these options require another server to run the React app. +> +> In this article, however, we’re considering the use of React as the “view” (the V in MVC) in a standard Grails application. And although we’re sharing a project directory, the React code and Grails artifacts are independent, and will communicate at runtime via our restful API just as if they were separate apps. The only thing tying these two apps together is the same Gradle build, which gives us the benefits described earlier in the article (in fact, it would be quite easy to split out the React app in future by simply moving the `src/main/js` and `src/test/js` directories into their own project, and configuring up a new server). +> +> There’s many situations where a team may want to bring React into a Grails application, and it can be done in a way that allows for full developer productivity for both Grails and Node/React developers. Read on to see how! + +## Upgrading Our Build + +React is most commonly used in combination with [node.js](https://nodejs.org/), and even if you aren’t intending to use node in particular, it still makes sense to have it installed if you intend to do any serious work with a Javascript library like React. + +The reason? You will use `npm` (which most surely [does _not_ stand for Node Package Manager](https://www.quora.com/I-keep-hearing-NPM-doesnt-stand-for-Node-Package-Manager-what-does-it-stand-for)) to download and install React and any other libraries you choose to use alongside it. `npm` can also be used to run scripts to build and test your React code, and it is the “handle” that will allow us to integrate our React code with our Gradle-based deployment. + +Once we have our React application set up, it will _not_ be necessary for all developers to run node on their machines – we’ll take care of making that happen seamlessly as part of the Gradle build. However, any developer who is set up with node will be able to use `npm` and other node tools just as if they were working within a “plain” node application. This gives us the best of both worlds: Backend Grails developers can do their work without relying upon node and `npm`, while frontend developers can use node and their preferred development tools. The only requirement for all team members will be a Gradle installation to run the Grails project. + +In addition to installing node in your development environment, we will need to install the [gradle-node plugin](https://github.com/srs/gradle-node-plugin) in our Grails application. This plugin will be the key to managing our `npm` tasks without relying upon local installations of node. Install the plugin by adding the plugin in `build.gradle`: + +```groovy + //build.gradle + + plugins { + id "com.moowork.node" version "0.12" + } + + node { + version = '5.10.1' + npmVersion = '3.8.3' + distBaseUrl = 'https://nodejs.org/dist' + download = true + } +``` + +## Setting Up Our React Environment + +For the next few steps, we'll use a local installation of `npm`. If you don't have it installed yet, I _highly_ recommend [nvm](https://github.com/creationix/nvm) to simplify installation and managing of node versions (if you've used `gvm`/`sdkman` for managing Grails/Groovy/Gradle versions, you'll like `nvm`). We'll be using the latest version of node 5.x as of the time of writing, which is 5.10.1\. Please refer to [the Readme in the Github repository](https://github.com/ZacharyKlein/sett-todolist/blob/master/README.md) for the versions of all node packages that are used. For a simple example like this, newer versions of any of the packages shouldn't cause a problem. + +Assuming you've installed `npm`, let's initialize our project. Run this command from your Grails project directory - you can accept the defaults for now; it's easy to fill in the details later): + +``` + npm init +``` + +Now we’re ready to install React and other dependencies. + +``` + npm install react react-dom --save + + npm install babel-core babel-preset-es2015 babel-preset-react babel-loader webpack --save-dev +``` + +There are plenty of options when setting up a React application, but these are the basics. + +Of course we need React and ReactDOM to render our app in the browser (React can also be used natively on mobile platforms like iOS, using [ReactNative](https://facebook.github.io/react-native/) instead of ReactDOM). + +In addition, because we’ll be using JSX to write our components, we’ll need to use a **transpiler** to convert our React code into “plain vanilla” Javascript. Modern Javascript frameworks are moving much faster than web browsers, and many of the Javascript APIs commonly used in React projects are not yet standard in browsers. + +[babel](https://babeljs.io/) is a popular transpiler with many “presets” supporting different versions of Javascript syntax. + +To enable these presets, create a `.babelrc` file in the project root directory with this content: + +```javascript + { + "presets": [ + "react", + "es2015" + ] + } +``` +This will ensure that babel uses the presets we’ve installed when transpiling our code. + +Of course, if we’re going to run our code through a transpiler, that means we need a build step to do the work. Typically in Grails applications, the asset pipeline plugin is the tool of choice for processing static assets like Javascript files. While there is a [Babel plugin](https://github.com/errbuddy/babel-asset-pipeline) for the Grails asset pipeline, we are going to take a different approach and use **webpack **for this purpose; this will give us more flexibility in processing our React code and is in keeping with typical React projects. + +## Webpack + +[Webpack](https://webpack.github.io "Webpack on GitHub") represents a family of tools called “bundlers” and is a very popular choice for building React applications. It’s also a powerful and complex tool, but we can get started with a fairly minimal configuration. + +Here’s the big picture: Webpack will be responsible for running our React code through “loaders” for processing, and then output the finished product as a “bundle”. There are [loaders for nearly every conceivable asset type](https://webpack.js.org/loaders/) you may want to access in your React application, including LESS, SASS, markdown, images, urls, generic files, and even Java properties files (such as `i18n/messages.properties` files). In our case, the babel-loader all we need to configure right now. We will configure webpack to drop this bundle into the `grails-app/assets/javascripts` directory in our Grails application, so it can be served just like another Javascript file. + +Here's our `webpack.config.js` file: + +```javascript + var path = require('path'); + + module.exports = { + entry: { + index: './src/main/js/index.js' + }, + output: { + path: './grails-app/assets/javascripts', + publicPath: '/assets/', + filename: 'bundle.js' + }, + module: { + loaders: [ + { + test: /\.js$/, + include: path.join(__dirname, 'src/main/js'), + loader: 'babel', + query: { + presets: ['es2015', 'react'] + } + } + ] + } + }; +``` + +Don't be intimidated by this configuration; it’s actually fairly simple. The syntax is plain Javascript, which can be a bit confusing for a Grails developer accustomed to a DSL for config. The key points are that we’re defining where to find our React source files (`src/main/js/index.js`), where to output them (`grails-app/assets/javascripts`), and how to process them via the babel loader. You can learn more about configuring webpack [from the documentation](https://webpack.js.org/concepts/), but this should get you started. + +> Where Is `/src/main/js`? +> +> Typically in a Grails application, Javascript files, like other static assets, live in the `grails-app/assets/` directory, which is where the asset pipeline picks them up. However, it is far more typical in a React application to keep the source files separate from the distributed bundle within a `src` directory, which makes sense, given that they contain “source code” for an application and are not really “assets” in the sense that Twitter Bootstrap or jQuery might be. +> +> In addition, we will want to write tests for our React code, and it really doesn't make sense for tests to live in an “assets” directory structure. This is simply a matter of preference; in this article, we will store our React source code under `src/main/js` (in keeping with Grails' conventional `src/main/java` and `src/main/groovy` source structure), and our tests under `src/test/js`. These directories won’t exist by default, so we’ll need to create them ourselves. + +We will also want to add a couple of “scripts” to our `package.json` file in order to run webpack via `npm` (and later automate these with Gradle). In the `scripts` section, add these two lines: + +```javascript + "scripts": { + "watch": "webpack --watch --colors --progress", + "bundle": "webpack", +``` + +Now we can call these scripts using `npm`. Why do we have two scripts that both run webpack? The “bundle” version runs webpack and generates the bundle once (analogous to `grails war`), while the “watch” version will run webpack in “watch” mode, where the tool will automatically regenerate the bundle every time it detects a change to the source files (similar to `grails run-app`, with reloading of changed classes). We also enable some pretty formatting to ensure developer happiness. + +You can now run these scripts like so: + +``` + npm run bundle +``` + +However, you'll likely get an error saying "Entry module could not be found." + +Yep, we haven't added the "entry" file we specified earlier in our `src/main/js` directory yet. Let's do that. + +Create `index.js` and add a simple `alert()` statement: + +```javascript +//src/main/js/index.js + alert('Hello!'); +``` + +Now if you run `npm run bundle`, you’ll get output like this: + +```javascript + Hash: bc17d737c7738edc00a5 + Version: webpack 1.13.0 + Time: 727ms + Asset Size Chunks Chunk Names + bundle.js 1.43 kB 0 [emitted] index + + 1 hidden modules +``` + +And if you check your `grails-app/assets/javascripts` directory, you should see your shiny new `bundle.js`! + +Finally we need to load this bundle on our page. We’ll use a Grails controller and GSP view in this demonstration, but this could easily be a plain HTML page as well. Create a new controller `AppController`, and create an `index.gsp` page in the `grails-app/views/app` directory with this content: + +``` + grails create-controller com.ociweb.AppController +``` + +```groovy +//grail-app/views/index.gsp + + + + Todo List + + +
    + + + +``` + +(Note that if we had used a plain HTML page, we would not be able to use the tag) + +Browse to [`http://localhost:8080/app`](http://localhost:8080/app), and you should see your `alert()` statement. + +> webpack-dev-server +> +> Webpack also includes a simple server called _webpack-dev-server_, which will operate similarly to “watch” mode but is actually able to instantly reload the bundle/s on your page, so that you can see your app update when you save your source file [without refreshing the browser](https://gaearon.github.io/react-hot-loader/getstarted/). This is a powerful feature, but it can be tricky to set up and is outside the scope of this article. I’ve created [a starter application available on Github](https://github.com/ZacharyKlein/grails-react-starter)[2] that demonstrates use of the webpack-dev-server within a Grails application. + +## Enter Gradle + +We’re almost done with our setup steps. With our current configuration, we can bundle our React code and output it to the asset pipeline, so the Grails app can serve it to our views. We also have a restful backend provided by our Grails app. Now we just need to make use of the Gradle node plugin [3] to automate the webpack bundling process when we 1\. start the Grails app, and 2\. package the Grails app as a WAR or JAR file. + +Add these two lines to the end of your `build.gradle`: + +```groovy +//build.gradle + + processResources.dependsOn(['npmInstall', 'npm_run_bundle']) + + assetCompile.dependsOn(['npmInstall', 'npm_run_bundle']) +``` + +And that’s it! All we’ve done here is “hooked” a pair of `npm` tasks into our Gradle build process. + +The first is `npmInstall`, which is the equivalent of `npm install`, and is typically the first command you’d run when setting up an existing node-based project. `npm install` will read the `package.json` file and install any missing dependencies in your development environment. + +The second task should look familiar – it’s our `bundle` script we just used a moment ago. The Gradle node plugin supports this syntax for _any_ script that you would normally run with `npm`. So any custom scripts you write in the future can be called via `npm_run_[your new script]`. + +Of course, you can run these scripts yourself through Gradle, using the included Gradle wrapper: + +``` + ./gradlew npm_run_watch +``` + +Other than the delay from spinning up Gradle, this will have the same effect as running `npm run watch` directly. This also means that developers without node installed can run these tasks without adding anything to their build environment - Gradle will handle those details seamlessly and OS-independently. + +When developing with React, typically you will run the Grails app _and_ run webpack in “watch” mode, using `npm` or Gradle. As you make changes to your Javascript sources, webpack will automatically regenerate the `bundle.js`, and you can load the changes by refreshing your page. + +![Blog post image 2016-05-28-img01](2016-05-28-img01.png) +_Development Workflow with Grails & Webpack (`grails run-app` in the left terminal; `./gradlew npm_run_watch` in the right)_ + +Returning to our new `build.gradle` steps, you'll notice that we've attached these tasks to Grails' `processResources` (which runs every time the Grails app is started) and `assetCompile` (which runs when the app is packaged) tasks as dependencies. In this case, we just want to make sure the bundle is generated when the app is run, and when we build our WAR/JAR file, so that we’re always using our latest `bundle.js`. This also means you can exclude `bundle.js` from your version control if you’d prefer. + +Now you can build your Grails application on a Continuous Integration server that knows nothing about node or React. Gradle will handle installing node (local to the project), downloading `npm` dependencies, and running scripts like our webpack bundle, all without any changes to your build and deployment process. + +## Defining our Components + +As we mentioned in the introduction to this article, React provides an [expressive XML-like syntax](https://facebook.github.io/react/docs/jsx-in-depth.html) for defining our components. Let’s take a look at a simple JSX component that will render a Todo instance. + +```javascript + // /src/main/js/todo.js + + import React from 'react'; + + function Todo(props) { + + const todo = props.todo; + + return( +
  • + + { todo.name } +
  • + ); + } +``` + +Again, this is not an in depth explanation of React and JSX, but you can learn a lot from a simple example like this one. As you can see, our component is a simple Javascript function, which takes an object (key/value pairs, similar to a Groovy map) that contains all attributes that are passed into this component. + +To use our new component, we just need to render it to our page (note that we have implemented a `toggleComplete`function yet, so we’re skipping that property for now - our component will still render but it won’t do anything yet): + + +```javascript + // /src/main/js/index.js + + import React from 'react'; + import ReactDOM from 'react-dom'; + import Todo from './todo'; + + //Call to render our component into the DOM… + ReactDOM.render( +
    + +

    Our first Todo!

    +{% raw %} + +{% endraw %} +
    , document.getElementById('app')); // ...into this element on the page +``` + +Compare this to a custom GSP tag that might render similar output server-side: + +```groovy + //Hypothetical GSP taglib + + def todo = { attrs -> + + def todo = attrs.todo + + out << """ +
  • + + ${todo.name} +
  • + """ + } + + +``` + +Of course this is not an entirely fair comparison. [GSP tags provide much more functionality](https://objectcomputing.com/resources/publications/sett/december-2015-custom-gsp-tags-grails-best-kept-secret/) than simply rendering of attributes, but Grails developers should find the syntax of JSX to be quite friendly and understandable coming from GSPs. + +JSX allows us to write Javascript expressions bound by curly braces, supports namespacing of components, and can make large, complex UIs easier to visualize while coding [4]. However, JSX is optional. You can write React components entirely in plain Javascript, but the resulting code is more verbose. + +> Word of Warning +> +> This article is not intended as a comprehensive introduction to React. For developers new to Javascript, there are plenty of pitfalls to be had when learning this library. Understanding function context, "binding" [5], and passing functional callbacks into child components are key skills when writing clean code in React. These concepts are not React-specific – they are in fact plain Javascript – but they can be confusing to Groovy and Java programmers. There are many resources for learning React, and we will list a few of them at the end of this article. + +## Calling the API + +Now that we have our React app integrated into our Grails project and served up via the asset pipeline, we can start to build out our application and write components that consume our restful API. Because React is a view library, it doesn’t offer specialized features for communicating with a restful API. Developers are encouraged to use native Javascript APIs or other libraries to supply this functionality. The example project from this article uses the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) [6]. The full code is available on Github, so we won’t go over it here. + +The app allows a user to create new todo lists and add new todo items to them. All changes are saved to the mongo database. It also makes use of [JSON Views](https://views.grails.org/latest/) to customize the JSON output from our endpoints. + +No update or delete functions are provided at this time. Those features are left as an exercise to the reader. + +[https://github.com/ZacharyKlein/sett-todolist](https://github.com/ZacharyKlein/sett-todolist) + +![Blog post image 2016-05-28-img02](2016-05-28-img02.png) + +Completed TodoList app + +## Testing + +One of the benefits of creating a user interface in React is testability. Because React encourages the use of stateless components, testing their functionality is often as simple as providing props and making assertions against their output. Let’s look at a simple test for our component, and then see how the Gradle node plugin can help us run our tests as part of our build. + +There are many options for testing Javascript code. [7,8] In this example we'll use the [mocha test framework](https://mochajs.org/), React’s own [testing utilities](https://facebook.github.io/react/docs/test-utils.html), and `expect.js` to provide assertions. + +Again, because React is focused on building our view layer, we’re mostly concerned with testing that our components output the correct content from their props. This is _not_ an in-depth look at testing React components, but it will give you a place to start. + +First, let’s install some dependencies: + +``` + npm install mocha expect react-addons-test-utils --save-dev +``` + +And add this "test" script to our `package.json` file: + +``` + ”test": "mocha './src/test/js/*.spec.js' --compilers js:babel-core/register" +``` + +Here's a simple test for our component: + +```javascript + // /src/test/js/lot.spec.js + + import React from 'react'; + import TestUtils from 'react-addons-test-utils'; + import expect from 'expect'; + import Todo from '../../main/js/todo'; + + describe('Todo', () => { + it('should have expected content', () => { + + const todo = {name: 'Task 1', complete: false, id: 1, list: { id: 1 }}; + + const renderer = TestUtils.createRenderer(); + + renderer.render( + ); + + const output = renderer.getRenderOutput(); + + //We expect the to output an
  • element + expect(output.type).toBe('li'); + + const children = output.props.children; + const [input, span] = children; + + //We expect the first element in our
  • to be an input + expect(input.type).toBe('input'); + + const todoName = span.props.children; + + //We expect the span to contain the name of the todo + expect(todoName).toBe(todo.name); + }); + }); +``` + +There’s a lot to unpack here that is beyond the scope of this article, so I’ll refer you to the resources at the bottom of the page for more detail. But the big picture is fairly simple. We’ve created a “mock” todo object, and used it to populate our component, which is then “rendered” using `TestUtils.createRenderer()` (`TestUtils` also includes features for simulating clicks and other user interactions with your components). At that point, we’re simply traversing the “DOM” and making assertions about the expected content. + +To run this test, use `npm` to run our new `test` script: + +``` + npm run test +``` + +```javascript + > todo-list@1.0.0 test /Users/zak/Dev/TodoList + > mocha './src/test/js/*.spec.js' --compilers js:babel-core/register + + Todo + ✓ should have expected content + + 1 passing (15ms) +``` + +Finally, we can add this test script to our Gradle build using the same techniques we explored earlier. + +```groovy + //build.gradle + + //Run React tests + task mochaTest(dependsOn: ['npmInstall', 'npm_run_test']) + + check.dependsOn(mochaTest) +``` + +Now we can run our React tests via Gradle with `./gradlew mochaTest`, and they will also be run as part of the `check` task (which runs Grails unit and integration tests together). + +## Conclusion + +React is a powerful and exciting library, and it’s a great choice for Grails applications. While there’s some bootstrapping necessary to get started, with a project structure like we’ve demonstrated you should be able to take advantage of the many resources available for learning React and associated libraries and tools, without having to “translate” into a Grails-specific flavor. In addition, front-end developers unfamiliar with Grails should find it much easier to work using their favorite node-based tools and development environments. The only requirement to firing up the backend is Java and the Gradle wrapper that is included in the Grails project. With React’s tooling standardized around `npm`, and Grails’ build process managed by `Gradle`, it’s quite straightforward to set up a combined development and deployment pipeline, one that allows both frameworks to be used as designed. + +> Postscript +> +> As mentioned earlier in the article, I've created a [starter project](https://github.com/ZacharyKlein/grails-react-starter) with React integrated in a Grails application, using the same structure described above. It also provides a working configuration for the `webpack-dev-server`, including a custom taglib to switch between the “hot load” bundle and the static bundle from the Grails asset pipeline. React-Bootstrap and loading of images and CSS are also demonstrated. The project is available on Github. [2] + +## References + +* [1] Sample App: [https://github.com/ZacharyKlein/sett-todolist](https://github.com/ZacharyKlein/sett-todolist) +* [2] Grails-React Starter: [https://github.com/ZacharyKlein/grails-react-starter](https://github.com/ZacharyKlein/grails-react-starter) +* [3] Gradle-node-plugin: [https://github.com/srs/gradle-node-plugin](https://github.com/srs/gradle-node-plugin) +* [4] JSX and “Separation of concerns”: [https://blog.andrewray.me/youre-missing-the-point-of-jsx/](https://blog.andrewray.me/youre-missing-the-point-of-jsx/) +* [5] Why and how to bind methods in your React component classes?: [https://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/](https://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/) +* [6] Fetch API: [https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) +* [7] How we unit test React components using expect-jsx: [https://blog.algolia.com/how-we-unit-test-react-components-using-expect-jsx](https://blog.algolia.com/how-we-unit-test-react-components-using-expect-jsx/) +* [8] How React Components Make UI Testing Easy [https://www.toptal.com/react/how-react-components-make-ui-testing-easy](https://www.toptal.com/react/how-react-components-make-ui-testing-easy) + +## Resources + +* OCI Training in React Web Development: [https://ocitraining.com/react-web-development](https://ocitraining.com/react-web-development/) +* Egghead.io video courses on React and related technologies: [https://egghead.io/q/react](https://egghead.io/q/react) +* Navigating the React.JS Ecosystem: [https://www.toptal.com/react/navigating-the-react-ecosystem](https://www.toptal.com/react/navigating-the-react-ecosystem) +* An excellent set of sample React apps written and maintained by my OCI colleague, Mark Volkmann: [https://github.com/mvolkmann/react-examples](https://github.com/mvolkmann/react-examples) +* RubyC presentation by [Alex Coles](https://alexbcoles.com/), “Beyond the Asset Pipeline” (Rails-specific talk, but much of the discussion is relevant to the Grails asset pipeline as well): [https://youtu.be/CNv9ewmQys8](https://youtu.be/CNv9ewmQys8) +* How to Use Webpack with Rails (also Rails-specific, but many of the techniques described are relevant to Grails projects): [https://clarkdave.net/2015/01/how-to-use-webpack-with-rails/](https://clarkdave.net/2015/01/how-to-use-webpack-with-rails/) + +## Documentation + +* React Documentation: [https://facebook.github.io/react/docs/getting-started.html](https://github.com/ZacharyKlein/grails-react-starter) +* React Test-Utils: [https://facebook.github.io/react/docs/test-utils.html](https://facebook.github.io/react/docs/test-utils.html) +* JSX Documentation: [https://facebook.github.io/react/docs/jsx-in-depth.html](https://github.com/ZacharyKlein/grails-react-starter) +* Webpack Documentation: [https://webpack.js.org/concepts/](https://webpack.js.org/concepts/) diff --git a/posts/2016-08-01.md b/posts/2016-08-01.md index adbbc83f9da..b51dbf244c9 100644 --- a/posts/2016-08-01.md +++ b/posts/2016-08-01.md @@ -1,165 +1,165 @@ -title: GR8Conf US 2016 Wrap-up! -date: August 1, 2016 -description: GR8Conf US 2016 Wrap-up! -author: Ryan Vanderwerf -image: 2016-08-01.jpg ---- - -# [%title] - -[%author] - -[%date] - -![The OCI Grails® team at GR8Conf US 2016](2016-08-01-img01.png) - -Well I've just started to clear my fuzzy head getting back from [GR8Conf US](https://gr8conf.us/) in Minneapolis, where OCI was a platinum sponsor this year. Lots of good stuff came out of the show, things announced, good workshops. There were 4 concurrent tracks of talks for 2 days, and 1 day of workshops. In all, the OCI Grails team delivered 4 workshops and 8 talks - most of the team creates these talks on their own time as well in addition to our regular responsibilities. We are dedicated! - -![](2016-08-01-img02.jpg) - -I grew up in a suburb in St. Paul and had not been back since I started speaking at Gr8Conf 3-4 years ago. What a beautiful city it is now! So much stuff going on, sports games, music, breweries and a pretty clean downtown. Can't recommend enough to come visit here in the summer - that said I would avoid it in the thick of winter - it's so cold they build sky-bridges to connect the buildings to minimize the outside elements! Check out one of these great buildings at night. The picture below is looking out from the University of St. Thomas, the venue. - -![Skyline](2016-08-01-img03.png) - -## Day 1: Workshops - -![Ryan and Lee presenting Alexa, Tell Me I'm Groovy](2016-08-01-img04.jpg) - -I started the day doing my Groovy Lego Mindstorms EV3 talk where we worked with putting Groovy apps on the robots, then used the Grails framework to control the robots like Mars rovers. I Then did a 2nd half day workshop with my friend Lee Fox on Amazon Alexa. We built Groovy Lambda Skills as well as Grails 3 Skills. - -![Jeff Scott Brown presenting at GR8Conf US 2016](2016-08-01-img05.jpeg) - -Jeff Brown then did 2(!) back-to-back workshops on 'Getting Started with Grails 3' and 'Rest with Grails 3' (*Pic by Annyce Davis). - -Danny Hyun did a Groovy intro workshop where he taught people to use a Pokemon Java API to help them catch them all in Groovy (all day). -Marcin Erdmann (His first stateside appearance at Gr8?) did an all day Ratpack sandbox workshop. - -## Day 2: Talks - -![Graeme Rocher presenting the keynote presentation](2016-08-01-img06.jpg) - -Graeme Rocher kicked off the conference with his keynote about all the goodness upcoming in Grails 3.2, GORM 6, and how overall better things are about Grails 3 as well as the future. - -Here we start the 4 parallel tracks, with one being 'Groovy for Java Developers' by Puneet Behl where he teaches how Groovy makes life better for Java devs. - -In the same slots were "Getting Started with Grails 3" by OCI Grails team member Colin Harrington gave a great Grails 3 intro talk. - -Also there was "GroovyFX - Groove JavaFX" by Alexander Sasha Klein on all the goodies aroung GroovyFX. - -Next up: Dynamic GORM by Burt Beckwith, Monitoring and Metrics with Grails 3 by OCI Grails Team co-founder Jeff Scott Brown. Craig Burke always brings the laughs with "Practical and Stupidly Impractical Groovy DSLs. Android Groovy plugin maintainer Andrew Reitz did a good talk on testing Gradle plugins, which is something people often overlook but is needed. - -![Ryan and Lee presenting Alexa, Tell Me I'm Groovy Day 2](2016-08-01-img07.jpeg) - -Next slot after lunch: Lee Fox and I do the "Alexa Tell me I'm Groovy" talk which we covered AWS Groovy Lambda Skills and The Grails 3 plugin. Lee made a superhero quiz game and Baruch from JFrog stepped up to test his skills. Needless to say he said his name and Alexa said 'I heard bottles' and proceeded to ask 'Bottles' trivia questions. So that is Baruch's new nickname, try it out next time you see him :) The audience got lots of laughs from all the Alexa antics we did. It gets better, we used a Grails app we wrote for Alexa to live-tweet the audience reaction. So much fun! - -While this was going on fellow OCI Grails team member Alvaro Sanchez-Mariscal did 'Mastering Grails 3 Plugins' with some solid advice on Grails 3 to avoid pain later. Asset-pipeline creator Dave Estes did a great talk on the ins and outs of asset-pipeline which every Grails developer should learn and know. Finishing this slot is Jenn Strater's talk on a TDD Approach to Documenting Restful APIs which a lot of people were excited about all of the documentation tools she showed off. - -Last talk slot of the day: - -Bob the Builder by Sascha Klein shared his tips of using builder patterns for daily survival. Teammate Alvaro continued with another talk on Creating apps with the Grails framework, AngularJS, and Spring Security which is a shorter talk version of the workshop he did at Gr8Conf.eu this year. Annyce Davis a new speaker I met this year did a great talk on From the Grails framework to Android: A Simple Journey. Finishing the talks for the day was Jenn Strater with "CodeNarc Revisited." - -![Alvaro presenting on Grails, Angular, and DDS](2016-08-01-img08.jpeg) - -Kenneth Kousen closed up the day with a great keynote that talked about all the value Groovy and all the community has to offer. - -![Ken Kousen delivering a keynote at GR8Conf US 2016](2016-08-01-img09.jpeg) - -After the talks and keynote, Object Partners was kind enough to bus everyone to their new offices in North Minneapolis for Gr8ConfUS beer, appetizers, and Groovy Puzzlers with Baruch(Bottles) and Dan Woods. - -![Groovy Puzzlers with Baruch(Bottles) and Dan Woods](2016-08-01-img10.jpeg) - -![Gr8ConfUS Beer](2016-08-01-img11.jpeg) - -## Day 3 Talks - -We roll into day 3 running with (almost) a complete track of talks about Ratpack by Dan Woods (9am after late night karaoke, impressive!), non web Ratpack with John Engelman, and testing Rackpack with Danny Hyun. Back to chronological order, Puneet Behl talked about Giving back to the community by helping migrate 2.x plugins to 3.x. Annyce David talked about Gradle Plugin Goodness, and Ryan Applegate talked about scaling Grails apps at SmartThings. - -Craig Burke talked about AngularJS in Grails apps as well as trolled Kyle Boon and myself pretty hard (His test is totally rigged I say!). Jeff Brown from OCI Grails Team talked about Groovy Metaprogramming, and Charlie Knudsen talked about a strategy to get to zero downtime deployments. - -![Colin Harrington's presentation about how to secure your Grails application via Spring Security Plugins](2016-08-01-img12.jpeg) - -Next slot we had fellow OCI Grails teammate Colin Harrington talk about how to secure your Grails application via Spring Security Plugins. Sacha Klein also gave a Groovy with Jenkins talk about using Groovy in your CI pipeline. Todd Miller talked about Spring Cloud in production with tools like Eureka and Hystrix/Turbine to monitor your apps. Craig Atkinson also gave a great Spock and Geb into talk. - -After lunch Burt Beckwith talked about Spring Security, Christian Oestreich talked about monitoring Grails 3 applications, Craig Atkinson gave another great functional testing talk with Geb. Stephen Pember gave a mind-bender talk on Reactive Streams and Groovy to finish out the time slot. - -Last talks of the day are now underway with "Grails Reactive Event-Driven Architecture" by Christian Oestreich (He maintains several Grails plugins like CXF/Client), Dockerize It All by Puneet Behl, and last but not least a JOOQ intro talk by Stephen Pember. - -Wrapping up the conference, John Engelman gave the closing keynote about writing software in the Agile age, culture devops, and other good stuff. - -After that, Ken Kousen and Baruch(Bottles) Sadogursky did a live Groovy podcast with a studio audience!. The link for it is [here](https://www.youtube.com/watch?v=MWRWnKfbnIs). - -![Gr8Ladies-sponsored happy hour](2016-08-01-img13.jpeg) - -Once the broadcast concluded, most of the attendees went home, but many speakers and attendees stayed and went to the Gr8Ladies sponsored happy hour. That extended to the roof later, where the Ratpack folks really showed their dance moves, especially Danny Hyun! - -![Ratpack folks showing off their dance moves, especially Danny Hyun](2016-08-01-img14.png) - -Special thanks to out to all the volunteers and helpers for the conference, especially Bobby Warner, Shaun Jurgenmeyer, Eric Kinsella, Doug Sabers, and Jenn Strater! - -I hope to be back again next year, as you won't find a nicer, friendlier accessible bunch than the folks at the Gr8Conf conferences. Come for the content, stay for the socialization and networking! The more I go to these events, I find the value scale for networking goes higher and higher, which is something you just can't get off youtube videos and posted slides. Come to see what others are doing or not doing because it didn't work - It could save your next project from failure! - -*** - -## Slide Decks From the Conference - -(cobbled together and ripped from tweets and Grails Diary) - -### Workshops - -[Exercises for Getting started with Grails 3 (Jeff Scott Brown)](https://www.dropbox.com/sh/ah2uxd9he0x4p4f/AACGHZEiY-PP9Zl3qpLCI4XOa?dl=0) - -[Getting Groovy with Lego Mindstorms (Ryan Vanderwerf)](https://www.slideshare.net/ryanvanderwerf/getting-groovy-with-lego-mindstorms-ev3-gr8conf-us-2016) - -[Amazon Alexa Workshop (Ryan Vanderwerf and Lee Fox](https://www.slideshare.net/ryanvanderwerf/amazon-alexa-workshop-grpovy-and-grails-gr8conf-us-2016) also labs [here](https://sites.google.com/site/alexaskillslab/) - -[Groovy Workshop 2016 (Daniel Hyun)](https://danhyun.github.io/2016-gr8conf-groovy-workshop/) - -### Talks – Day 2 - -[Getting started with Grails 3 (Colin Harrington)](https://slides.com/colinharrington/getting-started-with-grails-3-gr8confus-2016#/) - -[Practical and Stupidly Impractical Groovy DSLs (Code) (Craig Burke)](http://www.craigburke.com/practical-groovy-dsl/) - -[Alexa, Tell Me I'm Groovy (Ryan Vanderwerf / Lee Fox)](https://speakerdeck.com/rvanderwerf/alexa-tell-me-im-groovy-gr8conf-us-2016) - -[Mastering Grails 3 plugins (Alvaro Sanchez-Mariscal)](https://www.slideshare.net/alvarosanchezmariscal/mastering-grails-3-plugins-gr8conf-us-2016) - -[Codenarc Revisited (Jenn Strater)](https://speakerdeck.com/jlstrater/codenarc-revisited-gr8conf-us-2016) - -[From Grails to Android (Annyce Davis)](https://www.adavis.info/2016/07/talk-from-grails-to-android.html) - -[A Test-Driven Approach to Documenting RESTful APIs with Spring REST Docs (Jenn Strater)](https://speakerdeck.com/jlstrater/a-test-driven-approach-to-documenting-restful-apis-with-spring-rest-docs-gr8conf-us) - -### Talks – Day 3 - -[Securing your Grails application: A survey/layout of the security plugin space (Colin Harrington)](https://slides.com/colinharrington/springsecuritysurvey-gr8conf-us-2016#/) - -[Scaling Grails at SmartThings (Ryan Applegate)](https://speakerdeck.com/rappleg/scaling-grails-at-smartthings) - -[Gradle Plugin Goodness (Annyce Davis)](https://www.adavis.info/2016/07/talk-gradle-plugin-goodness.html) - -[Creating applications with Grails, Angular JS and Spring Security - (code) (Alvaro Sanchez-Mariscal)](https://www.slideshare.net/alvarosanchezmariscal/creating-applications-with-grails-angular-js-and-spring-security-gr8conf-us-2016) - -[Intro to Spock and Geb (Craig Atkinson)](https://craigatk.github.io/spock-geb-intro/) - -[Monitoring Grails 3 Applications (Christian Oestreich)](https://github.com/Grails-Plugin-Consortium/gr8conf-monitoring-metrics) - -[Grails Reactive Event-Driven Architecture (Christian Oestreich)](https://github.com/Grails-Plugin-Consortium/gr8conf-event-driven-microservices) - -[Geb Tips and Tricks (Craig Atkinson)](https://craigatk.github.io/geb-tips-tricks/#/) - -[Testing Ratpack Applications (Danny Hyun)](https://danhyun.github.io/2016-gr8confus-testing-ratpack-apps/) - -[Reactive Streams and the Wide World of Groovy (Steve Pember)](https://www.slideshare.net/StevePember/reactive-streams-and-the-wide-world-of-groovy-64526341) - -[An Introduction to jOOQ - code (Steve Pember)](https://www.slideshare.net/StevePember/an-introduction-to-jooq) - -### Some Other Recaps - -[Annyce Davis](https://www.adavis.info/2016/07/gr8conf-us-2016-recap.html) - -[Roberto Perez A.](https://rpalcolea.github.io/blog/2016/GR8Conf-US-Recap-2016.html) - -I look forward to the next edition in 2017! - -— Ryan Vanderwerf and the rest of the OCI/Grails Team +title: GR8Conf US 2016 Wrap-up! +date: August 1, 2016 +description: GR8Conf US 2016 Wrap-up! +author: Ryan Vanderwerf +image: 2016-08-01.jpg +--- + +# [%title] + +[%author] + +[%date] + +![The OCI Grails® team at GR8Conf US 2016](2016-08-01-img01.png) + +Well I've just started to clear my fuzzy head getting back from [GR8Conf US](https://gr8conf.us/) in Minneapolis, where OCI was a platinum sponsor this year. Lots of good stuff came out of the show, things announced, good workshops. There were 4 concurrent tracks of talks for 2 days, and 1 day of workshops. In all, the OCI Grails team delivered 4 workshops and 8 talks - most of the team creates these talks on their own time as well in addition to our regular responsibilities. We are dedicated! + +![Blog post image 2016-08-01-img02](2016-08-01-img02.jpg) + +I grew up in a suburb in St. Paul and had not been back since I started speaking at Gr8Conf 3-4 years ago. What a beautiful city it is now! So much stuff going on, sports games, music, breweries and a pretty clean downtown. Can't recommend enough to come visit here in the summer - that said I would avoid it in the thick of winter - it's so cold they build sky-bridges to connect the buildings to minimize the outside elements! Check out one of these great buildings at night. The picture below is looking out from the University of St. Thomas, the venue. + +![Skyline](2016-08-01-img03.png) + +## Day 1: Workshops + +![Ryan and Lee presenting Alexa, Tell Me I'm Groovy](2016-08-01-img04.jpg) + +I started the day doing my Groovy Lego Mindstorms EV3 talk where we worked with putting Groovy apps on the robots, then used the Grails framework to control the robots like Mars rovers. I Then did a 2nd half day workshop with my friend Lee Fox on Amazon Alexa. We built Groovy Lambda Skills as well as Grails 3 Skills. + +![Jeff Scott Brown presenting at GR8Conf US 2016](2016-08-01-img05.jpeg) + +Jeff Brown then did 2(!) back-to-back workshops on 'Getting Started with Grails 3' and 'Rest with Grails 3' (*Pic by Annyce Davis). + +Danny Hyun did a Groovy intro workshop where he taught people to use a Pokemon Java API to help them catch them all in Groovy (all day). +Marcin Erdmann (His first stateside appearance at Gr8?) did an all day Ratpack sandbox workshop. + +## Day 2: Talks + +![Graeme Rocher presenting the keynote presentation](2016-08-01-img06.jpg) + +Graeme Rocher kicked off the conference with his keynote about all the goodness upcoming in Grails 3.2, GORM 6, and how overall better things are about Grails 3 as well as the future. + +Here we start the 4 parallel tracks, with one being 'Groovy for Java Developers' by Puneet Behl where he teaches how Groovy makes life better for Java devs. + +In the same slots were "Getting Started with Grails 3" by OCI Grails team member Colin Harrington gave a great Grails 3 intro talk. + +Also there was "GroovyFX - Groove JavaFX" by Alexander Sasha Klein on all the goodies aroung GroovyFX. + +Next up: Dynamic GORM by Burt Beckwith, Monitoring and Metrics with Grails 3 by OCI Grails Team co-founder Jeff Scott Brown. Craig Burke always brings the laughs with "Practical and Stupidly Impractical Groovy DSLs. Android Groovy plugin maintainer Andrew Reitz did a good talk on testing Gradle plugins, which is something people often overlook but is needed. + +![Ryan and Lee presenting Alexa, Tell Me I'm Groovy Day 2](2016-08-01-img07.jpeg) + +Next slot after lunch: Lee Fox and I do the "Alexa Tell me I'm Groovy" talk which we covered AWS Groovy Lambda Skills and The Grails 3 plugin. Lee made a superhero quiz game and Baruch from JFrog stepped up to test his skills. Needless to say he said his name and Alexa said 'I heard bottles' and proceeded to ask 'Bottles' trivia questions. So that is Baruch's new nickname, try it out next time you see him :) The audience got lots of laughs from all the Alexa antics we did. It gets better, we used a Grails app we wrote for Alexa to live-tweet the audience reaction. So much fun! + +While this was going on fellow OCI Grails team member Alvaro Sanchez-Mariscal did 'Mastering Grails 3 Plugins' with some solid advice on Grails 3 to avoid pain later. Asset-pipeline creator Dave Estes did a great talk on the ins and outs of asset-pipeline which every Grails developer should learn and know. Finishing this slot is Jenn Strater's talk on a TDD Approach to Documenting Restful APIs which a lot of people were excited about all of the documentation tools she showed off. + +Last talk slot of the day: + +Bob the Builder by Sascha Klein shared his tips of using builder patterns for daily survival. Teammate Alvaro continued with another talk on Creating apps with the Grails framework, AngularJS, and Spring Security which is a shorter talk version of the workshop he did at Gr8Conf.eu this year. Annyce Davis a new speaker I met this year did a great talk on From the Grails framework to Android: A Simple Journey. Finishing the talks for the day was Jenn Strater with "CodeNarc Revisited." + +![Alvaro presenting on Grails, Angular, and DDS](2016-08-01-img08.jpeg) + +Kenneth Kousen closed up the day with a great keynote that talked about all the value Groovy and all the community has to offer. + +![Ken Kousen delivering a keynote at GR8Conf US 2016](2016-08-01-img09.jpeg) + +After the talks and keynote, Object Partners was kind enough to bus everyone to their new offices in North Minneapolis for Gr8ConfUS beer, appetizers, and Groovy Puzzlers with Baruch(Bottles) and Dan Woods. + +![Groovy Puzzlers with Baruch(Bottles) and Dan Woods](2016-08-01-img10.jpeg) + +![Gr8ConfUS Beer](2016-08-01-img11.jpeg) + +## Day 3 Talks + +We roll into day 3 running with (almost) a complete track of talks about Ratpack by Dan Woods (9am after late night karaoke, impressive!), non web Ratpack with John Engelman, and testing Rackpack with Danny Hyun. Back to chronological order, Puneet Behl talked about Giving back to the community by helping migrate 2.x plugins to 3.x. Annyce David talked about Gradle Plugin Goodness, and Ryan Applegate talked about scaling Grails apps at SmartThings. + +Craig Burke talked about AngularJS in Grails apps as well as trolled Kyle Boon and myself pretty hard (His test is totally rigged I say!). Jeff Brown from OCI Grails Team talked about Groovy Metaprogramming, and Charlie Knudsen talked about a strategy to get to zero downtime deployments. + +![Colin Harrington's presentation about how to secure your Grails application via Spring Security Plugins](2016-08-01-img12.jpeg) + +Next slot we had fellow OCI Grails teammate Colin Harrington talk about how to secure your Grails application via Spring Security Plugins. Sacha Klein also gave a Groovy with Jenkins talk about using Groovy in your CI pipeline. Todd Miller talked about Spring Cloud in production with tools like Eureka and Hystrix/Turbine to monitor your apps. Craig Atkinson also gave a great Spock and Geb into talk. + +After lunch Burt Beckwith talked about Spring Security, Christian Oestreich talked about monitoring Grails 3 applications, Craig Atkinson gave another great functional testing talk with Geb. Stephen Pember gave a mind-bender talk on Reactive Streams and Groovy to finish out the time slot. + +Last talks of the day are now underway with "Grails Reactive Event-Driven Architecture" by Christian Oestreich (He maintains several Grails plugins like CXF/Client), Dockerize It All by Puneet Behl, and last but not least a JOOQ intro talk by Stephen Pember. + +Wrapping up the conference, John Engelman gave the closing keynote about writing software in the Agile age, culture devops, and other good stuff. + +After that, Ken Kousen and Baruch(Bottles) Sadogursky did a live Groovy podcast with a studio audience!. The link for it is [here](https://www.youtube.com/watch?v=MWRWnKfbnIs). + +![Gr8Ladies-sponsored happy hour](2016-08-01-img13.jpeg) + +Once the broadcast concluded, most of the attendees went home, but many speakers and attendees stayed and went to the Gr8Ladies sponsored happy hour. That extended to the roof later, where the Ratpack folks really showed their dance moves, especially Danny Hyun! + +![Ratpack folks showing off their dance moves, especially Danny Hyun](2016-08-01-img14.png) + +Special thanks to out to all the volunteers and helpers for the conference, especially Bobby Warner, Shaun Jurgenmeyer, Eric Kinsella, Doug Sabers, and Jenn Strater! + +I hope to be back again next year, as you won't find a nicer, friendlier accessible bunch than the folks at the Gr8Conf conferences. Come for the content, stay for the socialization and networking! The more I go to these events, I find the value scale for networking goes higher and higher, which is something you just can't get off youtube videos and posted slides. Come to see what others are doing or not doing because it didn't work - It could save your next project from failure! + +*** + +## Slide Decks From the Conference + +(cobbled together and ripped from tweets and Grails Diary) + +### Workshops + +[Exercises for Getting started with Grails 3 (Jeff Scott Brown)](https://www.dropbox.com/sh/ah2uxd9he0x4p4f/AACGHZEiY-PP9Zl3qpLCI4XOa?dl=0) + +[Getting Groovy with Lego Mindstorms (Ryan Vanderwerf)](https://www.slideshare.net/ryanvanderwerf/getting-groovy-with-lego-mindstorms-ev3-gr8conf-us-2016) + +[Amazon Alexa Workshop (Ryan Vanderwerf and Lee Fox](https://www.slideshare.net/ryanvanderwerf/amazon-alexa-workshop-grpovy-and-grails-gr8conf-us-2016) also labs [here](https://sites.google.com/site/alexaskillslab/) + +[Groovy Workshop 2016 (Daniel Hyun)](https://danhyun.github.io/2016-gr8conf-groovy-workshop/) + +### Talks – Day 2 + +[Getting started with Grails 3 (Colin Harrington)](https://slides.com/colinharrington/getting-started-with-grails-3-gr8confus-2016#/) + +[Practical and Stupidly Impractical Groovy DSLs (Code) (Craig Burke)](http://www.craigburke.com/practical-groovy-dsl/) + +[Alexa, Tell Me I'm Groovy (Ryan Vanderwerf / Lee Fox)](https://speakerdeck.com/rvanderwerf/alexa-tell-me-im-groovy-gr8conf-us-2016) + +[Mastering Grails 3 plugins (Alvaro Sanchez-Mariscal)](https://www.slideshare.net/alvarosanchezmariscal/mastering-grails-3-plugins-gr8conf-us-2016) + +[Codenarc Revisited (Jenn Strater)](https://speakerdeck.com/jlstrater/codenarc-revisited-gr8conf-us-2016) + +[From Grails to Android (Annyce Davis)](https://www.adavis.info/2016/07/talk-from-grails-to-android.html) + +[A Test-Driven Approach to Documenting RESTful APIs with Spring REST Docs (Jenn Strater)](https://speakerdeck.com/jlstrater/a-test-driven-approach-to-documenting-restful-apis-with-spring-rest-docs-gr8conf-us) + +### Talks – Day 3 + +[Securing your Grails application: A survey/layout of the security plugin space (Colin Harrington)](https://slides.com/colinharrington/springsecuritysurvey-gr8conf-us-2016#/) + +[Scaling Grails at SmartThings (Ryan Applegate)](https://speakerdeck.com/rappleg/scaling-grails-at-smartthings) + +[Gradle Plugin Goodness (Annyce Davis)](https://www.adavis.info/2016/07/talk-gradle-plugin-goodness.html) + +[Creating applications with Grails, Angular JS and Spring Security - (code) (Alvaro Sanchez-Mariscal)](https://www.slideshare.net/alvarosanchezmariscal/creating-applications-with-grails-angular-js-and-spring-security-gr8conf-us-2016) + +[Intro to Spock and Geb (Craig Atkinson)](https://craigatk.github.io/spock-geb-intro/) + +[Monitoring Grails 3 Applications (Christian Oestreich)](https://github.com/Grails-Plugin-Consortium/gr8conf-monitoring-metrics) + +[Grails Reactive Event-Driven Architecture (Christian Oestreich)](https://github.com/Grails-Plugin-Consortium/gr8conf-event-driven-microservices) + +[Geb Tips and Tricks (Craig Atkinson)](https://craigatk.github.io/geb-tips-tricks/#/) + +[Testing Ratpack Applications (Danny Hyun)](https://danhyun.github.io/2016-gr8confus-testing-ratpack-apps/) + +[Reactive Streams and the Wide World of Groovy (Steve Pember)](https://www.slideshare.net/StevePember/reactive-streams-and-the-wide-world-of-groovy-64526341) + +[An Introduction to jOOQ - code (Steve Pember)](https://www.slideshare.net/StevePember/an-introduction-to-jooq) + +### Some Other Recaps + +[Annyce Davis](https://www.adavis.info/2016/07/gr8conf-us-2016-recap.html) + +[Roberto Perez A.](https://rpalcolea.github.io/blog/2016/GR8Conf-US-Recap-2016.html) + +I look forward to the next edition in 2017! + +— Ryan Vanderwerf and the rest of the OCI/Grails Team diff --git a/posts/2016-10-03.md b/posts/2016-10-03.md index f7c048bbdd9..66594af90d9 100644 --- a/posts/2016-10-03.md +++ b/posts/2016-10-03.md @@ -1,382 +1,382 @@ -title: How to Use Travis-CI to Build and Deploy Your Plugin -date: October 3, 2016 -description: How to Use Travis-CI to Build and Deploy Your Grails® 3 Plugin -author: Søren Berg Glasius -image: 2016-10-03.jpg -CSS: [%url]/stylesheets/prism.css -JAVASCRIPT: [%url]/javascripts/prism.js ---- - -# [%title] - -[%author] - -[%date] - -Tags: #plugins #travis - -## Introduction - -When you create a Grails® 3 plugin and you want to share it with the world, wouldn't it be great if building and deploying was taken care of by a CI server? - -In this blog I will show you how to set up a Grails Plugin project that will be built and deployed on the [Travis-CI infrastructure](https://travis-ci.org/). - -Let us start out by setting up the project, so that it can be deployed to Bintray. Then we will add a Travis build to the mix. Finally we will explore how to handle snapshot deployment to [JFrog's open source repository](https://oss.jfrog.org/). - -## How Travis-CI Works - -Travis-CI works by monitoring your GitHub repository and whenever it sees changes, it will make a build of your project. The change can be a new commit pushed to GitHub, a new tag pushed to GitHub, or a pull request to your project on GitHub. - -If you want a deeper knowledge on how Travis-CI works, please [see the documentation](https://docs.travis-ci.com/). - -## Getting Started - -While you might have a plugin already, let us start this example by creating a plugin. The plugin will not have any functionality; it is only here to show the steps. - -```bash -grails create-plugin -profile plugin demoplugin -cd demoplugin -``` - -To get Travis-CI working the project has to live on GitHub. - -### Setting Up a GitHub Repository - -The first step is to enable Git for the local repository, add the project files, and commit it: - -```bash -git init -git add . -git commit -m "Initial commit" -``` - -Now go to [GitHub](https://github.com/) where we create a new repository: - -![Create a new repository](2016-10-03-img01.png) - -![](2016-10-03-img02.png) - -![](2016-10-03-img03.png) - - -And push the first commit to GitHub: - -```bash -git remote add origin https://github.com/sbglasius/demoplugin.git -git push -u origin master -``` - -### Publishing Plugin to Bintray - -Before configuring Travis, let us update the configuration to enable publishing the plugin to Bintray and the Grails Plugin Portal. - -`build.gradle` already contains the building blocks for this: - -```groovy -// ... -group "org.grails.plugins" -// ... -apply plugin:"org.grails.grails-plugin" -// ... -grailsPublish { - // TODO: Provide values here - user = 'user' - key = 'key' - githubSlug = 'foo/bar' - license { - name = 'Apache-2.0' - } - title = "My Plugin" - desc = "Full plugin description" - developers = [johndoe:"John Doe"] - portalUser = "" - portalPassword = "" -} -``` - -As can be seen, some values are not filled in, like credentials and `githubSlug`. Let us add those values in a way where credentials are not visible in the public GitHub repository. - -My code snippet will contain two ways to fetch configuration values: - -```groovy -grailsPublish { - user = System.getenv("BINTRAY_USER") ?: project.bintrayUser - key = System.getenv("BINTRAY_KEY") ?: project.bintrayKey - githubSlug = 'https://github.com/sbglasius/demoplugin' - license { - name = 'Apache-2.0' - } - title = "Demo Plugin" - desc = "A Demo Plugin, no need to publish" - developers = [johndoe:"John Doe"] - portalUser = System.getenv("GRAILS_PORTAL_USER") ?: project.grailsPortalUser - portalPassword = System.getenv("GRAILS_PORTAL_PASSWORD") ?: project.grailsPortalPassword -} -``` - -The configuration values are now read from either the running environment (this is where Travis will provide them, more on this later) or they will be taken from the project configuration or Gradle's global configuration (`~/.gradle/gradle.properties`). That is where I recommend storing these credentials. - -The format for `~/.gradle/gradle.properties` is like this: - -```properties -bintrayUser=user -bintrayKey=[secret] - -grailsPortalUser=user -grailsPortalPassword=[secret] -``` - -With this in place, it is now possible to publish the plugin to Bintray. This can be done like this: - -```bash -./gradlew bintrayUpload -``` - -Before moving on to Travis, let me push this to GitHub: - -```bash -git add . -git commit -m "Build script for Gradle" -git push -``` - -## Set Up Travis Command Line - -Before we can use Travis, we need to install the Travis Command line. Travis Command line requires Ruby, and since my machine is a Mac, Ruby is included. For other OSes, please go [here](https://www.ruby-lang.org/en/) for more information. - -Install Travis - -```bash -gem install travis -``` - -## Adding Travis to the Project - -The first thing we will do is initialize Travis for the project. - -```bash -$ travis init -Detected repository as sbglasius/demoplugin, is this correct? |yes| -Main programming language used: |Ruby| Groovy -.travis.yml file created! -sbglasius/demoplugin: enabled :) -``` - -Take a look in `.travis.yml`. You should see one line of code: - -```yml -language: groovy -``` - -Let us push this change to GitHub: - -```bash -git add .travis.yml -git commit -m "Added travis config" -git push -``` - -This will result in the first Travis build – a failed build. When Travis tries to run `gradle assemble` it fails with the following error: - -```text -FAILURE: Build failed with an exception. -* Where: -Build file '/home/travis/build/sbglasius/demoplugin/build.gradle' line: 50 -* What went wrong: -A problem occurred evaluating root project 'demoplugin'. -> Could not find property 'bintrayUser' on root project 'demoplugin'. -* Try: -Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. -BUILD FAILED -``` - -As we can see from the error, it cannot find the `bintrayUser` in the properties – since it is not defined yet together with the other credential properties. - -Travis has the ability to set environment variables defined in .travis.yml, but we do not want credentials in clear text. Fortunately, Travis support [encrypting environment variables](https://docs.travis-ci.com/user/environment-variables#Defining-Variables-in-.travis.yml). It is important to understand that the variables added here will only work for the GitHub account associated with the project. - -### Adding Environment Variables to `.travis.yml.` - -Let us add four variables to the configuration under `env.global`: - -```bash -travis encrypt BINTRAY_USER=user --add env.global -travis encrypt BINTRAY_KEY=*** --add env.global -travis encrypt GRAILS_PORTAL_USER=user --add env.global -travis encrypt GRAILS_PORTAL_PASSWORD=[secret] --add env.global -``` - -Now `.travis.yml` looks like this: - -```yml - language: groovy -env: - global: - - secure: iU4Y3JVWFteYl6J9MIlKv4H6nT0... - - secure: xPW7KBPVHe64hMloY30Oa5WowYO... - - secure: mhCnvHfjPX+wudLOfo6B8MFVGBV... - - secure: QF0+kEZLjL3ZJe0U/5jKC1dijgm... -``` - -and then commit and push to GitHub. - -_Now the build goes green on Travis_, but it is still not publishing the plugin to Bintray. That's up next. - -## Publish to Bintray with Travis - -Travis should test `master` on GitHub every time code is committed. It should build pull-requests but should only release the plugin to Bintray, when Git is tagged with a new version. - -The developers of Travis have thought of this and allow us to use a bash script to make more fine-grained logic. The basic script could look like this: - -```bash -#!/usr/bin/env bash - -set -e -./gradlew clean check assemble --stacktrace - -EXIT_STATUS=0 -echo "Publishing archives for branch $TRAVIS_BRANCH" -if [[ -n $TRAVIS_TAG ]] || [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then - if [[ -n $TRAVIS_TAG ]]; then - echo "Pushing build to Bintray" - ./gradlew bintrayUpload notifyPluginPortal || EXIT_STATUS=$? - fi -fi -exit $EXIT_STATUS -fi -``` - -The script is currently a bit more advanced than it needs to be; that is because more functionality will be added later. - -To execute the script on Travis-CI add these few lines to `.travis.yml`: - -```yml -before_script: -- rm -rf target -script: ./travis-build.sh -``` - -I prefer them before the `env:` block. To allow Travis to actually execute the script, it's important that the script execute flag on `travis-build.sh` is set: - -```bash -chmod 755 travis-build.sh -``` - -Add, commit, and push this to GitHub like before. - -The result will be a successful build, but not a deployment to Bintray. This is of course due to the `if` statement in the bash script, which checks if a git tag is set. If it is the `master` branch and if it's not a pull-request. - -### Tag and Release - -I now want to make a release of my plugin. To do so, I need to bump the plugin version in `build.gradle`, commit the change, tag the commit, and push it to GitHub. - -Let me start with `build.gradle` - -```groovy -version "0.2" -``` - -and the commit, tag, and push: - -```bash -git commit -a -m "Bump revision to 0.2" -git tag "0.2" -git push --tags -``` - -Notice, that I added `--tags` to the `git` command to get tags pushed to GitHub. - -That's it. The build is automated, and a release can be created on Bintray by using Travis-CI and GitHub tagging. - -## Deploy Snapshots to JFrog OSS Artifactory - -To have snapshot published to a public repo for others to use it, we can resort to Jfrog OSS Artifactory [oss.jfrog.org (OJO)](https://oss.jfrog.org/), since Bintray does not support snapshot builds. (This section is inspired by the [blog post by Álvaro Sánchez](https://www.slideshare.net/alvarosanchezmariscal/mastering-grails-3-plugins-greach-2016)). Before you can publish to OJO, please read [this document](https://www.jfrog.com/confluence/display/RTF/Deploying+Snapshots+to+oss.jfrog.org). - -### Setup Build Scripts - -Let us start with `build.gradle`: - -```groovy -buildscript { - //... -} -plugins { - id "com.jfrog.artifactory" version "4.4.0" -} - -version "0.3-SNAPSHOT" -group "demoplugin" -//... -grailsPublish { - //... -} -artifactory { - contextUrl = 'https://oss.jfrog.org' - publish { - repository { - repoKey = 'oss-snapshot-local' - username = System.getenv("BINTRAY_USER") ?: project.bintrayUser - password = System.getenv("BINTRAY_KEY") ?: project.bintrayKey - } - defaults { - publications('maven') - } - } -} -``` - -Since OJO and Bintray are tightly coupled, it is the same credentials used. - -Updated `travis-build.sh` - -```bash -#!/usr/bin/env bash - -set -e -./gradlew clean check assemble --stacktrace - -EXIT_STATUS=0 -echo "Publishing archives for branch $TRAVIS_BRANCH" -if [[ -n $TRAVIS_TAG ]] || [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then - if [[ -n $TRAVIS_TAG ]]; then - echo "Pushing build to Bintray" - ./gradlew bintrayUpload || EXIT_STATUS=$? - else - echo "Publishing snapshot to OJO" - ./gradlew artifactoryPublish || EXIT_STATUS=$? - fi -fi -exit $EXIT_STATUS -fi -``` - -Commit and push to GitHub and go watch the build on Travis-CI. Notice, that the build ends with a push to OJO. - -That's it. Travis-CI will now publish both snapshot versions and tagged versions to OJO and Bintray. - -But wait – there is a bit more. - -## Optimizing Travis-CI setup - -Take a look at the log-output from Travis-CI and notice that it downloads Gradle and all of the maven dependencies on each build. - -Travis-CI supports caching of these artifacts and a couple of other options. - -Add the following to `.travis.yml` just below the `language: groovy` block: - -```yml -sudo: false # run on container-based infrastructure - -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - - $HOME/.m2/repositories/ -``` - -This will reduce downloads and build time on Travis-CI. - -## Conclusion - -Travis-CI is a great tool to build and deploy your Grails plugin; it will help you maintain your code when receiving pull requests from the community. Happy CI'ing! +title: How to Use Travis-CI to Build and Deploy Your Plugin +date: October 3, 2016 +description: How to Use Travis-CI to Build and Deploy Your Grails® 3 Plugin +author: Søren Berg Glasius +image: 2016-10-03.jpg +CSS: [%url]/stylesheets/prism.css +JAVASCRIPT: [%url]/javascripts/prism.js +--- + +# [%title] + +[%author] + +[%date] + +Tags: #plugins #travis + +## Introduction + +When you create a Grails® 3 plugin and you want to share it with the world, wouldn't it be great if building and deploying was taken care of by a CI server? + +In this blog I will show you how to set up a Grails Plugin project that will be built and deployed on the [Travis-CI infrastructure](https://travis-ci.org/). + +Let us start out by setting up the project, so that it can be deployed to Bintray. Then we will add a Travis build to the mix. Finally we will explore how to handle snapshot deployment to [JFrog's open source repository](https://oss.jfrog.org/). + +## How Travis-CI Works + +Travis-CI works by monitoring your GitHub repository and whenever it sees changes, it will make a build of your project. The change can be a new commit pushed to GitHub, a new tag pushed to GitHub, or a pull request to your project on GitHub. + +If you want a deeper knowledge on how Travis-CI works, please [see the documentation](https://docs.travis-ci.com/). + +## Getting Started + +While you might have a plugin already, let us start this example by creating a plugin. The plugin will not have any functionality; it is only here to show the steps. + +```bash +grails create-plugin -profile plugin demoplugin +cd demoplugin +``` + +To get Travis-CI working the project has to live on GitHub. + +### Setting Up a GitHub Repository + +The first step is to enable Git for the local repository, add the project files, and commit it: + +```bash +git init +git add . +git commit -m "Initial commit" +``` + +Now go to [GitHub](https://github.com/) where we create a new repository: + +![Create a new repository](2016-10-03-img01.png) + +![Blog post image 2016-10-03-img02](2016-10-03-img02.png) + +![Blog post image 2016-10-03-img03](2016-10-03-img03.png) + + +And push the first commit to GitHub: + +```bash +git remote add origin https://github.com/sbglasius/demoplugin.git +git push -u origin master +``` + +### Publishing Plugin to Bintray + +Before configuring Travis, let us update the configuration to enable publishing the plugin to Bintray and the Grails Plugin Portal. + +`build.gradle` already contains the building blocks for this: + +```groovy +// ... +group "org.grails.plugins" +// ... +apply plugin:"org.grails.grails-plugin" +// ... +grailsPublish { + // TODO: Provide values here + user = 'user' + key = 'key' + githubSlug = 'foo/bar' + license { + name = 'Apache-2.0' + } + title = "My Plugin" + desc = "Full plugin description" + developers = [johndoe:"John Doe"] + portalUser = "" + portalPassword = "" +} +``` + +As can be seen, some values are not filled in, like credentials and `githubSlug`. Let us add those values in a way where credentials are not visible in the public GitHub repository. + +My code snippet will contain two ways to fetch configuration values: + +```groovy +grailsPublish { + user = System.getenv("BINTRAY_USER") ?: project.bintrayUser + key = System.getenv("BINTRAY_KEY") ?: project.bintrayKey + githubSlug = 'https://github.com/sbglasius/demoplugin' + license { + name = 'Apache-2.0' + } + title = "Demo Plugin" + desc = "A Demo Plugin, no need to publish" + developers = [johndoe:"John Doe"] + portalUser = System.getenv("GRAILS_PORTAL_USER") ?: project.grailsPortalUser + portalPassword = System.getenv("GRAILS_PORTAL_PASSWORD") ?: project.grailsPortalPassword +} +``` + +The configuration values are now read from either the running environment (this is where Travis will provide them, more on this later) or they will be taken from the project configuration or Gradle's global configuration (`~/.gradle/gradle.properties`). That is where I recommend storing these credentials. + +The format for `~/.gradle/gradle.properties` is like this: + +```properties +bintrayUser=user +bintrayKey=[secret] + +grailsPortalUser=user +grailsPortalPassword=[secret] +``` + +With this in place, it is now possible to publish the plugin to Bintray. This can be done like this: + +```bash +./gradlew bintrayUpload +``` + +Before moving on to Travis, let me push this to GitHub: + +```bash +git add . +git commit -m "Build script for Gradle" +git push +``` + +## Set Up Travis Command Line + +Before we can use Travis, we need to install the Travis Command line. Travis Command line requires Ruby, and since my machine is a Mac, Ruby is included. For other OSes, please go [here](https://www.ruby-lang.org/en/) for more information. + +Install Travis + +```bash +gem install travis +``` + +## Adding Travis to the Project + +The first thing we will do is initialize Travis for the project. + +```bash +$ travis init +Detected repository as sbglasius/demoplugin, is this correct? |yes| +Main programming language used: |Ruby| Groovy +.travis.yml file created! +sbglasius/demoplugin: enabled :) +``` + +Take a look in `.travis.yml`. You should see one line of code: + +```yml +language: groovy +``` + +Let us push this change to GitHub: + +```bash +git add .travis.yml +git commit -m "Added travis config" +git push +``` + +This will result in the first Travis build – a failed build. When Travis tries to run `gradle assemble` it fails with the following error: + +```text +FAILURE: Build failed with an exception. +* Where: +Build file '/home/travis/build/sbglasius/demoplugin/build.gradle' line: 50 +* What went wrong: +A problem occurred evaluating root project 'demoplugin'. +> Could not find property 'bintrayUser' on root project 'demoplugin'. +* Try: +Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. +BUILD FAILED +``` + +As we can see from the error, it cannot find the `bintrayUser` in the properties – since it is not defined yet together with the other credential properties. + +Travis has the ability to set environment variables defined in .travis.yml, but we do not want credentials in clear text. Fortunately, Travis support [encrypting environment variables](https://docs.travis-ci.com/user/environment-variables#Defining-Variables-in-.travis.yml). It is important to understand that the variables added here will only work for the GitHub account associated with the project. + +### Adding Environment Variables to `.travis.yml.` + +Let us add four variables to the configuration under `env.global`: + +```bash +travis encrypt BINTRAY_USER=user --add env.global +travis encrypt BINTRAY_KEY=*** --add env.global +travis encrypt GRAILS_PORTAL_USER=user --add env.global +travis encrypt GRAILS_PORTAL_PASSWORD=[secret] --add env.global +``` + +Now `.travis.yml` looks like this: + +```yml + language: groovy +env: + global: + - secure: iU4Y3JVWFteYl6J9MIlKv4H6nT0... + - secure: xPW7KBPVHe64hMloY30Oa5WowYO... + - secure: mhCnvHfjPX+wudLOfo6B8MFVGBV... + - secure: QF0+kEZLjL3ZJe0U/5jKC1dijgm... +``` + +and then commit and push to GitHub. + +_Now the build goes green on Travis_, but it is still not publishing the plugin to Bintray. That's up next. + +## Publish to Bintray with Travis + +Travis should test `master` on GitHub every time code is committed. It should build pull-requests but should only release the plugin to Bintray, when Git is tagged with a new version. + +The developers of Travis have thought of this and allow us to use a bash script to make more fine-grained logic. The basic script could look like this: + +```bash +#!/usr/bin/env bash + +set -e +./gradlew clean check assemble --stacktrace + +EXIT_STATUS=0 +echo "Publishing archives for branch $TRAVIS_BRANCH" +if [[ -n $TRAVIS_TAG ]] || [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then + if [[ -n $TRAVIS_TAG ]]; then + echo "Pushing build to Bintray" + ./gradlew bintrayUpload notifyPluginPortal || EXIT_STATUS=$? + fi +fi +exit $EXIT_STATUS +fi +``` + +The script is currently a bit more advanced than it needs to be; that is because more functionality will be added later. + +To execute the script on Travis-CI add these few lines to `.travis.yml`: + +```yml +before_script: +- rm -rf target +script: ./travis-build.sh +``` + +I prefer them before the `env:` block. To allow Travis to actually execute the script, it's important that the script execute flag on `travis-build.sh` is set: + +```bash +chmod 755 travis-build.sh +``` + +Add, commit, and push this to GitHub like before. + +The result will be a successful build, but not a deployment to Bintray. This is of course due to the `if` statement in the bash script, which checks if a git tag is set. If it is the `master` branch and if it's not a pull-request. + +### Tag and Release + +I now want to make a release of my plugin. To do so, I need to bump the plugin version in `build.gradle`, commit the change, tag the commit, and push it to GitHub. + +Let me start with `build.gradle` + +```groovy +version "0.2" +``` + +and the commit, tag, and push: + +```bash +git commit -a -m "Bump revision to 0.2" +git tag "0.2" +git push --tags +``` + +Notice, that I added `--tags` to the `git` command to get tags pushed to GitHub. + +That's it. The build is automated, and a release can be created on Bintray by using Travis-CI and GitHub tagging. + +## Deploy Snapshots to JFrog OSS Artifactory + +To have snapshot published to a public repo for others to use it, we can resort to Jfrog OSS Artifactory [oss.jfrog.org (OJO)](https://oss.jfrog.org/), since Bintray does not support snapshot builds. (This section is inspired by the [blog post by Álvaro Sánchez](https://www.slideshare.net/alvarosanchezmariscal/mastering-grails-3-plugins-greach-2016)). Before you can publish to OJO, please read [this document](https://www.jfrog.com/confluence/display/RTF/Deploying+Snapshots+to+oss.jfrog.org). + +### Setup Build Scripts + +Let us start with `build.gradle`: + +```groovy +buildscript { + //... +} +plugins { + id "com.jfrog.artifactory" version "4.4.0" +} + +version "0.3-SNAPSHOT" +group "demoplugin" +//... +grailsPublish { + //... +} +artifactory { + contextUrl = 'https://oss.jfrog.org' + publish { + repository { + repoKey = 'oss-snapshot-local' + username = System.getenv("BINTRAY_USER") ?: project.bintrayUser + password = System.getenv("BINTRAY_KEY") ?: project.bintrayKey + } + defaults { + publications('maven') + } + } +} +``` + +Since OJO and Bintray are tightly coupled, it is the same credentials used. + +Updated `travis-build.sh` + +```bash +#!/usr/bin/env bash + +set -e +./gradlew clean check assemble --stacktrace + +EXIT_STATUS=0 +echo "Publishing archives for branch $TRAVIS_BRANCH" +if [[ -n $TRAVIS_TAG ]] || [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then + if [[ -n $TRAVIS_TAG ]]; then + echo "Pushing build to Bintray" + ./gradlew bintrayUpload || EXIT_STATUS=$? + else + echo "Publishing snapshot to OJO" + ./gradlew artifactoryPublish || EXIT_STATUS=$? + fi +fi +exit $EXIT_STATUS +fi +``` + +Commit and push to GitHub and go watch the build on Travis-CI. Notice, that the build ends with a push to OJO. + +That's it. Travis-CI will now publish both snapshot versions and tagged versions to OJO and Bintray. + +But wait – there is a bit more. + +## Optimizing Travis-CI setup + +Take a look at the log-output from Travis-CI and notice that it downloads Gradle and all of the maven dependencies on each build. + +Travis-CI supports caching of these artifacts and a couple of other options. + +Add the following to `.travis.yml` just below the `language: groovy` block: + +```yml +sudo: false # run on container-based infrastructure + +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock +cache: + directories: + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + - $HOME/.m2/repositories/ +``` + +This will reduce downloads and build time on Travis-CI. + +## Conclusion + +Travis-CI is a great tool to build and deploy your Grails plugin; it will help you maintain your code when receiving pull requests from the community. Happy CI'ing! diff --git a/posts/2016-11-14.md b/posts/2016-11-14.md index 981ce4687d5..a5c75f46ebc 100644 --- a/posts/2016-11-14.md +++ b/posts/2016-11-14.md @@ -1,117 +1,117 @@ -title: Introducing the React Profile for Grails® -date: November 14, 2016 -description: Learn about Grails® React profiles, one aimed at monolithic Grails applications, and a second profile which generates a multi-project client/server structure. -author: Zachary Klein -image: 2016-11-14.jpg ---- - -# [%title] - -[%author] - -[%date] - -Tags: #react - -## React Profiles for the Grails® framework - -Grails 3 offers great support for the Angular framework, including the Angular Scaffolding plugin as well as profiles for both Angular 1.x and 2.x. Recently new profiles have been released to provide support for creating React applications with Grails 3. - -This post will cover *two new profiles for React*, one aimed at monolithic Grails applications, and a second profile which makes use of the brand new [`create-react-app` CLI](https://github.com/facebookincubator/create-react-app) and generates a multi-project client/server structure. - -![](2016-11-14-img01.png) - -## React & Webpack Profiles - -If you've read the previous post on [Using React with the Grails framework](/blog/2016-05-28.html), you've probably noticed that there's quite a bit of wiring that has to happen to get React working properly in the context of a Grails application. This is a place where profiles shine, and now you can get an entire React/Grails project setup immediately upon app generation, including some basic sample React code. - - grails create-app myReactApp --profile=org.grails.profiles:react:1.0.2 - -The `react:1.x` profile is based on another new profile, `org.grails.profiles:webpack:1.x`. The `webpack` profile can be used standalone as well, if you want to use webpack with another JavaScript framework in a Grails project. In addition, the `webpack` profile offers a single feature which will configure the `babel` transpiler with support for ES6 - it also includes sample code to demonstrate the feature. - - grails create-app myWebpackApp --profile=org.grails.profiles:webpack:1.0.2 --features=babel - -Both the `webpack` and `react:1.x` profiles will expect the JavaScript source files to be kept under `/src/main/webapp`. You can simply start up your app, and webpack will run automatically and bundle the JavaScript into the Grails asset pipeline. Custom Gradle tasks such as `bundle` (to generate the webpack bundle on app startup) and `webpack` (to run webpack in "watch" mode and reload any changes) are defined. You may also run the corresponding npm scripts if you have npm installed (scripts are defined in `package.json`). - -For instance, you can run webpack alongside your Grails app with this command: - - ./gradlew webpack //or: npm run webpack - -Now when you make changes to your JavaScript/React code under `/src/main/webapp`, webpack will automatically regenerate the bundle. Just refresh your page to see the changes. - -In addition, the `react` profile adds a `mochaTest` task which will run React tests with the mocha test runner. Test sources are kept under `/src/test/js`, and a simple test is provided. Simply run: - - ./gradlew mochaTest //or: npm test - - -## React Profile - Multi-Project Edition - -The react profile is being released with two branches, currently `1.0.2` and `2.0.1`. - -The `react:2.0.1` profile is complete rewrite of the 1.x version, and it leverages the new React CLI from Facebook, `create-react-app`. For more information on the features provided by `create-react-app`, please read the [documentation on Github](https://github.com/facebookincubator/create-react-app). - -In short, `create-react-app` provides us with a complete webpack/React project, with custom scripts defined to build, run and test our React app. It is designed for standalone React apps, which makes it a perfect choice for a client/frontend application backed by a separate server application. That is exactly what `react:2.0.1` provides. - -![](2016-11-14-img02.png) - -Please note that `react:2.0.1` depends upon the new CORS support in Grails 3.2.1, so you will need to be using that version of Grails or newer. - -To get started with this profile, specify it when generating your app: - - grails create-app myReactMultiApp --profile=org.grails.profiles:react:2.0.1 - -Take a look at the directory structure - you will see a typical Gradle multi-project build, with separate client and server projects. - - -rw-r--r-- 1 zak staff 65 Nov 1 13:10 build.gradle - drwxr-xr-x 9 zak staff 306 Nov 1 13:15 client - drwxr-xr-x 3 zak staff 102 Nov 1 13:10 gradle - -rwxr--r-- 1 zak staff 4971 Nov 1 13:10 gradlew - -rwxr--r-- 1 zak staff 2314 Nov 1 13:10 gradlew.bat - drwxr-xr-x 8 zak staff 272 Nov 1 13:12 server - -rw-r--r-- 1 zak staff 26 Nov 1 13:10 settings.gradle - -`server` is of course our Grails application. The profile will generate a Grails app using the `rest-api` profile, which provides support for creating domain classes as restful resources as well as JSON and Markup views. - -`client` is our React app. It has been rewritten with React-Bootstrap (Bootstrap 3) and will connect with `server` via REST calls - it has no Grails dependencies of any kind. - - -rw-r--r-- 1 zak staff 44412 Nov 1 13:10 README.md - -rw-r--r-- 1 zak staff 669 Nov 1 13:10 build.gradle - -rw-r--r-- 1 zak staff 404 Nov 1 13:10 package.json - drwxr-xr-x 4 zak staff 136 Nov 1 13:10 public - drwxr-xr-x 10 zak staff 340 Nov 1 13:10 src - -This project structure (with the exception of `build.gradle`, which is specific to the `react:2.0.1` profile) is all courtesy of `create-react-app`, and includes an excellent `README` file. In short, the `src/` directory is where the React code is kept, `public/` is for public resources that you wish to make available from your React app without going through webpack's bundling - this directory also includes a template `index.html` file which is used to generate the React app's home page. Again, see the `create-react-app` documentation for more details. - -One significant customization of the `client` project (besides the Grails-branded UI) is the file `src/config.js`. This file is used to specify the URL of the backend, by default `http://localhost:8080`. It also obtains the current version of the React app from 'package.json'. - -As with the 1.x version of the `react` profile, this profile define custom Gradle tasks, including a `bootRun` task to startup the client app. You can either start up the `server` and `client` apps separately: - - ./gradlew server:bootRun - - //in another terminal - ./gradlew client:bootRun - -Or you can take advantage of Gradle's parallel execution to run both client and server apps in a single command: - - ./gradlew bootRun -parallel - -Other tasks defined in `client` wrap the `create-react-app` scripts for building and testing the React app. You can run them with the Gradle wrapper, or run the npm scripts directly if you have npm installed. - - ./gradlew client:test //or, from the client project dir: npm test - - ./gradlew client:build //or, from the client project dir: npm run build - -Again, please see the `create-react-app` documentation for more information on leveraging these scripts and the other features provided by `create-react-app`. - -## Wrap-Up - -These two profiles offer two ways to use React in the context of a Grails application. If you want to use React within your existing Grails application, either to render components on a GSP or to replace some or all of your GSP pages, then use `react:1.0.1` (or the latest version of the 1.x branch). - -If you prefer a completely separate frontend for your Grails application, and/or want to take advantage of the features of the `create-react-app` CLI, then the `react:2.0.1` (or latest version of the 2.x branch) is made for you. - -Whichever one you choose, here's hoping these profiles help you enjoy using React with Grails 3! - -## Links - - - `create-react-app`: [https://github.com/facebookincubator/create-react-app](https://github.com/facebookincubator/create-react-app) - - "Using React with the Grails framework": [/blog/2016-05-28.html](/blog/2016-05-28.html) +title: Introducing the React Profile for Grails® +date: November 14, 2016 +description: Learn about Grails® React profiles, one aimed at monolithic Grails applications, and a second profile which generates a multi-project client/server structure. +author: Zachary Klein +image: 2016-11-14.jpg +--- + +# [%title] + +[%author] + +[%date] + +Tags: #react + +## React Profiles for the Grails® framework + +Grails 3 offers great support for the Angular framework, including the Angular Scaffolding plugin as well as profiles for both Angular 1.x and 2.x. Recently new profiles have been released to provide support for creating React applications with Grails 3. + +This post will cover *two new profiles for React*, one aimed at monolithic Grails applications, and a second profile which makes use of the brand new [`create-react-app` CLI](https://github.com/facebookincubator/create-react-app) and generates a multi-project client/server structure. + +![Blog post image 2016-11-14-img01](2016-11-14-img01.png) + +## React & Webpack Profiles + +If you've read the previous post on [Using React with the Grails framework](/blog/2016-05-28.html), you've probably noticed that there's quite a bit of wiring that has to happen to get React working properly in the context of a Grails application. This is a place where profiles shine, and now you can get an entire React/Grails project setup immediately upon app generation, including some basic sample React code. + + grails create-app myReactApp --profile=org.grails.profiles:react:1.0.2 + +The `react:1.x` profile is based on another new profile, `org.grails.profiles:webpack:1.x`. The `webpack` profile can be used standalone as well, if you want to use webpack with another JavaScript framework in a Grails project. In addition, the `webpack` profile offers a single feature which will configure the `babel` transpiler with support for ES6 - it also includes sample code to demonstrate the feature. + + grails create-app myWebpackApp --profile=org.grails.profiles:webpack:1.0.2 --features=babel + +Both the `webpack` and `react:1.x` profiles will expect the JavaScript source files to be kept under `/src/main/webapp`. You can simply start up your app, and webpack will run automatically and bundle the JavaScript into the Grails asset pipeline. Custom Gradle tasks such as `bundle` (to generate the webpack bundle on app startup) and `webpack` (to run webpack in "watch" mode and reload any changes) are defined. You may also run the corresponding npm scripts if you have npm installed (scripts are defined in `package.json`). + +For instance, you can run webpack alongside your Grails app with this command: + + ./gradlew webpack //or: npm run webpack + +Now when you make changes to your JavaScript/React code under `/src/main/webapp`, webpack will automatically regenerate the bundle. Just refresh your page to see the changes. + +In addition, the `react` profile adds a `mochaTest` task which will run React tests with the mocha test runner. Test sources are kept under `/src/test/js`, and a simple test is provided. Simply run: + + ./gradlew mochaTest //or: npm test + + +## React Profile - Multi-Project Edition + +The react profile is being released with two branches, currently `1.0.2` and `2.0.1`. + +The `react:2.0.1` profile is complete rewrite of the 1.x version, and it leverages the new React CLI from Facebook, `create-react-app`. For more information on the features provided by `create-react-app`, please read the [documentation on Github](https://github.com/facebookincubator/create-react-app). + +In short, `create-react-app` provides us with a complete webpack/React project, with custom scripts defined to build, run and test our React app. It is designed for standalone React apps, which makes it a perfect choice for a client/frontend application backed by a separate server application. That is exactly what `react:2.0.1` provides. + +![Blog post image 2016-11-14-img02](2016-11-14-img02.png) + +Please note that `react:2.0.1` depends upon the new CORS support in Grails 3.2.1, so you will need to be using that version of Grails or newer. + +To get started with this profile, specify it when generating your app: + + grails create-app myReactMultiApp --profile=org.grails.profiles:react:2.0.1 + +Take a look at the directory structure - you will see a typical Gradle multi-project build, with separate client and server projects. + + -rw-r--r-- 1 zak staff 65 Nov 1 13:10 build.gradle + drwxr-xr-x 9 zak staff 306 Nov 1 13:15 client + drwxr-xr-x 3 zak staff 102 Nov 1 13:10 gradle + -rwxr--r-- 1 zak staff 4971 Nov 1 13:10 gradlew + -rwxr--r-- 1 zak staff 2314 Nov 1 13:10 gradlew.bat + drwxr-xr-x 8 zak staff 272 Nov 1 13:12 server + -rw-r--r-- 1 zak staff 26 Nov 1 13:10 settings.gradle + +`server` is of course our Grails application. The profile will generate a Grails app using the `rest-api` profile, which provides support for creating domain classes as restful resources as well as JSON and Markup views. + +`client` is our React app. It has been rewritten with React-Bootstrap (Bootstrap 3) and will connect with `server` via REST calls - it has no Grails dependencies of any kind. + + -rw-r--r-- 1 zak staff 44412 Nov 1 13:10 README.md + -rw-r--r-- 1 zak staff 669 Nov 1 13:10 build.gradle + -rw-r--r-- 1 zak staff 404 Nov 1 13:10 package.json + drwxr-xr-x 4 zak staff 136 Nov 1 13:10 public + drwxr-xr-x 10 zak staff 340 Nov 1 13:10 src + +This project structure (with the exception of `build.gradle`, which is specific to the `react:2.0.1` profile) is all courtesy of `create-react-app`, and includes an excellent `README` file. In short, the `src/` directory is where the React code is kept, `public/` is for public resources that you wish to make available from your React app without going through webpack's bundling - this directory also includes a template `index.html` file which is used to generate the React app's home page. Again, see the `create-react-app` documentation for more details. + +One significant customization of the `client` project (besides the Grails-branded UI) is the file `src/config.js`. This file is used to specify the URL of the backend, by default `http://localhost:8080`. It also obtains the current version of the React app from 'package.json'. + +As with the 1.x version of the `react` profile, this profile define custom Gradle tasks, including a `bootRun` task to startup the client app. You can either start up the `server` and `client` apps separately: + + ./gradlew server:bootRun + + //in another terminal + ./gradlew client:bootRun + +Or you can take advantage of Gradle's parallel execution to run both client and server apps in a single command: + + ./gradlew bootRun -parallel + +Other tasks defined in `client` wrap the `create-react-app` scripts for building and testing the React app. You can run them with the Gradle wrapper, or run the npm scripts directly if you have npm installed. + + ./gradlew client:test //or, from the client project dir: npm test + + ./gradlew client:build //or, from the client project dir: npm run build + +Again, please see the `create-react-app` documentation for more information on leveraging these scripts and the other features provided by `create-react-app`. + +## Wrap-Up + +These two profiles offer two ways to use React in the context of a Grails application. If you want to use React within your existing Grails application, either to render components on a GSP or to replace some or all of your GSP pages, then use `react:1.0.1` (or the latest version of the 1.x branch). + +If you prefer a completely separate frontend for your Grails application, and/or want to take advantage of the features of the `create-react-app` CLI, then the `react:2.0.1` (or latest version of the 2.x branch) is made for you. + +Whichever one you choose, here's hoping these profiles help you enjoy using React with Grails 3! + +## Links + + - `create-react-app`: [https://github.com/facebookincubator/create-react-app](https://github.com/facebookincubator/create-react-app) + - "Using React with the Grails framework": [/blog/2016-05-28.html](/blog/2016-05-28.html) diff --git a/posts/2021-04-07-publish-grails-plugin-to-maven-central.md b/posts/2021-04-07-publish-grails-plugin-to-maven-central.md index 7d951044dcc..db7003a648c 100644 --- a/posts/2021-04-07-publish-grails-plugin-to-maven-central.md +++ b/posts/2021-04-07-publish-grails-plugin-to-maven-central.md @@ -44,7 +44,7 @@ The Sonatype’s OSSRH service is the primary place to publish plugins to the Ce 1. Create a new Issue in the "Community Support - Open Source Project Repository Hosting" project. 2. The issue type should be "New Project". 3. On the Project Details page, enter basic project details. See the screenshot below for an example: - ![](2021-04-07-img01.png) + ![Blog post image 2021-04-07-img01](2021-04-07-img01.png) **NOTE:** Once the ticket is resolved, you should be good to deploy your artifacts. 3. ### Make sure your project meets the minimum requirements