Netlify & Next.js | CSS-Tricks
Strategy

Netlify & Next.js | CSS-Tricks


Cassidy Williams has been doing a Blogvent (blogging every day for a month) over on the Netlify Blog. A lot of the blog posts are about Next.js. There is a lot to like about Next.js. I just pulled one of Cassidy’s starters for fun. It’s very nice that it has React Fast-Refresh built-in. I like how on any given “Page” you can import and use a <Head> to control stuff that would be in a <head>. This was my first tiny little play with Next so, excuse my basicness.

But the most compelling thing about Next.js, to me, is how easily it supports the entire rendering spectrum. It encourages you to do static-file rendering by default (smart), then if you need to do server-side rendering (SSR), you just update any given Page component to have this:

export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

The assumption is that you’re doing SSR because you need to hit a server for data in order to render the page, but would prefer to do that server-side so that the page can render quickly and without JavaScript if needed (great for SEO). That assumes a Node server is sitting there ready to do that work. On Netlify, that means a function (Node Lambda), but you barely even have to think about it, because you just put this in your netlify.toml file:

[[plugins]]
  package = "@netlify/plugin-nextjs"

Now you’ve got static where you need it, server-rendered where you need it, but you aren’t giving up on client-side rendering either, which is nice and fast after the site is all booted up. I think it shoots some JSON around or something, framework magic.

I set up a quick SSR route off my homepage to have a play, and I can clearly see that both my homepage (static) and /cool route (SSR) both return static HTML on load.

I even had to prettify this source, as you HTML minification out of the box

I admit I like working in React, and Next.js is a darn nice framework to do it with because of the balance of simplicity and power. It’s great it runs on Netlify so easily.



Source link

Not Much | CSS-Tricks
Strategy

Not Much | CSS-Tricks


What’s one thing I learned about building websites this year? Not all that much.

This year, unlike most previous years, I didn’t explore a lot of new technologies. For obvious reasons, it’s been a difficult year to be as engaged in the hot new topics and to spend time playing around with new things. So, for the most part, I’ve tried to keep calm and carry on.

That said, I did try a couple of things that were new to me. I built my first React application (after stubbornly holding out for so long). This was a bit of a struggle for me, coming from using a fully fledged framework, like Angular, to a strictly UI library, like React, and I learned a lot about the difference between libraries and frameworks in the process.

I also trialled Tailwind to see what a radically different way of writing CSS (or in this case, not writing CSS) could be like. This was a really fun trial and although I’ve gone back to my good-ole-SCSS, I have taken with me the idea of utility CSS classes. For example, I now create utility classes for things like aligning text, so the line text-align: center; is only written once in my CSS file.

But ultimately, I’ve found that my way of building websites hasn’t changed all that much this year. And more importantly, it didn’t have to.



Source link

messy inline comments
Strategy

6 Tips to Help You Write Cleaner Code in Node.js


Node.js is one of the most popular lightweight JavaScript frameworks that allow you to create powerful server-side and client-side applications. As with any other language, developers must write clean Node.js code to get the most out of this application runtime environment.

Otherwise, your team will spend too much time juggling through blocks of unreadable code with unclear variable definitions, messy syntax, and duplicate functions. This can cause too much pain, especially when a developer is tasked with maintaining someone else’s code while pushing to meet deadlines.

So, how can development teams write readable Node.js code that’s easy to understand, change, and extend? The following six tips will help developers, including those with minimum experience, produce this kind of code.

Check Your Naming Convention

A great starting point for writing clean and consistent Node.js code is checking how you name your JavaScript components, including classes, functions, constants, and variables. The best approach here would be following a style guide whose coding standards and guidelines are accepted in the global Java script community.

When naming functions and variables, use the lowerCamelCase. Their names should be descriptive enough, but not too long. Uncommon abbreviations and single-character variable names should be avoided. 

For class names, use the UpperCamelCase with the first letter capitalized, as shown below.

When naming constants, you can use uppercase for the entire word, as shown below:

For constants and variables with more than one name in the declaration, we use an underscore to separate the names.

Modularize Your Functions

An easy way to declutter your code is creating a function for every single task. If a function does more than its name implies, you should consider splitting the functionality and creating another function.

Maintaining smaller functional chunks makes your code look neat. Additionally, you can have the maininit()function that holds the application structure. This makes it easier to re-use functions without duplicating code.

Functions that perform a single task are also easier to debug or modify since there’s no need to scan through the codebase searching for dependencies or identifying what block of code executes a particular action.

Proper Commenting

Comments are a valuable addition to your Node.js code because they clarify difficult segments and explain high-level mechanisms in your code. They describe the functionality of a particular block of code, thereby giving other programmers a better insight into your code.

When commenting, refrain from adding unnecessary comments that restate trivial things. For instance, the inline comments in the code snippet below are unnecessary:

messy inline comments

Source

The above example looks completely unprofessional since the commented code is left lying in the codebase. Instead, you can use a declarative head comment with a short explanation of what the does. If needed, you can list the arguments, return values, and exceptions.

The version below looks much better and explains what the method does without distracting the programmer from the code.

header comments example

Source

A rule of thumb when writing comments is to state why you’re doing something and leaving the code to answer the how part. 

Understand the Context When Debugging

Debugging is inevitable when it comes to software development, and it’s not always easy. When writing Node.js code, you often have several options. The console.log, for instance, is an often-used tool that provides a simple and quick way of debugging your errors.

However, if you do not clean up the logs, your console might end up in a mess. Additionally, you might want to implement production debugging. The console will not give you sufficient data to understand the impact of an error in your live app. 

This does not mean that you should ditch the console, but rather use a tool that provides all debug data needed to understand the context of your errors.

Using a debugging tool like Raygun, Rookout, or LogRocket gives you a deeper insight into the errors. Let’s look at Rookout, for example. It fetches on-demand debug data from the underlying Node.js application, whether in a development or production environment.

Debugging a node application deployed with Jenkins

Debugging a node application deployed with Jenkins.

With the Rookout debugger, you can set non-breaking breakpoints, view the stack trace, record console logs, and send this debugging data to a logging platform of your choice. 

This allows you to easily find errors in your code and understand them for quicker resolution.

Destructuring

Destructuring assignments is an awesome technique that allows you to break complex data structures like objects or arrays into simpler parts. It provides a convenient way of accessing array items and object properties.

Consider the example below where you want to access the first four items in an array as follows:

When we apply destructuring as illustrated below, the equivalent code looks more readable and concise:

Besides this, destructing provides a convenient way of swapping variables and performing a wide range of immutable operations. 

You can learn more about destructuring assignments and some practical applications when coding in this guide by Mozilla.

Do Not Repeat Yourself

The last tip involves the renowned DRY principle of software development, which aims to eliminate redundancy in software patterns by using data normalization and abstraction. As stated by Dave Thomas and Andrew Hunt in the book The Pragmatic Programmer,

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

This means that you shouldn’t duplicate knowledge or intent by expressing the same concept in different places or different ways. In general, if you find yourself writing the same block of code multiple times to achieve a particular functionality, it’s always a good idea to consolidate the code. 

Similarly, if your system uses a hard-coded value multiple times, consider making it a constant. By removing duplicate code, you make it cleaner and easier to maintain.

An important thing to remember that this principle applies to more than just your code. You should adhere to it when working on your database schema, writing documentation, test plans, APIs, or any other component of your system.

Conclusion

All members of a development team, regardless of their role, need to remember that clean code matters. It lies at the heart of reducing technical debt and delivering software products on time. 

Clean and understandable code also helps you build a solid foundation for easily maintainable applications. Following the above guidelines will help you keep your Node.js code clean and scalable.



Source link

Give Users Control: The Media Session API
Strategy

Give Users Control: The Media Session API


Here’s a scenario. You start a banging Kendrick Lamar track in one of your many open browser tabs. You’re loving it, but someone walks into your space and you need to pause it. Which tab is it? Browsers try to help with that a little bit. You can probably mute the entire system audio. But wouldn’t it be nice to actually have control over the audio playback without necessarily needing to find your way back to that tab?

The Media Session API makes this possible. It gives media playback access to the user outside of the browser tab where it is playing. If implemented, it will be available in various places on the device, including:

  • the notifications area on many mobile devices,
  • on other wearables, and
  • the media hub area of many desktop devices.

In addition, the Media Session API allows us to control media playback with media keys and voice assistants like Siri, Google Assistant, Bixby, or Alexa.

The Media Session API

The Media Session API mainly consists of the two following interfaces:

  • MediaMetadata
  • MediaSession

The MediaMetadata interface is what provides data about the playing media. It is responsible for letting us know the media’s title, album, artwork and artist (which is Kendrick Lamar in this example). The MediaSession interface is what is responsible for the media playback functionality.

Before we take a deep dive into the topic, we would have to take note of feature detection. It is good practice to check if a browser supports a feature before implementing it. To check if a browser supports the Media Session API, we would have to include the following in our JavaScript file:

if ('mediaSession' in navigator) {
  // Our media session api that lets us seek to the beginning of Kendrick Lamar's &quot;Alright&quot;
}

The MediaMetadata interface

The constructor, MediaMetadata.MediaMetadata() creates a new MediaMetadata object. After creating it, we can add the following properties:

  • MediaMetadata.title sets or gets the title of the media playing.
  • MediaMetadata.artist sets or gets the name of the artist or group of the media playing.
  • MediaMetadata.album sets or gets the name of the album containing the media playing.
  • MediaMetadata.artwork sets or gets the array of images related with the media playing.

The value of the artwork property of the MediaMetadata object is an array of MediaImage objects. A MediaImage object contains details describing an image associated with the media. The objects have the three following properties:

  • src: the URL of the image
  • sizes: indicates the size of the image so one image does not have to be scaled
  • type: the MIME type of the image

Let’s create a MediaMetadata object for Kendrick Lamar’s “Alright” off his To Pimp a Butterfly album.

if ('mediaSession' in navigator) {
  navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Alright',
    artist: 'Kendrick Lamar',
    album: 'To Pimp A Butterfly',
    artwork: [
      { src: 'https://mytechnicalarticle/kendrick-lamar/to-pimp-a-butterfly/alright/96x96', sizes: '96x96', type: 'image/png' },
      { src: 'https://mytechnicalarticle/kendrick-lamar/to-pimp-a-butterfly/alright/128x128', sizes: '128x128', type: 'image/png' },
      // More sizes, like 192x192, 256x256, 384x384, and 512x512
    ]
  });
}

The MediaSession interface

As stated earlier, this is what lets the user control the playback of the media. We can perform the following actions on the playing media through this interface:

  • play: play the media
  • pause: pause the media
  • previoustrack: switch to the previous track
  • nexttrack: switch to the next track
  • seekbackward: seek backward from the current position, by a few seconds
  • seekforward: seek forward from the current position, by a few seconds
  • seekto: seek to a specified time from the current position
  • stop: stop media playback
  • skipad: skip past the advertisement playing, if any

The MediaSessionAction enumerated type makes these actions available as string types. To support any of these actions, we have to use the MediaSession’s setActionHandler() method to define a handler for that action. The method takes the action, and a callback that is called when the user invokes the action. Let us take a not-too-deep dive to understand it better.

To set handlers for the play and pause actions, we include the following in our JavaScript file:

let alright = new HTMLAudioElement();

if ('mediaSession' in navigator) {
  navigator.mediaSession.setActionHandler('play', () => {
    alright.play();
  });
  navigator.mediaSession.setActionHandler('pause', () => {
    alright.pause();
  });
}

Here we set the track to play when the user plays it and pause when the user pauses it through the media interface.

For the previoustrack and nexttrack actions, we include the following:

let u = new HTMLAudioElement();
let forSaleInterlude = new HTMLAudioElement();

if ('mediaSession' in navigator) {
  navigator.mediaSession.setActionHandler('previoustrack', () => {
    u.play();
  });
  navigator.mediaSession.setActionHandler('nexttrack', () => {
    forSaleInterlude.play();
  });
}

This might not completely be self-explanatory if you are not much of a Kendrick Lamar fan but hopefully, you get the gist. When the user wants to play the previous track, we set the previous track to play. When it is the next track, it is the next track.

To implement the seekbackward and seekforward actions, we include the following:

if ('mediaSession' in navigator) {
  navigator.mediaSession.setActionHandler('seekbackward', (details) => {
    alright.currentTime = alright.currentTime - (details.seekOffset || 10);
  });
  navigator.mediaSession.setActionHandler('seekforward', (details) => {
    alright.currentTime = alright.currentTime + (details.seekOffset || 10);
  });
}

Given that I don’t consider any of this self-explanatory, I would like to give a concise explanation about the seekbackward and seekforward actions. The handlers for both actions, seekbackward and seekforward, are fired, as their names imply, when the user wants to seek backward or forward by a few number of seconds. The MediaSessionActionDetails dictionary provides us the “few number of seconds” in a property, seekOffset. However, the seekOffset property is not always present because not all user agents act the same way. When it is not present, we should set the track to seek backward or forward by a “few number of seconds” that makes sense to us. Hence, we use 10 seconds because it is quite a few. In a nutshell, we set the track to seek by seekOffset seconds if it is provided. If it is not provided, we seek by 10 seconds.

To add the seekto functionality to our Media Session API, we include the following snippet:

if ('mediaSession' in navigator) {
  navigator.mediaSession.setActionHandler('seekto', (details) => {
    if (details.fastSeek && 'fastSeek' in alright) {
      alright.fastSeek(details.seekTime);
      return;
    }
    alright.currentTime = details.seekTime;
  });
}

Here, the MediaSessionActionDetails dictionary provides the fastSeek and seekTime properties. fastSeek is basically seek performed rapidly (like fast-forwarding or rewinding) while seekTime is the time the track should seek to. While fastSeek is an optional property, the MediaSessionActionDetails dictionary always provides the seekTime property for the seekto action handler. So fundamentally, we set the track to fastSeek to the seekTime when the property is available and the user fast seeks, while we just set it to the seekTime when the user just seeks to a specified time.

Although I wouldn’t know why one would want to stop a Kendrick song, it won’t hurt to describe the stop action handler of the MediaSession interface:

if ('mediaSession' in navigator) {
  navigator.mediaSession.setActionHandler('stop', () => {
    alright.pause();
    alright.currentTime = 0;
  });
} 

The user invokes the skipad (as in, “skip ad” rather than “ski pad”) action handler when an advertisement is playing and they want to skip it so they can continue listening to Kendrick Lamar’s “Alright track. If I’m being honest, the complete details of the skipad action handler is out of the scope of my “Media Session API” understanding. Hence, you should probably look that up on your own after reading this article, if you actually want to implement it.

Wrapping up

We should take note of something. Whenever the user plays the track, seeks, or changes the playback rate, we are supposed to update the position state on the interface provided by the Media Session API. What we use to implement this is the setPositionState() method of the mediaSession object, as in the following:

if ('mediaSession' in navigator) {
  navigator.mediaSession.setPositionState({
    duration: alright.duration,
    playbackRate: alright.playbackRate,
    position: alright.currentTime
  });
}

In addition, I would like to remind you that not all browsers of the users would support all the actions. Therefore, it is recommended to set the action handlers in a try...catch block, as in the following:

const actionsAndHandlers = [
  ['play', () => { /*...*/ }],
  ['pause', () => { /*...*/ }],
  ['previoustrack', () => { /*...*/ }],
  ['nexttrack', () => { /*...*/ }],
  ['seekbackward', (details) => { /*...*/ }],
  ['seekforward', (details) => { /*...*/ }],
  ['seekto', (details) => { /*...*/ }],
  ['stop', () => { /*...*/ }]
]
 
for (const [action, handler] of actionsAndHandlers) {
  try {
    navigator.mediaSession.setActionHandler(action, handler);
  } catch (error) {
    console.log(`The media session action, ${action}, is not supported`);
  }
}

Putting everything we have done, we would have the following:

let alright = new HTMLAudioElement();
let u = new HTMLAudioElement();
let forSaleInterlude = new HTMLAudioElement();

const updatePositionState = () => {
  navigator.mediaSession.setPositionState({
    duration: alright.duration,
    playbackRate: alright.playbackRate,
    position: alright.currentTime
  });
}
 
const actionsAndHandlers = [
  ['play', () => {
    alright.play();
    updatePositionState();
  }],
  ['pause', () => { alright.pause(); }],
  ['previoustrack', () => { u.play(); }],
  ['nexttrack', () => { forSaleInterlude.play(); }],
  ['seekbackward', (details) => {
    alright.currentTime = alright.currentTime - (details.seekOffset || 10);
    updatePositionState();
  }],
  ['seekforward', (details) => {
    alright.currentTime = alright.currentTime + (details.seekOffset || 10);
    updatePositionState();
  }],
  ['seekto', (details) => {
    if (details.fastSeek && 'fastSeek' in alright) {
      alright.fastSeek(details.seekTime);
      updatePositionState();
      return;
    }
    alright.currentTime = details.seekTime;
    updatePositionState();
  }],
  ['stop', () => {
    alright.pause();
    alright.currentTime = 0;
  }],
]
 
if ( 'mediaSession' in navigator ) {
  navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Alright',
    artist: 'Kendrick Lamar',
    album: 'To Pimp A Butterfly',
    artwork: [
      { src: 'https://mytechnicalarticle/kendrick-lamar/to-pimp-a-butterfly/alright/96x96', sizes: '96x96', type: 'image/png' },
      { src: 'https://mytechnicalarticle/kendrick-lamar/to-pimp-a-butterfly/alright/128x128', sizes: '128x128', type: 'image/png' },
      // More sizes, like 192x192, 256x256, 384x384, and 512x512
    ]
  });
 
  for (const [action, handler] of actionsAndHandlers) {
    try {
      navigator.mediaSession.setActionHandler(action, handler);
    } catch (error) {
      console.log(`The media session action, ${action}, is not supported`);
    }
  }
}

Here’s a demo of the API:

I implemented six of the actions. Feel free to try the rest during your leisure.

If you view the Pen on your mobile device, notice how it appears on your notification area.

If your smart watch is paired to your device, take a sneak peek at it.

If you view the Pen on Chrome on desktop, navigate to the media hub and play with the media buttons there. The demo even has multiple tracks, so you experiment moving forward/back through tracks.

If you made it this far (or not), thanks for reading and please, on the next app you create with media functionality, implement this API.



Source link

r/webdev - Infinite loop, React!
Strategy

Infinite loop, React! : webdev


it seems like the useEffect is causing a infinite loop, to be more precise its setComments which cause it… i tried commenting out setComments and console logging the response i get from firebase and it only logs it once, so im pretty sure its the setComments thats causing it and i cant seem to find out why..any help will be much appreciated

I wouldve posted this on r/reactjs but it dosent allow images

r/webdev - Infinite loop, React!



Source link