A client-side workflow plays a significant part in creating optimized and maintainable websites. Here's a small overview of the client-side stack I have recently been using.
Semantic markup
I use Twig, a powerful templating engine and I keep my HTML documents as pure and semantic as I can. I often remind myself to keep things simple and try to separate the content from its styling or presentation, the former belonging to the HTML document, while the latter in the CSS file.
CSS frameworks served me well in the past especially for prototyping, however conforming totally to their way of doing things without having spent time to create and tune my own workflow, resulted most of the times in a non-semantic markup which was hard to maintain.
Having to edit HTML files to change grid settings for a specific element by adding or removing the appropriate classes for example as some framework dictates can be really inconvenient, especially when these templates get splitted into many parts and processed by the backend before they get served to the client.
Using semantic markup is a simple first step that results in making our views maintainable and aids in keeping our structure clean so that we can utilize the power our templating engine(s) provides us with. Each element thus gets assigned an ID or class that describes the content it represents, taking care to avoid using identifiers related to its presentation.
CSS pre-processor
A CSS pre-processor supports many interesting features that are currently missing from the original CSS and provides things like variables, loops, mixins and functions so one can really tune and automate the way things get done with stylesheets in general.
Since automation is always good, and as I've been reading many good things about Sass, I decided to give it a try. There's also a strong community supporting it and a huge set of libraries and frameworks written in Sass. The normal CSS syntax can also be used so it can be learned pretty quickly.
Using a CSS pre-processor you have the ability to create stylesheets in many files (partials) which can later be merged to a single final minified CSS file that would normally be served to the client.
Semantic grid
Having a grid we can set elements in, each of them taking up a specified amount of columns is a very handy abstraction. There are two criteria that I like to take into consideration when choosing a grid framework or library: the freedom to maintain semantic structure and compatibility with our CSS pre-processor of choice, in my case Sass.
I have been very happy using Susy, a grid framework written in Sass, that does all the math for you and lets you create awesome layouts. It is completely unopinionated and does not get in your way. Using Susy, changing our layout and column sizes becomes only a matter of changing the values for a couple of variables in our Sass files, so simple!
Another point where it really shines, is the way it handles media queries which relies on the amazing Sass library, Breakpoint. Every element gets assigned different amount of columns for different breakpoints whenever we need to apply changes for different viewports and this is extremely helpful.
Javascript modules
I have been looking for an easy and extendable way to include and manage Javascript in my web applications, which can be optimized for mobile phones. Many backend frameworks have components that let you manage and include Javascript files in your application, however this is not always an optimal or convenient option for a non-trivial project. What would happen if at some point we need to change the server-side technology?
Separating our code into multiple files really helps but then having to load files synchronously via multiple script tags creates performace issues, DOM content will not load until all the tags defined in the head section complete loading first, which becomes more evident when the site gets accessed by mobile phones and slow connections. Simple workarounds such as placing the script tags at the end exist, though most of the times these are not really the answer.
Having a completely independent way to include, merge and minify your code, and by using the very useful module pattern, you can write more efficient modular code, while at the same time minimizing the coupling between client and server code and decreasing load times.
To handle all these issues I use RequireJS a Javascript module loader. Its AMD web module support gives you the power to split your code into separate files that get loaded asynchronously. Code can be reused and all our files can be cleanly organised.
RequireJS comes with its own optimizer and can be used to build your project into a single minified file (or a couple of minified files depending on your configuration and the way you prefer to bundle your project—possibilities are endless.) Structuring our project with RequireJS we are able write our code into many separate modules and we can minimize the requests to the server by building the project into a single file for the production environment whenever we need to.
Build process
Introducing these tools to make our lives easier comes at a price, and a quick way to rebuild our project whenever we make changes soon will soon become essential. We have to be able to listen for changes in our scripts and in our stylesheets and perform the necessary tasks that need to be performed for all the different environments we decide to create our projects in.
Fortunately tools exist for exactly this purpose and the one I have been using is Grunt, a Javascript task-runner that can be installed and managed via npm, the Node.js package manager.
Grunt supports plugins that cover almost every need, it is really simple to use, and gives you the ability to register many tasks covering every need. I am even using it right now in composing this post, letting it sit quietly in the background and listen for changes in my markdown files, awaiting to build the project every time I make changes, through the grunt-sculpin plugin which takes care running the sculpin command-line tool.
Closing thoughts
Creating a workflow for the front-end, keeping it separated from the server-side technologies, forms a necessary foundation for all those changes and requirements that might suddenly arise, so we can keep our focus on the essence or functionality our project needs.
As a result, the whole web stack gets easier to manage and everything finds its proper place in the spectrum of technologies we are using. Our server-side code becomes lean and is used for the functionality, database access and every other aspect we need our server to handle, while our client-side stack ensures us that information gets presented in a maintainable, optimized and responsive way.