BTBCS Development
- 11 minsA Busy Summer
Over the course of this past summer, I spent the majority of my time working at the founding CIO (Chief Information Officer) of a new Social Services organization called “Building the Bridges Community Services”. Our website is located at btbcs.org and is available worldwide using Dreamhost as the backend and Cloudflare as the CDN (Content Delivery Network).
Over the course of the summer, I built the entire website from the ground up using Bootstrap 4 CSS/JS framework, my own PHP shell to manage header and footer items, and a variety of PHP and JS functions to perform various aspects of the website like PHPMailer and form submissions via AJAX requests. More on all these later.
Of course, developing a massive website with so many intertwining web technologies, it became obvious that I had no way to easily test the site on my Windows OS. Which is why I also learned how to use Docker this summer. With Docker, I could create a test environment that is nearly identical to my actual production environment on a shared Dreamhost server. The process was quite complex at first, but has become incredibly essential to my development workflow. In the future, I would like to be able to use Kubernetes or similar tools to simplify the transition from the development environment to production.
Aside from the website development, I also got the chance to setup a Google Workspace as the primary administrator. It was a very worthwhile experience getting to see all the backend tools and settings that Google supplies to their customers.
General State of Web Development
From my experiences this past summer, the state of web development is rather crazy. There are approximately millions of different ways to go about designing and building a website. There are almost a dozen different programming languages alone which can be used in web design (PHP, Ruby, JavaScript, etc). To be honest, you can usually use just about any language you want as the backend so long as the server’s OS can support it.
For my this website, I started with the basics. I refrained from using any language out side of HTML, CSS, and JS. I will readily say that working with Bootstrap CSS was a wonderful time. They have created an outstanding set of CSS helper functions and classes that made my amateur design abilities look visually pleasing. I look forward to seeing what improvements the community has made to Bootstrap with the v5 update.
As nice and simple as trying to make a static website was, I quickly realized it was not feasible to create the functionality I needed without a backend server-side language. Enter PHP on to the scene. I have long expressed my displeasure with PHP overall, but I knew it was the most common and widely used server language.
PHP was useful for a variety tasks on my website: submitting / handling forms, sending emails, and adding the header and footer to each page. Looking back however, I wish I had taken the time to learn something other than PHP like Ruby or NodeJS.
I finally reached the point where the last big feature to implement on the website was blog. To do this properly, I needed the ability to archive posts and make a continually growing list of posts look nice. Most websites use WordPress to handle this, but I refused to use WordPress in order to keep the site source code function as independently as possible. The solution I came up with was perhaps a little odd.
I used something known as Jekyll. This very website you are reading from right now was also generated by Jekyll. All Jekyll does is take websites with dynamic content such as a changing number of blog posts and generates a set of static HTML webpages from it. What made my use case really strange was that I was creating PHP files instead of HTML, something that Jekyll was never intended to do. With a little bit of tweaking to Jekyll’s source code (something they actually encourage!), I was able to make Jekyll meet my needs perfectly.
In the future, I’d be much more interested in using tools like Ruby and Jekyll to generate the website from the very start. The idea of serving only static HTML files is very appealing, not to mention they support SASS too which will make the source code for my CSS much cleaner. Then whenever a dynamic capability like form submissions is needed, there is still a backend scripting language ready to go.
Neat Tips and Tricks
CDN Failsafe
Since I was working with so many mainstream web libraries like Bootstrap and JQuery, it only made sense to use the CDN versions for potentially faster load times. However, that means if those serves go down due to a DDoS attack or widespread system failure, my website would lose most functionality and appearance.
Thus, I wrote some neat JavaScript failsafe scripts that would switch the site to copies of the libraries that are stored on the primary server instead:
if(typeof(window.jQuery) === 'undefined') {
document.write(unescape('%3Cscript src="/resources/jquery-3.6.0/jquery-3.6.0.min.js"%3E%3C/script%3E'));
}
This checks for the existence of an object called window.jQuery and in the case which it is undefined (meaning the CDN failed to load), it writes a script to load from the local version instead.
Forcing Jekyll to Output PHP files
I was really trying to create a much more elegant solution to this, but I ended up having to do a quick and dirty method of just forcing it to use a “custom” extension when writing the files. So I could specify the desired custom extension in the file that was being converted. It failed to change the inner working of Jekyll so I then had to workaround the fact that Jekyll still thought the file extension was HTML when referencing it.
The following is a snippet of a custom plugin I wrote to override the destination function with the desired custom extension.
module Jekyll
class Document
def destination(base_directory)
dest = site.in_dest_dir(base_directory)
path = site.in_dest_dir(dest, URL.unescape_path(url))
if url.end_with? "/"
path = File.join(path, "index.html")
else
path << output_ext unless path.end_with? output_ext
end
# replace extension with custom_ext
path.sub! output_ext, data['custom_ext'] if data['custom_ext']
path
end
end
end
The failures here are not really a major issue with Jekyll, and theoretically there is a way for a Jekyll package to fully enable custom extensions in the way that I wanted. Perhaps this may be a project for the future.
AJAX Form Requests
One of biggest ways to make a form look nice on a website is to have smart input validation and form feedback. Using AJAX to intercept the form submissions, I was able to add things like an upload percentage bar and a visually appealing success response.
form.submit(function (e) {
e.preventDefault();
form_data = new FormData(this);
form_data.append("file", $('#inputFile')[0].files[0]);
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
bar.parent().fadeIn();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
percentComplete = parseInt(percentComplete * 100);
bar.css('width', percentComplete + '%');
if (percentComplete === 100) {}
}
}, false);
return xhr;
},
url: form.attr('action'),
type: form.attr('method'),
data: form_data,
contentType: false,
processData: false,
success: done_func,
error: fail_func
});
});
Dropdown Navbar on Hover
One of the more hidden features that few people notice is the ability for dropdown bars to activate on hover rather than Bootstrap’s default design which requires you to tap them. This feature also only applies to desktop devices because with a touch screen, the hover concept is ruined. I accomplished this feature using a custom JavaScript event listener:
$(window).on("load resize", function() {
if (this.matchMedia("(min-width: 992px)").matches) { // only apply to desktop devices
$dropdown.hover(
function() {
if (! $(this).hasClass('show')) { // prevent it from toggling OFF when mouse arrives
$(this).find($dropdownToggle).dropdown('toggle');
}
},
function() { // mouse leaves area
if ($(this).hasClass('show')) { // prevent it from toggling ON when mouse leaves
$(this).find($dropdownToggle).dropdown('toggle');
}
}
);
} else {
$dropdown.off("mouseenter mouseleave");
}
});
This used the default Bootstrap JavaScript functions for activating dropdowns. Which was essential because I also added a smooth sliding transition that works on both desktop and mobile:
$dropdown.on('show.bs.dropdown', function() {
$(this).find($dropdownMenu).first().stop(true, true).slideDown();
});
// Add slideUp animation to Bootstrap dropdown when collapsing.
$dropdown.on('hide.bs.dropdown', function() {
$(this).find($dropdownMenu).first().stop(true, true).delay(50).slideUp();
});
Take careful note of the delay(50) because without the short pause, the animations can get stuck in a loop of frantic opening and closing.
Docker - Incredibly Powerful Tech
The most useful piece of tech that I used over the course of this entire project was undoubtedly Docker. This incredibly simplified the process of creating and manipulating VMs as containers and made a fully operational Apache web server run locally on my desktop while allowing my web browsers to connect to the “website” via a localhost port.
The technology is most definitely an underused piece of software for all web development as one of the most annoying and difficult problems of development as an industry, is how to transition from development to production when the two OS environments can be vastly different. I expect to use a lot more Docker in my future projects.
Wrap-Up
While I didn’t spend the summer as an intern at a software company, I certainly didn’t waste too much time. Taking a list of requests and features for a website and turning them into a reality was a very rewarding experience and I hope to be able to take on more big projects in the future.