How I built
Using Polymer, Gulp, Jade, Sass and ES6
This year’s grand sponsor is the Polymer project, with a special prize for Best Use of Web Components, so this event is the best time to experiment with Polymer.
With Polymer and Web Components approaches web development with a radically different approach.
- index.html (the markup)
- stylesheets/ (containing all your app’s stylesheets)
With Polymer, your web application will be totally component based. Instead of putting parts of your components in different places, you now put all of them in a single “polymer-element” tag.
Web Components has some magic to prevent CSS or IDs from interfering with each other, so you’re free to use any ID inside your component.
Your component becomes a new tag. To use it, import the component using a <link> tag and simply use the new tag.
For my synthesizer app, I used:
Post-processing steps may include vendor-prefixing your CSS, inlining, and minification.
For traditional web applications, this is not a problem since your markup, script, and stylesheet are all in different files.
With Polymer, however, markups, stylesheets, and scripts are combined into a single tag, so this is not as straightforward.
Jade Filters are Awesome
Now I can write my component like this:
…and it will be compiled into this:
Jade also allows including other files, and you can combine that with filters. That means you can put stylesheets and scripts in a different file:
Building using Gulp
Here’s my gulpfile.js which takes all .jade file, pipe it through gulp-jade, and pipe it into dist/ directory. Simple, quick and dirty:
In the last three lines I also defined a “watch” task that watches jade, js, and css files and run the “compile” tasks whenever a file changes.
To compile and recompile when file changes, I used this command:
while true; do gulp compile watch; done
I had to put it in a while loop, because a compilation error crashes the Gulp process, so I had to re-spawn it to keep it watching my files.
That’s it. I always loved it when different tools and libraries just work together in a beautiful manner, because many times, tools don’t just work together.
Because my timeframe was limited, I made a lot of design decisions without thinking.
I ended up with a badly-designed mess of code. The UI and audio processing code for a single unit ended up in different places, totally breaking Polymer’s concept of “components,” making it virtually non-extensible.
There were also a lot of naming inconsistencies and uncontrolled access to global state. The two-way data bindings in the code were very messy. A lot of logic goes directly into the main ‘synth-app’ element.
This is a maintenance nightmare.
When using Polymer, personally I think you have to be very careful on how to do data binding, because it’s so easy to create such mess. But for a project that needs to be finished fast, Polymer does’t get in your way.
In fact, Polymer has a lot of off-the-shelf components that makes your life easier. For instance, the application’s global state is stored inside a single Object:
I wanted the synthesizer’s state to be persisted so that the synth’s configuration won’t be lost when you refresh the page. I hooked the synth’s state to the localStorage using a single tag:
And now they are synchronized. Very convenient!
But there’s one more problem: because of uncontrolled access, the UI mutated properties deep inside the model directly! The app could not detect a change such deeply-nested object and won’t save the synth’s state.
To fix that in a quickest possible way, I ended up putting this wherever the synth’s state is altered.
There are 10 occurrences of the above code, and if I forget to call it somewhere, then the synth will not adjust the processing chain and will not save its state.
This is very error-prone.
React promotes the Flux architecture that encourages one-way data flow. But it makes your code more verbose with all these Dispatcher, Store and change listener stuff, on the other hand, it makes code less error-prone. However, I might not finish the project on time if I strictly use the React+Flux architecture, as sometimes architecture can often get in my way.
But with Polymer, you are your own boss. Just be reminded about the technical debts you may incur.