f w h

Install Node with Sudo Access

Some distributions of Linux, particularly Raspbian, don’t have recent versions of Node in their repositories, and there’s often a mismatch in versions between Node and npm. To add to the problem, some version managers also don’t support ARM architectures. While the excellent n does support ARM, it doesn’t install Node or npm in a way that is accessible via sudo.

In general, you shouldn’t be using Node or npm with sudo, but getting the permissions right for that situation can be a huge pain, and sometimes you just need a Raspberry Pi with a hastily set up Node server to run some local projects. Getting sudo to work with Node and npm in these instances can also be a huge pain, and the vast array of different possible answers can be daunting to sift through.

The Fix

For quick, one-off setups, the following will most likely work, and only takes a few minutes – without having to worry about sudo having access to it:


~ $ sudo apt-get install -y nodejs npm
~ $ sudo npm i -g n npm@lts
~ $ sudo n lts

The first step installs the Node and npm versions available on your distro’s repository. The second line will install the latest version of npm. NOTE: you may see a warning about a mismatch in versions while this step is running. It is safe to ignore. The third step uses n to install the lts version of Node.

That’s it! Test your Node and npm with sudo by running ~ $ sudo node -v and ~ $ sudo npm -v. Both should output their version numbers. This also works to install Node and npm for the Windows Subsystem for Linux.

ProgressBar.js for React with ES6

If you’re not aware, ProgressBar.js is a great way to create beautiful, animated progress bars with JavaScript. The library outputs and automatically animates your progress bar with SVG.

There are a couple of React implementations out there, including one by the creator of the original library. However, they are rather limited in the options they let you set. So, I created react-es6-progressbar.js. The package exposes a set of React components to which you can pass the library’s full set of options.

Get the library here:

NPMnpm install --save react-es6-progressbar.js

GitHub

Populating Multiple Fields and Levels with Mongoose

Mongoose, the popular MongoDB library for NodeJS is incredibly robust and relatively easy to pick up. Its documentation, however leaves a little to be desired.

To attain functionality similar to join functionality present in relational databases, Mongoose provides a method called populate(). Used in conjunction with the ref schema property, data can be pulled in from other documents in place of an id. The process is fairly straightforward. However, what Automattic’s documentation doesn’t explain is how to populate multiple paths, and the documentation for multiple levels leaves much to be desired.

The documentation does point out that chaining multiple populate functions won’t work. How, then can this be done? Multiple paths may be populated by creating a space-separated list. Note the emphasis, because comma-separated lists do not work. By way of example:


// Doesn't work - will only populate 'friends'
Users.findOne({/* query here */})
.populate('address')
.populate('friends');

// Works
Users.findOne({/* query here */})
.populate('address friends');

Now, what if we wanted to populate the friends’ addresses? As explained in the docs, you would nest another populate by passing an object to the method, and adding another populate as a property. That was pretty confusing to me, but here’s what it means:


// This time, we're not passing a string, but an object to populate()
Users.findOne({/* query here */})
.populate({
  path: 'address friends', // The string we passed in before
  populate: {
    path: 'address' // This will populate the friends' addresses
  }
});

The first level of items to populate is passed in a key called path. The next level items to populate are passed as a new populate object. This can be continued on down the line as necessary. Each populate will have a path key/value pair, and if there’s another level of things to populate, those are passed in a populate key/value pair.

Stop Setting Breakpoints

Ever since Ethan Marcotte’s amazing article on ALA way back in 2010, web developers have been leveraging media queries to ensure frontend designs are usable across devices. In general, that means setting breakpoints with new styles for each device size. This new idea lurched web interface design forward, and the idea of responsive web design has become not only ubitquitous, but standard. Most web design/development courses include the concept as part of their curriculum.

What web developer hasn’t played with the width of their browser window, resizing until it breaks, and then setting a breakpoint at that width. Lather, rinse, repeat until the design works cross-browser. I am a firm believer in the concept that if it works, it’s not wrong. However, I think there’s a better way.

Viewport Units

Support for viewport units in CSS is rather high. The vh and vw units are almost universally usable. I would say for almost all projects, they’re safe to use. Support for vmax and vmin isn’t quite as good, and that’s the only reason I even discuss continued use of media queries at all in this article. Put another way, once vmin and vmax support widens, media queries can become almost unnecessary.

The Only Media Query You’ll Ever Need

I present to you the only media query you’ll ever need: orientation. The team up of viewport units and the orientation query can’t solve every design problem, but it can come pretty close.

Consider this scenario: You are working on a design in-browser. It has three blocks arranged horizontally. In landscape, which is the orientation most desktop users are going to be using, The blocks fit well, and their content is easily readable. However, below 600px width, the content overflows the box, causing the last box to drop to the next line. Normally in a situation like this, because the font-size is set using em, rem or some other either relative or static sizing, you would likely set a breakpoint at 600px width, then adjust the font size.

See the Pen wpjdGN by Ronald Roe (@ronaldroe) on CodePen.

This is where viewport units come in. Instead of using the relative or static units like normal, set the font-size based on the width of the viewport. For most paragraph text, I find 2 – 3vw works well, but use whatever works for your design.

With the vw units set, the content will no longer overflow the box as the size shrinks. In most cases, the breakpoint becomes unnecessary. Next, in our imaginary scenario, we try the design in portrait orientation on a phone and find that the boxes are small and the text is too small to read. What happened? Since the text size is based on the viewport’s width, and the width is much smaller than the height, the text looks tiny.

That’s where our orientation media query comes in. Setting @media (orientation: portrait) will trigger when the height of the viewport is greater than the width. Now, inside the query, reset the font size to use vh units. In general, using the same number as the vw value will maintain a similar if not consistent look. Additionally, most scenarios with floated boxes will look better if the float is removed (set to none) in portrait.

See the Pen baMWRP by Ronald Roe (@ronaldroe) on CodePen.

There will be cases where breakpoints are still necessary. However, this method should reduce the need considerably. I’ve used this method in all of my current and some of my recent past projects, and am having a lot of success with it. For my current project, a frontend for Shape Fitness, You will not find a single breakpoint in the CSS.

Let me know on Twitter what you think.

Viewport Units on SVG

A quick note, learned from experience: viewport units (vw, vh, vmin, vmax) do not work as height or width attributes in Firefox. I tested the latest (as of this post’s pub date) versions of: Chrome, Firefox, Edge and IE11. It seems to work perfectly in all of those except Firefox.

What do I mean? Take a look:


<svg height="10vh" width="10vw">
	<!-- SVG innards -->
</svg>

This works with no issue in most browsers, but will be ignored in Firefox. Why? I’m guessing it’s Firefox sticking closely to the spec, as Mozilla doesn’t list them as an available option in their MDN document on SVG sizes, and neither does the W3C spec for the length data-type on SVGs.

Fret not, however, because I have a fix for it.

Viewport units are simply a percentage of the viewport’s, or as the CSS spec states, ‘initial containing block’ size. Thus, if your viewport is 1000px wide, 1vw is equivalent to 10px. The only problem is that it will need to adjust automatically when the viewport changes.

The script below sets the viewport units aside in a data-* attribute, then uses them to calculate a pixel value for them:


// My viewport script from a previous post
function viewport(){

	let w = window.innerWidth;
	let h = window.innerHeight;
	
	let orientation = w > h ? 'landscape' : 'portrait';
	
	let output = {
		w: w,
		h: h,
		orientation: orientation
	};

	return output;

}

// Converts the viewport units to a pixel-based length
function viewport2px(size){

	let int = parseInt(size, 10); // Grabs the size and extracts only the number
	let output;
	
	size.includes('h') ? output = ((int / 100) * viewport().h) + 'px' :  output = ((int / 100) * viewport().w) + 'px';
	
	return output;

}

// Sets the new units according to their current size
function sizeSVGs(svgsIn){

	// If a NodeList object is not provided, just select all of them
	let svgs = svgsIn || document.querySelectorAll('svg');
	
	Array.from(svgs).forEach(function(svg){
		// Check the height for viewport units (doesn't check for vmin/vmax - easy enough to add),
		// Sets those units aside for later use,
		// Sets the new px size
		if(svg.getAttribute('height').includes('vw') || svg.getAttribute('height').includes('vh')){
			svg.setAttribute('data-height', svg.getAttribute('height'));
			svg.setAttribute('height', viewport2px(svg.getAttribute('height')));
		}
		// Does the same thing for width
		if(svg.getAttribute('width').includes('vw') || svg.getAttribute('width').includes('vh')){
			svg.setAttribute('data-width', svg.getAttribute('width'));
			svg.setAttribute('width', viewport2px(svg.getAttribute('width')));
		}
	});

}

// Fire on load
window.addEventListener('load', function(){

	sizeSVGs();

});

But what about the resize? Well, remember how we set aside the initial values in a data-*attribute? We just need to grab that value again and recalculate any time a resize event fires.


window.addEventListener('resize', function(){
	Array.from(svgs).forEach(function(svg){
		if(svg.hasAttribute('data-height')) svg.setAttribute('height', vp2px(svg.getAttribute('data-height')));
		if(svg.getAttribute('data-width')) svg.setAttribute('width', vp2px(svg.getAttribute('data-width')));
	});
});

Caveat: This script uses the Array.from()method to convert the SVG NodeList into an array for iteration. No version of IE supports this method. If IE support is required, MDN has a great drop-in polyfill.

Next Page »