Hello!
Not so long ago a javascript library for building user interfaces from facebook -
Reactjs appeared on the Internet. This library is ideal for creating simple and complex javascript applications. Allows you to organize your client-side in the form of independent components. It takes care of modifying the DOM structure of the tree. And it does it very efficiently and reasonably.
In general, as a result of a small acquaintance with reactjs, such an application appeared -
demo . The purpose of this post is to share impressions of working with reactjs + gruntjs + browserify.
')
Below will be stated:
- The main points of creating the application and personal impressions (symbiosis of reactjs + browserify + gruntjs + coffeescript).
- The server prerenderg reactjs components for static pages.
- Approach to building reactjs applications using gruntjs and gh-pages deploy with one command.
Those who are interested in asking under the cat ...
The idea of the application
I will not prevaricate, the idea of the online gamma generator is not new, and I drew my inspiration from this
resource by adding a few buns from myself. Gammas, first of all, are useful for people who are trying to master improvisation. And as useful as an exercise to improve the technique of the game. Each gamma, in fact, consists of certain notes, which are calculated by a specific formula. It is a pleasure for me, as a guitar lover, to guess the key and try to select a solo to my favorite music. And this application is very good at helping.
What was implemented

- The choice of tonality.
- Gamma selection (minor, major, blues, pentatonic).
- The choice of guitar pitch.
- The alternate reproduction of notes for the selected part of the neck of the guitar.
- Change the direction of music playback (top down / bottom up).
- Possibility of looping (for learning).
- Automatically change the direction of music playback.
Organization of the application
For good karma, and I just love to tinker with it - all javascript was designed as commonjs modules, glued into 1 file and minified, and reactjs components are prerendered during the build and inserted into the html pages.
This effect was achieved with the help of such tools:
The commonjs format is very convenient and allows you to use the same javascript code on both the server and the client.
Server Pre-Rendering
One of the most attractive features in reactjs for me is the possibility of server-side pre-rendering of components. After all, it is great to be able to initialize the initial state of your application and draw the components before they get to the browser. The beauty of reacjs is that he himself understands when the component has already been drawn, and does not try to do it again. If you look at the code for a page from
demo , you can see that the main component of the page has already been rendered before the content is sent to the browser. The main requirement for server rendering is the ability to make the require component on the server. Since the pre-rendering procedure is necessary only when deploying - I decided to make a separate grunt plugin for it, which will process html files before loading it on gh-pages -
grunt-react-render .
The plugin is quite simple and operates according to this algorithm:
- We read the file for processing.
- Parsing the html structure, we find tags with the data-rcomp attribute.
- Read the relative path to the component from the data-rcomp attribute.
- Make the require of the component and call the method react.renderComponentToString ().
- Insert inside the tag with the data-rcomp attribute.
- Save the file.
Here is the html section of the main page code that is processed by this plugin:
<div class="container"> <h1>Scales generator</h1> <div data-rcomp="./lib-js/pages/scales_page_component" id="container"> </div> </div>
This is what the grunt plugin configuration looks like:
react_render: index: options: src: '.dist/index.html'
Impressions of Reactjs
Reactjs pushes to form the application logic as separate configurable components that can be reused as much as possible. The philosophy of reactjs says that components must keep state to a minimum, since the stored state in different places is a source of magic and side effects. Therefore, it is better to save and change the state in the top-level components and pass it to the internal components via properties (props).
In the process of creating an application, I faced the fact that there are few ready-made solutions for simple components on the Internet. At first, I was very embarrassed and I spent some time searching for ready-made solutions, for example for the same drop-down lists. I tried to integrate them into my project and adapt the layout, but then I tried to implement the functionality of such a drop-down list from scratch:

And I was surprised how simple it is with reactjs. In fact, the component becomes very simple when the whole rendering takes on reactjs, and you just have to ask how to draw the component in different states and switch it correctly.
drop-down code React = require 'react' {ul, li, span, div, a} = React.DOM SimpleDropdown = React.createClass displayName: "SimpleDropdown" getDefaultProps: -> onChange: -> getInitialState: -> isOpen: false value: @props.value or "" toggle: -> @setState {isOpen: !@state.isOpen} itemClick: (ev) -> ev.preventDefault() value = (ev.target.getAttribute "value") @setState {value, isOpen: false} @props.onChange value render: -> self = @ options = @props.options.map ([value, text]) -> (li {key: "opt_#{value}"}, (a {value, href: "#", onClick: self.itemClick}, text)) openCls = if @state.isOpen then "open" else "" currentOption = (@props.options.filter ([value, text]) => value.toString() is @state.value.toString())?[0] (div className: "btn-group #{openCls}" (button className: "btn btn-default" onClick: @toggle (span {className: "glyphicon"}, "") currentOption?[1] (span {className: "caret"}, "")) (ul className: "dropdown-menu" ref: "select" options))
Coffeescript was very convenient for describing the html structure of components. Especially useful is its restructuring assignment.
{div, ul, span, li} = React.DOM (div {className: "div"} (span {className: "span", "span Text") (ul (li "option 1") (li "option 2") )
As for me, it is enough to not use
jsx . I also had to tinker with the bootstrap buttons and the draggable behavior of the components.
Business logic
Since the application was created not only to master the reactor, but also to simplify your life for others in studying the scales on the guitar - I tried to make all the logic as simple as possible so that, if possible, someone could add a different scale or scale without much effort. guitars. So, for example, the description of gammas in the code looks like:
SCALES = Minor: desc: "Minor scale" size: [STEP, hSTEP, STEP, STEP, hSTEP, STEP, STEP] get_notes: (Tonica) -> generate_scale Tonica, SCALES.Minor Major: desc: "Major scale" size: [STEP, STEP, hSTEP, STEP, STEP, STEP, hSTEP] get_notes: (Tonica) -> generate_scale Tonica, SCALES.Major ...
Each gamma has its own formula (size), a function for generating notes and a description. Having shown this project to one friend, he, having a deeper knowledge of music, easily added several other scales.
The data for guitar lines is just as simple:
TUNINGS = "Standart": name: "Standart E" notes: [E, B, G, D, A, E] offset: [0, 0, 0, 0, 0, 0] "DropD": name: "Dropped D" notes: [E, B, G, D, A, D] offset: [0, 0, 0, 0, 0, -2] ...
The sequential playback of sounds is implemented using the
howler.js library.
If someone from those who read up to this place has a desire to add and improve something in the project, I will be extremely happy.
Build and warm 1st team
Many do not bother at all on the assembly of the project and the organization of the code, maybe this is correct. Personally, I get pleasure from the automation process, so I was a little confused over this and organized the assembly and the project deployment on gruntjs. There are 3 main commands:
- grunt build (coffeescript compilation, browser modules for commonjs, js and css gluing into 1 file)
- grunt deploy (build + minify js and css, copy to the directory for deployment, pre-rendering the reactant of components)
- grunt deploy-gh (deploy + deploy on github pages)
Gruntfile can tell more details about the build project in the
repository .
findings
In general, working with reactjs left a positive impression, in the future I want to try it along with some kind of FRP library (RxJs or bacon.js). Also, I plan to add another useful functionality to this project.
Thank you for attention! Any criticism, suggestions and feedback are welcome.
Source Code -
github