Post image
Strategy

Simple Question about React.js Project : webdev


Hello all, I am still a newb when it comes to React and honestly web dev in general. I have learned a ton from everyone on this subreddit and I really appreciate it.

I am working on a React project, specifically a project portfolio website.

My question is, how can I make an array of descriptive words display a different word in the array every three seconds?

This is my code that currently works now:

Post image

This is my current array, as you can see it just shows one word (the one that is highlighted).

Post image

And this is my code that shows the array being passed into the display area.



Source link

Spitzer composite image of Elephant Trunk Nebula
Strategy

Space Photos of the Week: An Ode to Infrared


On January 30, NASA will bid farewell to its Spitzer Space Telescope. The size of a schoolbus, Spitzer is one of NASA’s most beloved and hardworking telescopes: It launched on August 25, 2003, and its mission has been to study the universe using infrared light. (Space is cold, so detecting even slight variations in heat can be tricky, which is why we’ve needed Spitzer’s specialty skills.) In the last sixteen years Spitzer has revealed the universe to us, including helping scientists understand how galaxies form by revealing cold and impossible to see clumps of gas. It has also helped astronomers better understand star formation because it can see through opaque clouds to reveal activity hidden within them. Later in its mission, Spitzer helped detect the exoplanets around the Trappist 1 star system.

Sadly the mission is now coming to an end. The orbiting telescope has been low on coolant fuel for years, and now it is trailing further and further away from the Earth, making operations more difficult. Still, after nearly fourteen years over its planned mission lifetime, it’s done pretty well for itself. This week we will celebrate its legacy with just a few of the beautiful photos it took during its time in space.

Whenever a telescope goes online for the first time it collects what astronomers call “first light.” This is Spitzer’s first photo, depicting the Elephant’s Trunk Nebula. This photo reveals a large stellar nursery which we can see shining bright at the left of the frame. If we looked at this nebula with our eyes or with Hubble, it would look like nothing, like you were staring into the blackness of space, but Spitzer’s infrared capabilities revealed a whole host of protostars, or baby stars that have just been formed and are seen here glowing brightly.Photograph: NASA/JPL-Caltech/W. Reach
In this photo, the telescope peered through what is called the Rho Ophiuci dark cloud. Composed mostly of molecular hydrogen, this is the stuff that turns into stars. The colors in this stunning photo indicate how hot the stars are in their various stages of growth. Some glow hotter and are very young and surrounded by thick clumps of dust, while the brighter blue stars are older and colder.Photograph: NASA/JPL-Caltech/Harvard-Smithsonian CfA
Spitzer didn’t always gaze out into the distant universe, sometimes it looked closer to home: This is a dizzying spectacle of stars at the center of our Milky Way Galaxy. (Our solar system lies around 26,000 light years from the center of the galaxy, and we orbit in one of the outer arms). Without Spitzer this image would be impossible: The thick dust and gas that exists between us and the center of the galaxy blocks visible light. The bright spot at the center is the core of the galaxy, dense with billions and billions of stars, and near the center is our very own supermassive black hole.Photograph: NASA/JPL-Caltech
This image of M82, also known as the cigar galaxy, is 12 million light years away. This photo is a collaboration between Spitzer and SOFIA, another NASA infrared telescope. The waves are magnetic field lines at the center of M82, while the red is hydrogen gas, the yellow is dust, and the gray is visible starlight.Photograph: NASA
This is not Mordor but actually the Perseus molecular cloud, also known as a stellar nursery. Regions like this contain the right conditions to form molecules, especially molecular hydrogen, which is the fuel for new stars. At only 500 light years across, this inferno is a dense collection of dust and gas. Without Spitzer, Perseus would be invisible to us, but infrared reveals these violent beginnings.Photograph: NASA/JPL-Caltech
This legendary spacecraft will be missed but its contributions to astronomy will last for many decades to come. Because of its mission to search out the delicate heat signatures in the cosmos, the spacecraft operates at an astonishingly cold -400 degrees Fahrenheit, allowing the three instruments on board to unveil a new layer of the universe.Photograph: NASA

See more of what Spitzer saw here.


More Great WIRED Stories



Source link

The header of the An Event Apart website with slanted images of speakers, and captions beneath.
Strategy

Flexible Captioned Slanted Images ◆ 24 ways


We have a lot of new layout tools at our disposal these days—flexbox is finally stable and interoperable, and Grid very much the same, with both technologies having well over 90% support coverage. In that light, we might think there’s no place for old tricks like negative margins, but I recently discovered otherwise.

Over at An Event Apart, we’ve been updating some of our landing pages, and our designer thought it would be interesting to have slanted images of speakers at the tops of pages. The end result looks like this.

The header of the An Event Apart website with slanted images of speakers, and captions beneath.

The interesting part is the images. I wanted to set up a structure like the following, so that it will be easy to change speakers from time to time while preserving accessible content structures:

<div id="page-top">
  <ul class="monoliths">
    <li>
      <a href="https://aneventapart.com/speakers/rachel-andrew"> 
        <img src="/img/rachel-andrew.jpg" alt=""> 
        <div> 
          <strong>Rachel Andrew</strong> CSS Grid 
        </div> 
      </a>
    </li>
    <li>
      <a href="https://aneventapart.com/speakers/derek-featherstone"> 
        <img src="/img/derek-featherstone.jpg" alt=""> 
        <div> 
          <strong>Derek Featherstone</strong> Accessibility 
        </div> 
      </a>
    </li>
    <li>
      …
    </li>
    <li>
      …
    </li>
  </ul>
</div>

The id value for the div is straightforward enough, and I called the ul element monoliths because it reminded me of the memorial monoliths at the entrance to EPCOT in Florida. I’m also taking advantage of the now-ubiquitous ability to wrap multiple elements, including block elements, in a hyperlink. That way I can shove the image and text structures in there, and make the entire image and text below it one link.

Structure is easy, though. Can we make that layout fully responsive? I wondered. Yes we can. Here’s the target layout, stripped of the navbar and promo copy.

The header of the An Event Apart website without navigation or promo copy.

So let’s start from the beginning. The div gets some color and text styling, and the monoliths list is set to flex. The images are in a single line, after all, and I want them to be flexible for responsive reasons, so flexbox is 100% the right tool for this particular job.

#page-top { 
  background: #000; 
  color: #FFF; 
  line-height: 1; 
} 
#page-top .monoliths { 
  display: flex; 
  padding-bottom: 1em; 
  overflow: hidden; 
}

I also figured, let’s give the images a simple basis for sizing, and set up the hyperlink while we’re at it.

#page-top .monoliths li { 
  width: 25%; 
} 
#page-top .monoliths a { 
  color: inherit; 
  text-decoration: inherit; 
  display: block; 
  padding: 1px; 
}

So now the list items are 25% wide—I can say that because I know there will be four of them—and the links pick up the foreground color from their parent element. They’re also set to generate a block box.

At this point, I could concentrate on the images. They need to be as wide as their parent element, but no wider, and also match height. While I was at it, I figured I’d create a little bit of space above and below the captioning text, and make the strong elements containing speakers’ names generate a block box.

#page-top .monoliths img { 
  display: block; 
  height: 33rem; 
  width: 100%; 
} 
#page-top .monoliths div { 
  padding: 0.5em 0; 
} 
#page-top .monoliths strong { 
  display: block; 
  font-weight: 900; 
}
The header of the An Event Apart website with the speaker photos appearing to be stretched vertically.

It looks like the speakers were all cast into the Phantom Zone or something, so that needs to be fixed. I can’t physically crop the images to be the “correct” size, because there is no correct size: this needs to work across all screen widths. So rather than try to swap carefully-sized images in and out at various breakpoints, or complicate the structure with a wrapper element set to suppress overflow of resized images, I turned to object-fit.

#page-top .monoliths img { 
  display: block; 
  height: 33rem; 
  width: 100%; 
  object-fit: cover; 
  object-position: 50% 20%; 
}

If you’ve never used object-fit, it’s a bit like background-size. You can use it to resize image content within the image’s element box without creating distortions. Here, I set the fit sizing to cover, which means all of the img element’s element box will be covered by image content. In this case, it’s like zooming in on the image content. I also set a zooming origin with object-position, figuring that 50% across and 20% down would be in the vicinity of a speaker’s face, given the way pictures of people are usually taken.

The header of the An Event Apart website, and this time the speaker photos are not stretched.

This is fairly presentable as-is—a little basic, perhaps, but it would be fine to layer the navbar and promo copy back over it with Grid or whatever, and call it a day. But it’s too square and boxy. We must go further!

To make that happen, I’m going to take out the third and fourth images temporarily, so we can see more clearly how the next part works. That will leave us with Rachel and Derek.

Two speaker photos side by side, and a blank space on the right.

The idea here is to clip the images to be slanted, and then pull them close to each other so they have just a little space between them. The first part is managed with clip-path, but we don’t want to pull the images together unless their shapes are being clipped. So we set up a feature query.

@supports (clip-path: polygon(0 0)) or (-webkit-clip-path: polygon(0 0)) { 
  #page-top .monoliths li { 
    width: 37.5%; 
  } 
}

I decided to test for both the un-prefixed and WebKit-prefixed versions of clip-path because Safari still requires the prefix, and I couldn’t think of a good reason to penalize Safari’s users for the slowness of its standards advancement. Then I made the images wider, taking them from 25% to 37.5%, which makes them half again as wide.

The same two speaker photos side by side, but wider and with less space on the right.

Thanks to object fitting, the images don’t distort when I change their parent’s width; they just get wider and scale up the contents to fit. And now, it is time for clipping!

@supports (clip-path: polygon(0 0)) or (-webkit-clip-path: polygon(0 0)) { 
  #page-top .monoliths li { 
    width: 37.5%; 
    -webkit-clip-path: polygon(25% 0, 100% 0, 75% 100%, 0 100%); 
    clip-path: polygon(25% 0, 100% 0, 75% 100%, 0 100%); 
  } 
}

Each coordinate pair in the polygon() is like the position pairs in background-position or object-position: the horizontal distance first, followed by the vertical distance. So the first point in the polygon is 25% 0, which is 25% of the way across the element box, and no distance down, so right at the top edge. 100% 0 is the top right corner. 75% 100% is on the bottom edge, three-quarters of the way across the element, and 0 100% is the bottom left corner. That creates a polygon that’s a strip three-quarters the full width of the element box, and runs from bottom left to top right.

The speaker photos with slanted right and left angles, and a large gap inbetween.

Now we just have to pull them together, and this is where old tricks come back into play: all we need is a negative right margin to bring them closer together.

#page-top .monoliths li { 
  width: 37.5%; 
  margin-right: -7.5%; 
  -webkit-clip-path: polygon(25% 0, 100% 0, 75% 100%, 0 100%); 
  clip-path: polygon(25% 0, 100% 0, 75% 100%, 0 100%); 
}
The speaker photos with slanted right and less gap inbetween.

The separation between them is a little wider than we were originally aiming for, but let’s see what happens when we add the other two images back in and let flexbox do its resizing magic.

Notice how the slants actually change shape as the screen gets narrower or wider. This is because they’re still three-quarters the width of the image element’s box, but the width of that box is changing as the screen width changes. That means at narrow widths, the slant is much steeper, whereas at wide widths, the slant is more shallow. But since the clipping path’s coordinates were all set with percentage distances, they all stay parallel to each other while being completely responsive to changes in screen size. An absolute measure like pixels would have failed.

But how did the images get closer together just by adding in two more? Because the list items’ basic sizing added up to more than 100%, and they’re all set to flex-shrink: 1. No, you didn’t miss a line in the CSS: 1 is the default value for flex-shrink. Flex items will shrink by default, which after all is what we should expect from a flexible element. If you want to know how much they shrunk, and why, here’s what Firefox’s flex inspector reports.

A diagram of the flex container's size, from Firefox's flex inspector. The base size is 487.5px, the flexibility is -65px, and the final size is 422.5px.

When there were only two list items, there was space enough for both to be at their base size, with no shrinkage. Once we went to four list items, there wasn’t enough space, so they all shrank down. At that point, having a negative right margin of -7.5% was just right to pull them together to act as a unit.

So, now they’re all nicely nestled together, and fully responsive! The captions need a little work, though. Notice how they’re clipped off a bit on the left edge, and can be very much clipped off on the right side at narrower screen widths? This happens because the li elements are being clipped, and that clipping applies to all their contents, images and text alike. And we can’t use overflow to alter this: clipped is clipped, not overflowed.

Fortunately, all we really need to do is push the text over a small amount. Inside the feature query, I added:

#page-top .monoliths div { 
  padding-left: 2%;
  padding-right: 26%; 
}

This shifts the text just a bit rightward, enough to clear the clip path. On the right side, I padded the div boxes so their contents wouldn’t fall outside the clipped area and appear to slide under the next caption. We could also use margins here, but I didn’t for reasons I’ll make clear at the end.

A cropped screenshot of the captions below the speaker images.

At the last minute, I decided to make the text at least appear to follow the slants of the images. For that, I just needed to shift the first line over a bit, which I did with a bit more padding.

#page-top .monoliths strong { 
  padding-left: 1%; 
}
The same cropped screenshot of the captions below the speaker images, but the second line of text is slightly shifted to the left to follow the line of the slanted image edge.

That’s all to the good, but you may have noticed the captions still overlap at really narrow screen widths. There are a lot of options here, from stacking the images atop one another to reverting to normal flow, but I decided to just hide the captions if things got too narrow. It reduces clutter without sacrificing too much in the way of content, and by leaving them still technically visible, they seem to remain accessible.

@media (max-width: 35rem) { 
  #page-top .monoliths div { 
    opacity: 0.01 
  } 
}

And that, as they say, is that! Fully responsive slanted images with text, in an accessible markup structure. I dig it.

I did fiddle around with the separations a bit, and found that a nice thin separator occurred around margin-right: -8%, whereas beefier ones could be found above -7%. And if you crank the negative margin value to something beyond -8%, you’ll make the images overlap entirely, no visible separation—which can be a useful effect in its own right.

I promised to say why I used padding for the caption text div rather than margins. Here’s why.

#page-top .monoliths div { 
  padding-left: 3%; 
  padding-right: 26%; 
  border-top: 2px solid transparent; 
  background: linear-gradient(100deg,hsl(292deg,50%,50%) 50%, transparent 85%); 
  background-clip: padding-box; 
}
The same cropped screenshot of the captions below the speaker images, highlighted in purple.

It required a wee bit more padding on the left to look decent, and an alteration to the background clipping box in order to keep the purple from filling the transparent border area, but the end result is pretty nifty, if I do say so myself. Alternatively, we could drop the background gradient on the captions and put one in the background, with a result like this.

The final image of the header with speaker images and captions beneath. There's a dark purple background underneath it all.

I have no doubt this technique could be extended, made more powerful, and generally improved upon. I really wished for subgrid support in Chrome, so that I could put everything on a grid without having to tear the markup structure apart, and there are doubtless even more interesting clipping paths and layout patterns to try out.

I hope these few ideas spark some much better ideas in you, and that you’ll share them with us!



Source link

Python String Format Examples - DZone Web Dev
Strategy

Python String Format Examples – DZone Web Dev


The most basic way to construct a dynamic string in Python is with simple concatenation.

This approach is simple, but it is messy, ineffecient, and prone to error (ever forget the spaces?), especially for complex, dynamic strings.

You may also be familiar with the % operator (called a modulo), which allows you to perform string replacements like this (using a predefined variable “month” for substitution):

While also valid, this approach is more or less obsolete (Python 3 introduced the format() method, which was back-ported to Python 2.7).

You may also like:
Six Python Tips for Beginners

Introduction to the format() Method

That brings us to Python’s format() method. Introduced in Python 3, this method provides a simple way to construct and format strings with dynamic substitutions.  Once you understand the basic syntax, this method offers a flexible way to construct strings that also happens to leave your code looking much cleaner (in my opinion).

With the format() method, there are two primary substitution types, by index and by keyword.

Substitution by Index

The index argument is positional and allows you to insert items from a list. In this example, 'world' is the first (index 0) item in our list, so it gets inserted.

When we print our string to the console, we get: Hello world!

To see another example, try the interactive example below:

Example: Try changing the index values in the string!

Substitution by Keyword

The other approach is to use a keyword substitution, where the keyword references the key in a key-value pair.

If we print our string to the console, we get: This month is February!

Example: Using Variables

Number Formatting

The previous examples work for inserting strings into strings, but what if you want to insert a numeric value?  For that, there are additional formatting specifiers that are appended to the value to specify the desired output format. 

(If you don’t include a format specifier for an integer, it will default to “general” format.)

Specifier Formats Number As
d Decimal integer
g | G General number. Defaults to 6 levels of precision, or the min number of relevant levels. 
 | “G” functions the same as “g” except that large numbers will be formatted with “E”.
f Fixed point number. Defaults to 6 levels of precision.
e | E Scientific notation
% Converts value to a percentage
n Same as ‘g’ but uses the seperators of the current locale.
Specifier Converts Number To
h | H Hexidecimal (lower case | upper case)
o Octal
b Binary
c

Unicode

F-string (Literal String Interpolation, Oh My!)

With the release of Python 3.6, we were introduced to F-strings.

As their name suggests, F-strings begin with “f” followed by a string literal. We can insert values dynamically into our strings with an identifier wrapped in curly braces, just like we did in the format() method. However, instead of an index that represents our value’s position in a list or a key that maps to our value, we can use a variable name as our identifier. 

Take the following example: 

Here, our month variable is placed directly into our string. {month} is then replaced with month‘s value, “February,” when the F-string is evaluated. So, when my_string prints to our terminal, we get This month is February!. This removes some of the ambiguity that the previous methods added to string formatting. After all, why create a placeholder to represent a value that we reference later if we can use a single variable instead?

Another advantage of F-strings is that we don’t have to account for variable types. Notice that num_normal_days in the example above is an integer, 28. Previously, we would have had to use placeholders like %d or :g in order to add a numeric type to our string. With F-string, we don’t have to tell our program that it’s going to be looking at an integer inside of a string. Let’s let Python do what it’s good at — making our lives easier. 

Note: When using properties of objects with F-strings, make sure to avoid dot notation and instead use braces. For example, if I had an object called month and wanted to access its property, days, I would use months['days'] as opposed to month.days.

Additional String Methods

Python also offers a set of methods to help you programmatically transform your strings. Here is a list of a few methods worth making note of:

Method Result
capitalize() Capitalizes the first letter of the string
casefold() Returns the string in all lowercase (useful for string matching according to the python documentation)
count() Counts all instances of a substring
upper() Returns the string in all uppercase letters
split() Splits string on designated seperator
encode() Returns an encoded string
swapcase() Swaps the case of each letter in the string

More methods can be found in Python’s String documentation.

Note: If you’re interested in another formatting method in Python, check out their docs on String Templates

Further Reading



Source link

Image title
Strategy

The Ultimate Vue.js and Laravel CRUD Tutorial


CRUD (Create, Read, Update, and Delete) are the basic operations of data storage, and one of the first things you learn as a Laravel developer.

But what happens when you add a Vue.js single-page app as the front-end to this the stack? Suddenly you have to deal with asynchronous CRUD since operations now occur without a page refresh. This will require special attention to ensuring the state of the data is consistent in both the front-end and backends.

In this tutorial, I’ll show you how to set up a full-stack Vue and Laravel app and demo each of the CRUD operations. AJAX is the key to this architecture, so we’ll use Axios as the HTTP client. I’ll also show you some strategies for dealing with the UX pitfalls of this architecture.

You can check out the finished product in this GitHub repo.

Demo App

The demo full-stack app allows a user to create new “Cruds,” which I decided, after an incredible amount of creative thinking, are alien creatures with strange names and the ability to change from red to green and back.

The Cruds are shown on the main page, and the user has the power to create new Cruds, to delete them, or to update their color.

Image title

CRUD in the Laravel Backend

We’ll begin the tutorial with the Laravel backend where the CRUD operations are fulfilled. I’ll keep this part brief as Laravel CRUD is a topic covered extensively elsewhere.

In summary, we will:

  • Set up a database.
  • Set up RESTful API routes by using a Resource Controller.
  • Define methods in the controller to perform the CRUD operations.

Database

Firstly, the migration. Our Cruds have two properties: a name, and color which we store as text.

2018_02_02_081739_create_cruds_table.php

<?php

...

class CreateCrudsTable extends Migration
{
  public function up()
  {
    Schema::create('cruds', function (Blueprint $table) {
      $table->increments('id');
      $table->text('name');
      $table->text('color');
      $table->timestamps();
    });
  }

  ...
}
...

API

Now we set up RESTful API routes. The resource method of the Route facade will create all the actions we need automatically. However, we don’t need edit, show or store so we’ll exclude those.

routes/api.php

<?php

Route::resource('/cruds', 'CrudsController', [
  'except' => ['edit', 'show', 'store']
]);

With this in place, here are the various endpoints we’ll now have available in our API:

Image title

Controller

We now need to implement those actions in the controller:

app/Http/Controllers/CrudsController.php

*app/Http/Controllers/CrudsController*
<?php

namespace AppHttpControllers;

use AppCrud;
use IlluminateHttpRequest;
use IlluminateHttpResponse;
use FakerGenerator;

class CrudsController extends Controller
{
  // Methods
}

Let’s do a brief overview of each method:

create. We randomize the name and color of a new Crud using the Faker package included with Laravel. We send the new Crud data back as JSON.

<?php

...

public function create(Generator $faker)
{
  $crud = new Crud();
  $crud->name = $faker->lexify('????????');
  $crud->color = $faker->boolean ? 'red' : 'green';
  $crud->save();

  return response($crud->jsonSerialize(), Response::HTTP_CREATED);
}

index. We return the full set of Cruds with the index method. In a more serious app we’d use pagination, but let’s keep it simple for now.

<?php

...

public function index()
{
  return response(Crud::all()->jsonSerialize(), Response::HTTP_OK);
}

update. This action allows a client to change the color of a Crud.

<?php

...

public function update(Request $request, $id)
{
  $crud = Crud::findOrFail($id);
  $crud->color = $request->color;
  $crud->save();

  return response(null, Response::HTTP_OK);
}

destroy. This is how we delete our Cruds.

<?php

...

public function destroy($id)
{
  Crud::destroy($id);

  return response(null, Response::HTTP_OK);
}

Vue.js App

Now for our Vue single-page app. We’ll begin by creating a single-file component to represent our Cruds called CrudComponent.vue.

Image title

This component is just for display and doesn’t have much logic. Here are the noteworthy aspects:

  • The image shown depends on the color of the Crud (either red.png or green.png).
  • Has a delete button which triggers a method del on click, which emits an event delete with the ID of the Crud.
  • Has an HTML select (for choosing the color) which triggers a method update on change, which emits an event update with the ID of the Crud and the new color selected.

resources/assets/js/components/CrudComponent.vue

<template>
  <div class="crud">
    <div class="col-1">
      <img :src="image"/>
    </div>
    <div class="col-2">
      <h3>Name: {{ name | properCase }}</h3>
      <select @change="update">
        <option
          v-for="col in [ 'red', 'green' ]"
          :value="col"
          :key="col"
          :selected="col === color ? 'selected' : ''"
        >{{ col | properCase }}</option>
      </select>
      <button @click="del">Delete</button>
    </div>
  </div>
</template>
<script>
  export default {
    computed: {
      image() {
        return `/images/${this.color}.png`;
      }
    },
    methods: {
      update(val) {
        this.$emit('update', this.id, val.target.selectedOptions[0].value);
      },
      del() {
        this.$emit('delete', this.id);
      }
    },
    props: ['id', 'color', 'name'],
    filters: {
      properCase(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
      }
    }
  }
</script>
<style>...</style>

The other component in this project is App.js. This is where all the interesting logic occurs so we’re going to go through this one step-by-step.

Let’s begin with the template. This has the following jobs:

  • Display our Cruds with the crud-component component discussed above.
  • Loop through an array of Crud objects (in the array cruds), with each mapping to an instance of crud-component. We pass all the properties of a Crud through to the component as props and set up listeners for the update and delete events coming from the component.
  • We also have an Add button that will create new Cruds by triggering a method create on click.

resources/assets/js/components/App.vue

<template>
  <div id="app">
    <div class="heading">
      <h1>Cruds</h1>
    </div>
    <crud-component
      v-for="crud in cruds"
      v-bind="crud"
      :key="crud.id"
      @update="update"
      @delete="del"
    ></crud-component>
    <div>
      <button @click="create()">Add</button>
    </div>
  </div>
</template>

Here’s the script from App.js. Let’s talk this out too:

  • We start with a function Crud that creates new objects used to represent our Cruds. Each has an ID, color, and name.
  • We import the adjacent CrudComponent
  • The component definition contains the array cruds as a data property. I’ve also stubbed methods for each CRUD operation which will be populated in the next section.

resources/assets/js/components/App.vue

<template>...</template>
<script>
  function Crud({ id, color, name}) {
    this.id = id;
    this.color = color;
    this.name = name;
  }

  import CrudComponent from './CrudComponent.vue';

  export default {
    data() {
      return {
        cruds: []
      }
    },
    methods: {
      create() {
        // To do
      },
      read() {
        // To do
      },
      update(id, color) {
        // To do
      },
      del(id) {
        // To do
      }
    },
    components: {
      CrudComponent
    }
  }
</script>

Triggering CRUD From the Front-End With AJAX

All the CRUD operations in a full-stack app will be executed in the backend since that’s where the database is. However, the triggering of CRUD operations will often happen in the front-end.

As such, an HTTP client (something that can communicate between our front-end and backend across the internet) will be of importance here. Axios is a great HTTP client that comes pre-installed with the default Laravel front-end.

Let’s look at our resource table again, as each AJAX call will need to target a relevant API endpoint:

Image title

Read

Let’s begin with the read method. This method is responsible for retrieving our Cruds from the backend and will target the index action of our Laravel controller, thus using the GET endpoint /api/cruds.

We can set up a GET call with window.axios.get, as the Axios library has been aliased as a property of the window object in the default Laravel front-end setup.

Axios methods like get, post, etc. return a promise. We chain a then method with a callback to access the response. The object resolved can be destructured to allow convenient access to the data property in the callback, which is the body of the AJAX response.

resources/assets/js/components/App.vue

...

methods() {
  read() {
    window.axios.get('/api/cruds').then(({ data }) => {
      // console.log(data)
    });
  },
  ...
}

/*
Sample response:

[
  {
    "id": 0,
    "name": "ijjpfodc",
    "color": "green",
    "created_at": "2018-02-02 09:15:24",
    "updated_at": "2018-02-02 09:24:12"
  },
  {
    "id": 1,
    "name": "wjwxecrf",
    "color": "red",
    "created_at": "2018-02-03 09:26:31",
    "updated_at": "2018-02-03 09:26:31"
  }
]
*/

As you can see, the Cruds are returned in a JSON array. Axios automatically parses the JSON and gives us JavaScript objects, which is nice. Let’s iterate through these in the callback, then create new Cruds with our Crud factory function, then push them to the cruds array data property i.e. this.cruds.push(...).

resources/assets/js/components/App.vue

...

methods() {
  read() {
    window.axios.get('/api/cruds').then(({ data }) => {
      data.forEach(crud => {
        this.cruds.push(new Crud(crud));
      });
    });
  },
},
...
created() {
  this.read();
}

Note: We need to trigger the read method programmatically when the app loads. We do this from the created hook, which works, but is not very efficient. It’d be far better to get rid of the read method altogether and just include the initial state of the app inlined into the document head when the first loads. I discuss this design pattern in depth in the article Avoid This Common Anti-Pattern In Full-Stack Vue/Laravel Apps if you want to implement it.

With that done, we can now see the Cruds displayed in our app when we load it:

Image title

Update (and Syncing State)

The update action requires us to send form data, i.e. color, so the controller knows what to update. The ID of the Crud is given in the endpoint.

This is a good time to discuss an issue I mentioned at the beginning of the article: with full-stack apps, you must ensure the state of the data is consistent in both the front and backends.

In the case of the update method, we could update the Crud object in the front-end app instantly before the AJAX call is made since we already know the new state.

However, we don’t perform this update until the AJAX call completes. Why? The reason is that the action might fail for some reason: the internet connection might drop, the updated value may be rejected by the database, or some other reason.

If we wait until the server responds before updating the front-end state, we can be sure the action was successful and the front and backend data is synchronized.

resources/assets/js/components/App.vue

methods: {
  read() {
    ...
  },
  update(id, color) {
    window.axios.put(`/api/cruds/${id}`, { color }).then(() => {
      // Once AJAX resolves we can update the Crud with the new color
      this.cruds.find(crud => crud.id === id).color = color;
    });
  },
  ...
}

You might argue its bad UX to wait for the AJAX to resolve before showing the changed data when you don’t have to, but I think it’s much worse UX to mislead the user into thinking a change is done, when in fact, we aren’t sure if it is done or not.

Create and Delete

Now that you understand the key points of the architecture, you will be able to understand these last two operations without my commentary:

resources/assets/js/components/App.vue

methods: {
  read() {
    ...
  },
  update(id, color) {
    ...
  },
  create() {
    window.axios.get('/api/cruds/create').then(({ data }) => {
      this.cruds.push(new Crud(data));
    });
  },
  del(id) {
    window.axios.delete(`/api/cruds/${id}`).then(() => {
      let index = this.cruds.findIndex(crud => crud.id === id);
      this.cruds.splice(index, 1);
    });
  }
}

Loading Indicator and Disabling Interaction

As you know, our CRUD operations are asynchronous, and so there’s a small delay while we wait for the AJAX call to reach the server, for the server to respond, and to receive the response.

To improve UX, it’d be good to have some kind of visual loading indicator and to disable any interactivity while we wait for the current action to resolve. This lets the user know what’s going on, plus, it gives them certainty of the state of the data.

There are some good plugins for Vue.js loading state, but I’m just going to make something quick and dirty here: while AJAX is underway, I’ll overlay a full screen, semi-transparent div over the top of the app. This will kill the two above-mentioned birds with a single stone.

resources/views/index.blade.php

<body>
<div id="mute"></div>
<div id="app"></div>
<script src="js/app.js"></script>
</body>

To do this, we’ll toggle the value of a boolean mute from false to true whenever AJAX is underway, and use this value to show/hide the div.

resources/assets/js/components/App.vue

export default {
  data() {
    return {
      cruds: [],
      mute: false
    }
  },
  ...
}

Here’s how we implement the toggling of mute in the update method. When the method is called, mute is set to true. When the promise resolves, AJAX is done so it’s safe for the user to interact with the app again, so we set mute back to false.

resources/assets/js/components/App.vue

update(id, color) {
  this.mute = true;
  window.axios.put(`/api/cruds/${id}`, { color }).then(() => {
    this.cruds.find(crud => crud.id === id).color = color;
    this.mute = false;
  });
},

You’ll need to implement the same thing in each of the CRUD methods, but I won’t show that here for brevity.

To make our loading indicator markup and CSS, we add the element<div id="mute"></div> directly above our mount element <div id="app"></div>.

As you can see from the inline style, when the class on is added to <div id="mute">, it will completely cover the app, adding a greyish tinge and preventing any click events from reaching the buttons and selects:

resources/views/index.blade.php

<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <title>Cruds</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;,
      height: 100%;
      width: 100%;
      background-color: #d1d1d1
    }
    #mute {
      position: absolute;
    }
    #mute.on {
      opacity: 0.7;
      z-index: 1000;
      background: white;
      height: 100%;
      width: 100%;
    }
  </style>
</head>
<body>
<div id="mute"></div>
<div id="app"></div>
<script src="js/app.js"></script>
</body>
</html>

The last piece of the puzzle is to toggle the on class by utilizing a watch on the value of mute, which calls this method each time mute changes:

export default {
  ...
  watch: {
    mute(val) {
      document.getElementById('mute').className = val ? "on" : "";
    }
  }
}

With that done, you now have a working full-stack Vue/Laravel CRUD app with a loading indicator. Here it is again in its full glory:

Image title

Don’t forget to grab the code in this GitHub repo and leave me a comment if you have any thoughts or questions!



Source link

Min and Max Width/Height in CSS
Strategy

Min and Max Width/Height in CSS


Oftentimes, we want to limit the width of an element relative to its parent, and at the same time, to make it dynamic. So having a base width or height with the ability to make it extend based on the available space. Let’s say, for example, that we have a button that should have a minimum width, where it shouldn’t go below it. This is where the maximum and minimum properties become handy.

In this article, we will go through the maximum and minimum CSS properties for width and height, and to explain each one in a detailed way with possible use cases and tips.

Table of Contents

Width Properties

The first thing to discuss is width-related properties. We have min-width and max-width, and each one of them is important and has its use cases.

Min Width

When setting the value of min-width, its benefit lies in preventing the used value for width property from becoming less than the specified value for min-width. Note that the default value for min-width is auto, which resolves to 0.

Let’s take a basic example to demonstrate that.

We have a button with a varying text within in. The text might range from one word to multiple. To guarantee that it will have a minimum width even if it has one word only, min-width should be used. The minimum width is 100px so that even if the button has a very short content, like “Done” word, or an icon only, it will still be big enough to be noticed. This is very important when working with multilingual websites like Arabic. Consider the below example from Twitter:

In the before case, the button has the word “تم”, which means Done. The button width is too small, so I increased the min-width of it as you notice in the after case.

Min Width and Padding

While min-width can extend the button width in case its content is longer, padding on the horizontal sides should be added to achieve a proper looking button.

Max Width

When setting the value of max-width, its benefit lies in preventing the used value for width property from becoming more than the specified value for max-width. The default value for max-width is none.

A common and simple use case for max-width is using it with images. Consider the below example:

The image is larger than its parent element. By using max-width: 100%, the width of the image won’t exceed the width of its parent. In case the image is smaller than its parent, max-width: 100% won’t have an actual effect on the image, because it’s smaller than its parent.

Using Min Width and Max Width

When both min-width and max-width used for an element, which one of them will override the other? In other words, which one has a higher priority?

If min-width value is larger than max-width, then the min-width value will be taken as the width for the element. Consider the following example.

<div class="wrapper">
  <div class="sub"></div>
</div>
.sub {
  width: 100px;
  min-width: 50%;
  max-width: 100%;
}

The initial width value is 100px, and adding on that, there is min-width and max-width values. The result is that the element width hasn’t exceeded 50% of its containing block/parent element.

See the Pen
Min Width – Example 2
by Ahmad Shadeed (@shadeed)
on CodePen.

Height Properties

In addition to the minimum and maximum width properties, we have the same properties as the height.

Min Height

When setting the value of min-height, its benefit lies in preventing the used value for height property from becoming less than the specified value for min-height. Note that the default value for min-height is auto, which resolves to 0.

Let’s take an example to demonstrate a simple use case.

We have a section with a description text. The goal is to have a minimum height for the section, so it can handle short or long content. Consider the below basic case:

.sub {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  min-height: 100px;
  color: #fff;
  background: #3c78dB;
}

The minimum height is 100px, and with flexbox, the content is centered horizontally and vertically. What would happen if the content were longer? For example, a paragraph?

Yes, you guessed it! The height of the section will expand to contain the new content. By having that, we can build components that are fluid and responsive to its content.

See the Pen
Min Height – Example 1
by Ahmad Shadeed (@shadeed)
on CodePen.

Max Height

When setting the value of max-height, its benefit lies in preventing the used value for height property from becoming more than the specified value for max-height. Note that the default value for max-height is none.

Consider the below example where I set max-height for the content. But, because it’s bigger than the specified space, there is an overflow. The text is out of its parent boundaries due to that.

Use Cases for Min and Max Properties

We will go through some common and uncommon use cases for min-width, min-height, max-width, and max-height.

Tags List

When having a list of tags, it’s recommended to constraint a minimum width for a tag so that if its content is short, the look of it won’t be affected.

By having that flexibility, the tag will look good no matter how short the content is. But, what will happen in case the content author entered a very long tag name, and the content management system he uses doesn’t have a maximum character’s length for a tag? We can use max-width as well.

.c-tag {
  display: inline-block;
  min-width: 100px;
  max-width: 250px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  /*Other styles*/
}

By using max-width, the tag width will be constrained to a specific value. However, that’s not enough. The tag name should be truncated.

See the Pen
Min Width – Use case 1
by Ahmad Shadeed (@shadeed)
on CodePen.

Buttons

There are different use cases for the minimum and maximum values with buttons since there are multiple variations of a button component. Consider the following figure:

Notice that the button’s “Get” width is too small. Without setting a minimum width, this can get worse in case there was no text for any reason. Setting a minimum width is important in that case.

Setting Min Width to Zero With Flexbox

The default value for min-width is auto, which is computed to zero. When an element is a flex item, the value of min-width doesn’t compute to zero. The minimum size of a flex item is equal to the size of its contents.

According to the CSSWG:

By default, flex items won’t shrink below their minimum content size (the length of the longest word or fixed-size element). To change this, set the min-width or min-height property.

Consider the following example.

The person’s name has a very long word which caused an overflow and horizontal scrolling. Though, I added the below CSS to the title to truncate it:

.c-person__name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

Since the title is a flex item, the solution is to reset min-width and force it to become zero.

.c-person__name {
    /*Other styles*/
    min-width: 0;
}

Here is how it should look when fixed:

According to the CSSWG:

On a flex item whose overflow is visible in the main axis, when specified on the flex item’s main-axis min-size property, specifies an automatic minimum size.

That means, setting overflow to other than visible value can result in the min-width to be computed to zero, which solves our problem without setting min-width: 0.

See the Pen
Min Width and Flexbox Issue
by Ahmad Shadeed (@shadeed)
on CodePen.

Setting Min Height to Zero With Flexbox

While this is a less common issue compared to min-width, but it can happen. Just to confirm, the issue is related to a flex item that cannot be shorter than its content. As a result, the min-height value is set to as long the content is.

Consider the following example:

The text colored in red should be clipped in its parent. Because the panel body is a flex item, it’s min-height is as equal as its content. To prevent that, we should reset the minimum height value. Let’s see how the HTML and CSS:

<div class="c-panel">
  <h2 class="c-panel__title"><!-- Title --></h2>
  <div class="c-panel__body">
    <div class="c-panel__content"><!-- Content --></div>
  </div>
</div>
.c-panel {
  display: flex;
  flex-direction: column;
  height: 180px;
}

.c-panel__body {
  min-height: 0;
}

.c-panel__content {
  overflow-y: scroll;
  height: 100%;
}

By adding min-height: 0 to the panel body, this will reset the property and it should work as expected now.

Demo

Mixing Min Width and Max Width

In some cases, we have an element with minimum width, but at the same time, it doesn’t have a maximum width. This might result in the component being too wide without the author intended to do so. Consider the following example:

Since the width is defined in pixel, the above is not guaranteed to work for a mobile viewport. To solve that, we can use percentages instead of pixels for the minimum and maximum properties. Consider the below example that has an article body.

I added the following CSS for the image:

img {
  min-width: 35%;
  max-width: 70%;
}

See the Pen
Mixing Min Width and Max Width
by Ahmad Shadeed (@shadeed)
on CodePen.

Page Wrapper/Container

One of the top useful use cases for max-width is for page wrapper or containers. By adding a maximum width to the page, we can be sure that the content will be readable and easy to scan for the user.

Below is an example of a wrapper that is centered, and has horizontal padding on the left and right sides.

.wrapper {
    max-width: 1170px;
    padding-left: 16px;
    padding-right: 16px;
    margin-left: auto;
    margin-right: auto;
}

Max Width and The ch Unit

The ch unit is equal to the 0 (zero) character width in the element’s font. By combining this unit with max-width. As per this article on Smashing Magazine, the recommended line length is 45 to 75 characters per line.

In the previous example for the wrapper element, we can get the benefit of the ch unit, since it’s an article body.

.wrapper {
    max-width: 70ch;
    /* Other styles */
}

Animating An Element With An Unknown Height

In some cases, we face the challenge of animating accordion or a mobile menu with unexpected content height. In such a case, max-height can be a good solution.

Consider the following example:

When the menu button is clicked, the menu should slide from top to bottom with an animation. Without having a fixed height for it (which is not recommended), this is not possible unless JavaScript is used. However, with max-height, this is possible. The idea is to add big value for the height, for example, max-height: 20rem, which probably won’t be reached, then we can animate from max-height: 0, to max-height: 20rem.

.c-nav {
    max-height: 0;
    overflow: hidden;
    transition: 0.3s linear;
}

.c-nav.is-active {
    max-height: 22rem;
}

Click the menu button to see the animation in action.

See the Pen
Max Height Animation
by Ahmad Shadeed (@shadeed)
on CodePen.

Min Height For Hero Elements

In general, I don’t like to add a fixed height to elements. I feel that by doing that, I’m going against making the web fluid and build components that are fluid as water. Adding a minimum height to a hero section is useful in cases where a very long content is added (It happens).

Consider the following example, where we have a hero section with a fixed height set. Everything looks good.

When the content is longer, though, it overflows and goes out of the hero wrapper. This is not good.

To fix that issue upfront, we can add min-height instead of height, and we at least do that to salve our conscience. Even though this might cause a page to look weird, but I think such a thing should be prevented from happening in the content management system (CMS) in the first place. With that, the issue is fixed and it looks good.

The issue of overflowing content is not only about the content being bigger than the fixed hero height. It could happen on screen resize as a result of text wrapping.

If min-height were used instead, the above won’t happen at all.

For a modal component, it needs a minimum and maximum width so it can work on screens from mobile to desktop. In this regard, I recall an interesting article on CSS Tricks that discussed what to use for that purpose.

Concept 1

.c-modal__body {
    width: 600px;
    max-width: 100%;
}

Concept 2

.c-modal__body {
    width: 100%;
    max-width: 600px;
}

For me, I prefer the second concept as I only need to define max-width: 600px. The modal is a <div> element so it already has 100% width of its parent, correct?

Consider the below-reduced test case for a modal design. Notice how the width changes to 100% of its parent, in case the available viewport space is not enough.

See the Pen
Max Width Modal
by Ahmad Shadeed (@shadeed)
on CodePen.

Min Height and Sticky Footers

When the content of a website is not long enough, it’s expected to see the footer not sticked to the bottom. Let’s take a visual example to show that better.

Notice that the footer is not sticked at the end of the browser window. That’s because the content is not enough to be as long as the browser window height. When fixed, it should look like the below:

First, I made the body element as a flexbox container, then I set the minimum height of it to be 100% of the viewport height.

body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

footer {
    margin-top: auto;
}

I recommend checking this article about sticky footers.

Demo

Fluid Ratio with Max Width/Height and Viewport Units

To make a proportional container that scales responsively based on the viewport size, the padding hack were introduced. Now, we can mimic the same behaviour by combining viewport units and max width/height in CSS.

Based on an article by Miriam Suzanne, I want to explain how it works.

We have an image with the dimensions 644*1000 pixels. To make it fluid, we need the following:

  • Aspect ratio: height/width
  • The width of its container: it can be a fixed number, or dynamic (100%)
  • Set the height which is 100% of the viewport width multiplied by the aspect ratio
  • Set the max-height which is the container width multiplied by the aspect ratio
  • Set the max-width to be equal to the container width
img {
  --ratio: 664 / 1000;
  --container-width: 30em;
  display: block;
  height: calc(100vw * var(--ratio));
  max-height: calc(var(--container-width) * var(--ratio));
  width: 100%;
  max-width: var(--container-width);
}

See the Pen
Fluid Ratio with Max Height/Width
by Ahmad Shadeed (@shadeed)
on CodePen.

HTML/Body with 100% height

When we want the <body> element to take 100% height of the viewport. How we can do it? This is a common question/use case in the web community as in this question on StackOverflow.

First, we need to add height: 100% to the <html> element. This will guarantee that the root element has 100% height. Then, we add min-height to the <body> element, and the reason min-height is used, because this can allow the body height to be dynamic, no matter how long its content is.

html {
  height: 100%;
}

body {
  min-height: 100%;
}

Demo

Notes

Min Width and Block Elements

In some cases, we forgot that the element we’re trying to apply min-width to is a block element. As a result, this might be confusing and it won’t affect the element. Make sure that the element is not a block-level one.

CSS Comparison Functions

While researching about pain points and issues people face in StackOverflow, I stumbled upon this question, where the author asked the following:

Is it possible to do something like this
max-width: calc(max(500px, 100% - 80px))
or
max-width: max(500px, calc(100% - 80px)))

The behaviour wanted is that to keep the element’s width 500px and it should not exceed that. If the viewport width is not enough to contain the element, then its width will be 100% - 80px.

As for the above solutions from the question, I tried the second one and it works in the latest Chrome (v79) and Safari (v13.0.3), as the time of writing this article. Since this is out of the scope of this article, and I might write about it soon, I will explore a solution suggested in the question.

.yourselector {
  max-width: calc(100% - 80px);
}

/* Update: I changed the max-width from 500px to 580px. Thanks @fvsch */
@media screen and (max-width: 580px) {
  .yourselector {
    max-width: 500px;
  }
}

Resources and Further Reading

The End

And that’s a wrap. Do you have a comment or a suggestion? Please feel free to ping me on @shadeed9.





Source link

seo_01.png
Strategy

Is My Single-Page Application SEO Friendly?


A notoriously murky area of single-page application (SPA) development is SEO. Depending on who you ask, search engine crawling of client-rendered content is either totally fine, fine as long as it’s synchronous or not at all fine.

Due to the confusion caused by all this conflicting advice, I regularly see the question “is my Vue SPA okay for SEO?” come up in places like the Vue.js Developers Facebook group, the Vue.js Forums, and r/vuejs on Reddit.

In this article, we’ll challenge the popular opinions, do doing some basic tests, and try to conclude with some sensible advice for building SEO-friendly SPAs.

The Issue With Client-Rendered Content

The standard implementation of a single-page app provides a page “shell” to the browser without any meaningful content included. The content is instead loaded on demand from the server with AJAX and then added to the page by JavaScript.

This allows a user to view the “pages” of an SPA site without a page refresh, theoretically improving UX.

seo_01.png

While this architecture works for human users viewing the page in a browser, what about search engine crawlers? Can crawlers run JavaScript? If so, will they wait for the AJAX calls to complete before crawling the page?

It’s important to know this, as it could determine whether or not the site’s content is indexable by a search engine, and just as importantly, how well its content is ranked.

Googlebot

Since Google is the leading search engine globally, our inquiry should focus on Googlebot, the Google search engine crawler.

In the early days of the web, Googlebot would only crawl the static HTML provided in a page. It was announced in 2014, however, that Googlebot would now attempt to render JavaScript before it began crawling.

To help debug any issues with rendering a JavaScript-modified page, Google provided webmasters with the Fetch As Google tool, which shows a snapshot of what Googlebot sees at a particular URL.

One common myth is that Googlebot won’t crawl asynchronous JavaScript. This article has done a great job of busting it. TLDR; Googlebot will wait at least 20 seconds for asynchronous calls to complete!

How Googlebot Sees an SPA

The quintessential Vue.js SPA example is the Vue HackerNews Clone 2.0. This is an open source project provided by the Vue team to demonstrate the full capabilities of Vue and effective design patterns.

I deployed this app to a Heroku instance and ran it through Fetch As Google. In the image below, the screenshot on the left shows how Googlebot saw it, and the screenshot on the right shows how a user would see it. They appear to be identical.

seo_02.png

Removing Server-Side Rendering

One of the key features of the Vue HackerNews Clone 2.0 is server-side rendering (SSR). This means, unlike a more basic SPA, the content for each page is rendered on the server and provided to the browser on each page load, just like it were static HTML.

What we’re trying to understand, though, is how Googlebot sees client-rendered content. For this reason, I switched SSR off and ran the test again:

seo_03.png

Even with client rendering only, Googlebot had no trouble seeing the content. I also waited a few days to see if Google had indexed the app. It had:

seo_04.png

But Wait…

While this test seems to satisfy any concern about client-rendered content, there are some reasons why you shouldn’t have full confidence in it:

  1. Like all JavaScript engines, Googlebot will not be infallible and there may be edge cases where it cannot render your page.
  2. Just because a page can be indexed, doesn’t mean it will rank well.

Be Skeptical of JavaScript

Googlebot had no issues rendering Vue HackerNews. But we shouldn’t conclude it can render all JavaScript so flawlessly. Google’s 2014 announcement about JavaScript rendering made it clear that there would be no guarantee, although most developers seem to have overlooked that.

Just like a browser, Googlebot must have a JavaScript engine with a particular subset of implemented web standards and ES features, and its particular idiosyncrasies for how those are implemented.

According to this video from Google developers Addy Osmani and Rob Dodson (released Nov 2017), Googlebot is currently based on Chrome 41. There are a lot of new APIs that have been released since version 41, and if you used any of them, presumably Googlebot would not be able to render and index your page.

You may think this is a trivial issue, as you would need to transpile or polyfill such features for older browsers anyway. The point, though, is that you shouldn’t have blind faith in your app being run correctly by every search crawler, just as you wouldn’t have blind faith in your app being run correctly by every browser.

Optimization

Don’t forget the “O” in “SEO” stands for “optimization.” Being indexed be a search engine is not enough; we want our sites to rank well, too. Fetch As Google tells us how a page is seen, but not how the page compares to the competition.

There’s an interesting comment on the article SEO vs. React: Web Crawlers are Smarter Than You Think made by SEO expert Barry Adams. On the topic of how search engines rank SPAs he said:

“What happens when you use React without server-side rendering is that the crawler halts on the very first page because it can’t see any hyperlinks to follow…It makes the crawl process incredibly slow and inefficient. And that is why websites built on React (and similar JavaScript platforms) perform worse in Google than websites that primarily serve plain HTML to the crawler….plain HTML websites can be crawled very efficiently, newly added and changed content will be crawled and indexed much quicker, and Google is much better able to evaluate the crawl priority of individual pages on such websites.”

While he doesn’t provide any evidence for this, it does seem to be inline with the philosophy of other ranking determinates like page speed.

What to Do if SEO Is Critical

The bottom line is, if SEO is critical, you can’t rely on your SPA’s client rendering and must ensure content comes included in your pages.

This doesn’t mean you need to abandon the SPA architecture, though. There are two techniques, server-side rendering and prerendering, that both can achieve the desired outcome.

Server-Side Rendering

Server-side rendering (SSR) is where a page is rendered by the web server as part of the server request/response cycle. In the case of Vue.js and other similar frameworks, this is done by executing the app against a virtual DOM.

The state of the virtual DOM is converted to an HTML string, then injected into the page before as it is sent to the client. When the page reaches the browser, the JavaScript app will seamlessly mount over the existing content.

SSR guarantees your page will be crawler friendly, as the page content is complete regardless of how, or even if, the crawler runs JavaScript.

SSR has its downsides, though:

  • You’ll need to design your code to be “universal,” i.e. it must work in both in the browser and in a server-based JavaScript environment. This means any code that expects browser APIs and objects like window to be available, will not work.
  • Your app will run on each request to the server, adding additional load and slowing responses. Caching can partially alleviate this.
  • It’s complicated and time-consuming to implement SSR, so you’ll need more developer hours for the project.
  • It only works well with a Node.js backend. SSR can be done with non-Node backends, for example, by using the PHP extension v8js, but such solutions are quite limited.

If you’re keen to implement server-side rendering in a Vue.js SPA, you should begin with the official guide: Vue.js Server-Side Rendering Guide. I’ve also written a guide on implementing SSR with Laravel and Vue.js: Server-Side Rendering With Laravel & Vue.js 2.5.

Tip: frameworks like Nuxt.js come with server-side rendering out of the box.

Prerendering

If you can’t use SSR for one of the above reasons, there is another way: prerendering. With this approach, you run the app with a headless browser in your development environment, snapshot the page output, and substitute your HTML files with this snapshot in the server’s response.

It’s pretty much the same concept as SSR, except it’s done pre-deployment, not on a live server. It’s typically performed with a headless browser like Chrome and can be incorporated into a build flow with Webpack, Gulp, etc.

The advantage of prerendering is that it doesn’t require a Node.js production server and doesn’t add load to your production server.

However, prerendering also has downsides:

  • It doesn’t work well for pages that display changing data, for example, Vue HackerNews.
  • It’s not appropriate for pages that have user-specific content, e.g. an account page with a user’s personal details. However, these kinds of pages are less critical for SEO; you normally wouldn’t want an account page indexed anyway.
  • You’ll need to pre-render every route in the app individually, which could take a great amount of time for a large site.

If you’re keen to implement prerendering in a Vue.js app, I’ve written a guide on this blog: Pre-Render A Vue.js App (With Node Or Laravel)

Tip: prerendering for SEO can be purchased as a service from prerender.io

Conclusion

Many developers saw Google’s 2014 announcement about JavaScript rendering as an end to SEO concerns about SPA content. In fact, there’s no guarantee that Googlebot will correctly render a page, and, if it does, it still may rank the page lower than static HTML pages in competing sites.

My advice: if you are going to use the SPA architecture, be sure to provide server rendered or prerendered pages.





Source link

Waterfall chart for approach #2
Strategy

Web Performance Calendar » Bundling JavaScript for Performan…


We’re about to enter into a new decade – 2020 and beyond, so what a good time to re-evaluate our best practices of yesteryear to see if they still hold up. Sometimes the best practices of yesterday become the antipatterns of today…

I’ll be looking at three approaches with bundling a simple React.js “hello world” app. Some of these examples assume some basic knowledge of module bundlers such as Webpack, which still seems to be the most popular of the module bundler options out there today.

Approach #1: Bundle all the things! (big ball of yarn)

(TLDR: don’t use this approach!)

This approach simply uses a module bundler to package everything, dependencies and all, into one big ball of yarn. For my “hello world” example, this bundle includes react, react-dom, as well as the “hello world” code. The entrypoint includes just this one script bundle:

<!-- index.html -->
<script src="https://calendar.perfplanet.com/bundle.[hash].min.js"></script>

Before HTTP/2, this pattern may have been kind of acceptable because it reduces HTTP requests, but with most sites now using HTTP/2, this has become an antipattern.

Why? Because with HTTP/2 there is no longer a big overhead with making multiple HTTP requests, removing any substantial advantage in bundling everything up.

Browser caching also becomes very problematic with this approach. Think of this: changing just one line of code in the simple “hello world” code invalidates the hash of the entire bundle, forcing all users to redownload everything, even though 99% of the code may be exactly the same compared to the last time a user visited. That’s a lot of wasted bandwidth for code that hasn’t changed.

HTTP/2 is now supported by over 95% of clients worldwide, and as of this year is now the majority protocol implemented by web servers across the web. Check out the Web Almanac for more information about HTTP/2 usage this year.

Approach #2: Separated vendor and client code (code splitting)

(TLDR: please use this approach!)

Ok, let’s learn our lesson from Approach #1 and take better advantage of browser caching by splitting out our own code from its dependencies. This solves the simple use case above where we just changed one line of code and redeployed. Now just the index file hash has changed, and the vendor hash remains the same. Returning visitors will save some bandwidth by only re-downloading the changed index file!

In Webpack land, this requires some extra code splitting config to tell Webpack where the vendor code lives (node_modules in the path is a nice low-maintenance way of determining that, since all our vendor dependencies live there).

Here’s what our site looks like now:

<!-- index.html -->
<script src="https://calendar.perfplanet.com/vendor.[hash].min.js"></script>
<script src="index.[hash].min.js"></script>

And here’s a waterfall chart for this approach (served on HTTP/2):

Waterfall chart for approach #2

This is a step in the right direction, and we can even optimize further. If you think about it, you will realize that some of your vendor dependencies probably change slower than others. react and react-dom probably change the slowest, and their versions are always paired together, so they both form a logical chunk that can be kept separate from other faster-changing vendor code:

<!-- index.html -->
<script src="https://calendar.perfplanet.com/vendor.react.[hash].min.js"></script>
<script src="vendor.others.[hash].min.js"></script>
<script src="index.[hash].min.js"></script>

To optimize even further, consider that visitors probably don’t need to download all of your app code to view just one page. Just like us humans have a tendency to grow larger this time of the year, over time your site’s index code will also grow larger, so eventually it may make sense to code split even further by dynamically loading individual components and even prefetching/preloading individual modules.

To me this still sounds pretty scary and experimental (and probably a nice opportunity for difficult bugs to creep in somewhere), but it seems clear that this is the direction we’re headed. Perhaps with the native browser support of JavaScript modules, we may eventually abandon module bundlers like Webpack altogether and simply deliver code in module-sized chunks! It’ll be interesting to see this evolve over time!

Approach #3: Public CDN for some vendor code?

(TLDR: don’t use this approach!)

If you are a bit oldschool (like yours truly), you may have a gut intuition that we could maybe benefit by replacing vendor.react in Approach #2 with script tags from a public CDN:

<!-- index.html -->
<script crossorigin src="https://unpkg.com/react@16.12.0/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.production.min.js"></script>
<script src="index.[hash].min.js"></script>

(note: for this approach you’d also have to separately configure Webpack to exclude react and react-dom from the index build)

Unfortunately, this approach now has mostly downsides. Here are four strikes against it:

Strike 1: Shared vendor files between websites? Not anymore…

Traditionally, the hope was that if all sites linked to that same CDN and used the same version of React as we’re using, we could assume that visitors to our site would arrive with all the React dependencies already cached, speeding up their experience considerably. What’s more, the React.js docs support that use case, so surely some folks are using this pattern, right?

While this may have been true in past times, browsers are recently starting to implement something called partitioned caches due to security concerns. What this effectively means is that even in ideal conditions where two sites point to the exact same third party resource URL, the code is downloaded once per domain, and the cache is “sandboxed” to that domain due to privacy implications. As Andy Davies discovered, this is already implemented in Safari (apparently it’s been around since 2013?!). And as of Chrome 77, this partitioned cache is implemented behind a flag.

The Web Almanac also makes an educated guess that usage of these public CDNs will decrease as more browsers implement partitioned caches.

(credit to Anthony Barré’s article, Joseph Scott’s comment on that article, and research by Andy Davies)

Strike 2: Extra time for pre-request stuff (for every domain)

Also mentioned in Anthony Barré’s article is the fact that using a public CDN incurs a hit due to a lot of browser back and forth that needs to happen before even sending an HTTP request: DNS resolution, initial connection, and SSL handshake. This is stuff that already needs to happen one way or another for browsers to connect to your main site, but hitting the public CDN incurs an additional hit:

Here’s a waterfall to illustrate when we use a public CDN:

Waterfall chart for using a public CDN

Note the areas circled in red, which is all that pre-request stuff happening behind the scenes. That’s a lot of extra pre-request overhead for just this simple “hello world”.

As my simple “hello world” site grows, I expect that soon a custom font would get added, say from Google Fonts, resulting in more of this sort of waiting from an additional domain. Suddenly the case becomes stronger for simply hosting all the assets on your main domain (behind your own CDN of course, such as Cloudflare or Cloudfront).

Simply moving these two React dependencies from the public CDN onto the primary domain results in a much cleaner waterfall:

Waterfall chart for hosting all vendor code

Strike 3: Disparate vendor versions

I performed a quick unscientific study of 32 major websites that use React.js. Sadly, I found that only 10% used a public CDN to host React. But it turned out not to matter much. Even in an ideal world, if we could get everyone to coordinate and use the same public CDN (and without the partitioned cache concern in Strike #1), the React versions used by these websites are too disparate to be useful:

Pie chart with many different React.js versions

If you browse from one popular React-based website to another React-based site, the chances are not in your favor that the React versions are the same.

I did find some other interesting tidbits about these React.js sites that you may find interesting:

  • 2/3 use Webpack to bundle their code.
  • 87% use HTTP/2, way more than the current 58% average.
  • The majority host their own custom fonts (~56%).

You can view my raw data from this quick unscientific study here.

Strike 4: Non-performance implications

Unfortunately there are more than just performance downsides to using public CDNs today:

  • Security concerns. Aside from the security concerns that are leading browsers to use partitioned caching (see Strike #1 above), there are other security concerns. If hackers compromise a public CDN, they can very subtly inject malicious JavaScript into libraries. These scripts would have all the privileges of clientside code running on your domain, and be able to access data of logged-in users.
  • Privacy concerns. Many companies harvest user data from third party requests. Theoretically, if all websites implemented a public CDN for their vendor code or fonts, that CDN would be able to track a user’s session and browsing habits, and make guesses at their interests (e.g. for advertising), without the aid of cookies!
  • Single point of failure. Spreading content out across multiple domains increases the chances that one of those domains will have an outage, resulting in your page getting only partially loaded. To be fair, there are JavaScript workaround for this, but it involves some extra work.

Conclusions

Clearly the future is in Approach #2.

Put your app behind HTTP/2, a non-shared CDN (e.g. Cloudflare or Cloudfront), and serve up your site into several bite-sized chunks to take advantage of caching. These bite-sized chunks may get even smaller in the future, probably at the JavaScript module level, as browsers start to natively support JavaScript modules.



Source link

5 Awesome Boilerplates/Templates for Vue.js Projects
Strategy

5 Awesome Boilerplates/Templates for Vue.js Projects


Are you about to begin an important Vue project? To ensure you start with a solid foundation, you might use a template (aka boilerplate, skeleton, starter, or scaffold) rather than starting from npm init or vue init.

Many experienced developers have captured their wisdom about building high-quality Vue apps in the form of open source templates. These templates include optimal configuration and project structure, the best third-party tools, and other development best practices.

Unlike Vue CLI 3, which is optimized for flexibility, templates are opinionated. It’s important, therefore, to choose the one that fits with your development philosophy and has roughly the same features that you’ll need out of the box.

Some considerations for choosing a Vue template include:

  • Webpack
  • PWA
  • Full-stack with authentication
  • Good documentation
  • GraphQL
  • Testing

There are many great Vue.js templates out there, but, in this article, we’ll look at 5 that include key features that new projects will often require.

1. Best for Webpack

If you need a solid Webpack setup then look no further than the Webpack template included with Vue CLI 2. With almost 7000 stars on GitHub and development and maintenance by Vue team members, this template is your best bet for creating a highly optimized Webpack-powered SPA.

This template leverages many cutting-edge features of Webpack and its ecosystem including hot reload, CSS extraction, linting and of course single-file component loading. It also includes separate configs optimized for development, production, and even testing.

Being part of Vue CLI 2, this is one of the least opinionated templates we’ll feature and so doesn’t include many desirable extras like server-side rendering.

If you find the Webpack template a bit of overkill, you can try its little brother, the Webpack Simple template.

Link: https://github.com/vuejs-templates/webpack

Note: Vue CLI version 3, which is soon to leave beta, has dropped the template architecture in favor of plugins, so this template will technically be deprecated, but will still be available from the legacy settings of Vue CLI 3. Learn more in our article Vue CLI 3: A Game Changer For Frontend Development.

2. Best for PWAs

Do you need the superior UX of a progressive app? Vue Starter is an SPA template for server-rendered PWAs. It includes Vuex and Vue Router configured to work with server-side rendering (SSR) out of the box.

This project has put a lot of thought into ensuring your deployed project has amazing UX right from the beginning, like internationalization for multiple language support and a Lighthouse score of 90+ thanks to SSR and caching with service worker.

Additionally, document head tag management with vue-meta is used for SEO, while SSR ensures that your page will be indexed by search engines that support JavaScript content.

Link: https://github.com/devCrossNet/vue-starter

Demo: https://vue-starter.herokuapp.com

Another nice option if you’re building a PWA is VuePack and of course, there’s the Vue CLI 2 PWA template.

3. Best for Authentication

If you need user authentication then check out Vue Express Mongo Boilerplate. This project provides a full-stack “MEVN” web app boilerplate with out-of-the-box authentication including user signup and social login with Google, Facebook, Twitter, and GitHub.

This template follows security best practices by using OAuth 2, Helmet (which adds secure HTTP headers) and Express Validator for input sanitization. It also provides support for several remote logging services.

For the database, MongoDB with Mongoose is provided. The repo also includes Docker config so you can spin up an instance with ease.

Link: https://github.com/icebob/vue-express-mongo-boilerplate

Demo: http://vemapp.moleculer.services/

Tip: if you’d prefer to use Laravel as a backend for an authenticated Vue app, try Laravel Vue Boilerplate which includes many similar features.

4. Best for Documentation

Where many templates fall down is with their lack of documentation. Not so with Vue Enterprise Boilerplate. This project is created and maintained by Chris Fritz who wrote much of the Vue documentation, so it is both well organized and consistent with Vue best practices.

The great thing about the documentation for this template is that it explains not only what’s included, but often what is not included, and why. For example, Chris explains why there’s no TypeScript, Babel polyfills, Pug, etc., which are common in other templates.

Don’t let the plain-looking default page of this app fool you, it has plenty of features too. Some of my favorites include mock APIs for testing, and the inclusion of generators allowing you to setup components, views, and layouts with unit tests automatically added.

Vue Enterprise Boilerplate also supports Vue CLI 3 so the project could easily be expanded with additional Vue CLI 3 plugins.

Link: https://github.com/chrisvfritz/vue-enterprise-boilerplate

5. Best for GraphQL

GraphQL is all the rage right now, and many developers want it in their new Vue projects. Not many Vue templates have it though, so if you need GraphQL be sure to check out Vuexpresso.

This project uses GraphQL, Apollo, and also GraphiQL UI, an in-browser IDE for exploring GraphQL. In addition to these, you get a well-configured Webpack setup, Vuex, and Vue Router. You also get Storybook, which allows for interactive development, testing, and sharing of UI components.

The only downside to Vuexpresso is that it is still fairly new, so be sure to have the time to thoroughly test any apps you build with it.

Link: https://github.com/Ethaan/vuexpresso

Another boilerplate with GraphQL support is Friendly Vue Starter which also includes critical-path CSS extraction via Critical.



Source link