Archiwum kategorii: CSS

Seriously, though. What is a progressive web app?

Post pobrano z: Seriously, though. What is a progressive web app?

Amberley Romo read a ton about PWAs in order to form her own solid understanding.

“Progressive web app” (PWA) is both a general term for a new philosophy toward building websites and a specific term with an established set of three explicit, testable, baseline requirements.

As a general term, the PWA approach is characterized by striving to satisfy the following set of attributes:

  1. Responsive
  2. Connectivity independent
  3. App-like-interactions
  4. Fresh
  5. Safe
  6. Discoverable
  7. Re-engageable
  8. Installable
  9. Linkable

Direct Link to Article — Permalink

The post Seriously, though. What is a progressive web app? appeared first on CSS-Tricks.

Level up your .filter game

Post pobrano z: Level up your .filter game

.filter is a built-in array iteration method that accepts a predicate which is called against each of its values, and returns a subset of all values that return a truthy value.

That is a lot to unpack in one statement! Let’s take a look at that statement piece-by-piece.

  • „Built-in” simply means that it is part of the language—you don’t need to add any libraries to get access to this functionality.
  • „Iteration methods” accept a function that are run against each item of the array. Both .map and .reduce are other examples of iteration methods.
  • A „predicate” is a function that returns a boolean.
  • A „truthy value” is any value that evaluates to true when coerced to a boolean. Almost all values are truthy, with the exceptions of: undefined, null, false, 0, NaN, or "" (empty string).

To see .filter in action, let’s take a look at this array of restaurants.

const restaurants = [
    {
        name: "Dan's Hamburgers",
        price: 'Cheap',
        cuisine: 'Burger',
    },
    {
        name: "Austin's Pizza",
        price: 'Cheap',
        cuisine: 'Pizza',
    },
    {
        name: "Via 313",
        price: 'Moderate',
        cuisine: 'Pizza',
    },
    {
        name: "Bufalina",
        price: 'Expensive',
        cuisine: 'Pizza',
    },
    {
        name: "P. Terry's",
        price: 'Cheap',
        cuisine: 'Burger',
    },
    {
        name: "Hopdoddy",
        price: 'Expensive',
        cuisine: 'Burger',
    },
    {
        name: "Whataburger",
        price: 'Moderate',
        cuisine: 'Burger',
    },
    {
        name: "Chuy's",
        cuisine: 'Tex-Mex',
        price: 'Moderate',
    },
    {
        name: "Taquerias Arandina",
        cuisine: 'Tex-Mex',
        price: 'Cheap',
    },
    {
        name: "El Alma",
        cuisine: 'Tex-Mex',
        price: 'Expensive',
    },
    {
        name: "Maudie's",
        cuisine: 'Tex-Mex',
        price: 'Moderate',
    },
];

That’s a lot of information. I’m currently in the mood for a burger, so let’s filter that array down a bit.

const isBurger = ({cuisine}) => cuisine === 'burger';
const burgerJoints = restaurants.filter(isBurger);

isBurger is the predicate, and burgerJoints is a new array which is a subset of restaurants. It is important to note that restaurants remained unchanged from the .filter.

Here is a simple example of two lists being rendered—one of the original restaurants array, and one of the filtered burgerJoints array.

See the Pen .filter – isBurger by Adam Giese (@AdamGiese) on CodePen.

Negating Predicates

For every predicate there is an equal and opposite negated predicate.

A predicate is a function that returns a boolean. Since there are only two possible boolean values, that means it is easy to „flip” the value of a predicate.

A few hours have passed since I’ve eaten my burger, and now I’m hungry again. This time, I want to filter out burgers to try something new. One option is to write a new isNotBurger predicate from scratch.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = ({cuisine}) => cuisine !== 'burger';

However, look at the amount of similarities between the two predicates. This is not very DRY code. Another option is to call the isBurger predicate and flip the result.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = ({cuisine}) => !isBurger(cuisine);

This is better! If the definition of a burger changes, you will only need to change the logic in one place. However, what if we have a number of predicates that we’d like to negate? Since this is something that we’d likely want to do often, it may be a good idea to write a negate function.

const negate = predicate => function() {
  return !predicate.apply(null, arguments);
}

const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = negate(isBurger);

const isPizza = ({cuisine}) => cuisine === 'pizza';
const isNotPizza = negate(isPizza);

You may have some questions.

What is .apply?

MDN:

apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object).

What is arguments?

MDN:

The arguments object is a local variable available within all (non-arrow) functions. You can refer to a function’s arguments within the function by using the arguments object.

Why return an old-school function instead of a newer, cooler arrow function?

In this case, returning a traditional function is necessary because the arguments object is only available on traditional functions.

Returning Predicates

As we saw with our negate function, it is easy for a function to return a new function in JavaScript. This can be useful for writing „predicate creators.” For example, let’s look back at our isBurger and isPizza predicates.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isPizza  = ({cuisine}) => cuisine === 'pizza';

These two predicates share the same logic; they only differ in comparisons. So, we can wrap the shared logic in an isCuisine function.

const isCuisine = comparison => ({cuisine}) => cuisine === comparison;
const isBurger  = isCuisine('burger');
const isPizza   = isCuisine('pizza');

This is great! Now, what if we want to start checking the price?

const isPrice = comparison => ({price}) => price === comparison;
const isCheap = isPrice('cheap');
const isExpensive = isPrice('expensive');

Now the isCheap and isExpensive are DRY, and isPizza and isBurger are DRY—but isPrice and isCuisine share their logic! Luckily, there are no rules for how many functions deep you can return.

const isKeyEqualToValue = key => value => object => object[key] === value;

// these can be rewritten
const isCuisine = isKeyEqualToValue('cuisine');
const isPrice = isKeyEqualToValue('price');

// these don't need to change
const isBurger = isCuisine('burger');
const isPizza = isCuisine('pizza');
const isCheap = isPrice('cheap');
const isExpensive = isPrice('expensive');

This, to me, is the beauty of arrow functions. In a single line, you can elegantly create a third-order function. isKeyEqualToValue is a function that returns the function isPrice which returns the function isCheap.

See how easy it is to create multiple filtered lists from the original restaurants array?

See the Pen .filter – returning predicates by Adam Giese (@AdamGiese) on CodePen.

Composing Predicates

We can now filter our array by burgers or by a cheap price… but what if you want cheap burgers? One option is to simply chain to filters together.

const cheapBurgers = restaurants.filter(isCheap).filter(isBurger);

Another option is to „compose” the two predicates into a single one.

const isCheapBurger = restaurant => isCheap(restaurant) && isBurger(restaurant);
const isCheapPizza = restaurant => isCheap(restaurant) && isPizza(restaurant);

Look at all of that repeated code. We can definitely wrap this into a new function!

const both = (predicate1, predicate2) => value =>
  predicate1(value) && predicate2(value);

const isCheapBurger = both(isCheap, isBurger);
const isCheapPizza = both(isCheap, isPizza);

const cheapBurgers = restaurants.filter(isCheapBurger);
const cheapPizza = restaurants.filter(isCheapPizza);

What if you are fine with either pizza or burgers?

const either = (predicate1, predicate2) => value =>
  predicate1(value) || predicate2(value);

const isDelicious = either(isBurger, isPizza);
const deliciousFood = restaurants.filter(isDelicious);

This is a step in the right direction, but what if you have more than two foods you’d like to include? This isn’t a very scalable approach. There are two built-in array methods that come in handy here. .every and .some are both predicate methods that also accept predicates. .every checks if each member of an array passes a predicate, while .some checks to see if any member of an array passes a predicate.

const isDelicious = restaurant =>
  [isPizza, isBurger, isBbq].some(predicate => predicate(restaurant));

const isCheapAndDelicious = restaurant =>
  [isDelicious, isCheap].every(predicate => predicate(restaurant));

And, as always, let’s wrap them up into some useful abstraction.

const isEvery = predicates => value =>
  predicates.every(predicate => predicate(value));

const isAny = predicates => value =>
  predicates.some(predicate => predicate(value));

const isDelicious = isAny([isBurger, isPizza, isBbq]);
const isCheapAndDelicious = isEvery([isCheap, isDelicious]);

isEvery and isAny both accept an array of predicates and return a single predicate.

Since all of these predicates are easily created by higher order functions, it isn’t too difficult to create and apply these predicates based on a user’s interaction. Taking all of the lessons we have learned, here is an example of an app that searches restaurants by applying filters based on button clicks.

See the Pen .filter – dynamic filters by Adam Giese (@AdamGiese) on CodePen.

Wrapping up

Filters are an essential part of JavaScript development. Whether you’re sorting out bad data from an API response or responding to user interactions, there are countless times when you would want a subset of an array’s values. I hope this overview helped with ways that you can manipulate predicates to write more readable and maintainable code.

The post Level up your .filter game appeared first on CSS-Tricks.

Working with refs in React

Post pobrano z: Working with refs in React

Refs make it possible to access DOM nodes directly within React. This comes in handy in situations where, just as one example, you want to change the child of a component. Let’s say you want to change the value of an <input> element, but without using props or re-rendering the whole component.

That’s the sort of thing refs are good for and what we’ll be digging into in this post.

How to create a ref

createRef() is a new API that shipped with React 16.3. You can create a ref by calling React.createRef() and attaching a React element to it using the ref attribute on the element.

class Example extends React.Component {
  constructor(props) {
    super(props)

    // Create the ref
    this.exampleRef = React.createRef()
  }

  render() {
    return (
      <div>
        // Call the ref with the `ref` attribute
        <input type="text" ref={this.exampleRef} />
      </div>
    )
  }
}

We can „refer” to the node of the ref created in the render method with access to the current attribute of the ref. From the example above, that would be this.exampleRef.current.

Here’s an example:

See the Pen React Ref – createRef by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

class App extends React.Component {
  constructor(props) {
    super(props)
    
    // Create the ref
    this.textInput = React.createRef();
    this.state = {
      value: ''
    }
  }
  
  // Set the state for the ref
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: this.textInput.current.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - createRef</h1>
        // This is what will update
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          // Call the ref on <input> so we can use it to update the <h3> value
          <input type="text" ref={this.textInput} />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}
How a conversation between a child component and an element containing the ref might go down.

This is a component that renders some text, an input field and a button. The ref is created in the constructor and then attached to the input element when it renders. When the button is clicked, the value submitted from the input element (which has the ref attached) is used to update the state of the text (contained in an H3 tag). We make use of this.textInput.current.value to access the value and the new state is then rendered to the screen.

Passing a callback function to ref

React allows you to create a ref by passing a callback function to the ref attribute of a component. Here is how it looks:

<input type="text" ref={element => this.textInput = element} />

The callback is used to store a reference to the DOM node in an instance property. When we want to make use of this reference, we access it using:

this.textInput.value

Let’s see how that looks in the same example we used before.

See the Pen React Ref – Callback Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

class App extends React.Component {
    state = {
    value: ''
  }
  
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: this.textInput.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - Callback Ref</h1>
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          <input type="text" ref={element => this.textInput = element} />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

When you make use of callback like we did above, React will call the ref callback with the DOM node when the component mounts, when the component un-mounts, it will call it with null.

It is also possible to pass ref from a parent component to a child component using callbacks.

See the Pen React Ref – Callback Ref 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Let’s create our „dumb” component that will render a simple input:

const Input = props => {
  return (
    <div>
      <input type="text" ref={props.inputRef} />
    </div>
  );
};

This component is expecting inputRef props from its parent component which is then used to create a ref to the DOM node.

Here’s the parent component:

class App extends React.Component {
  state = {
    value: ''
  };

  handleSubmit = event => {
    this.setState({ value: this.inputElement.value });
  };

  render() {
    return (
      <div>
        <h1>React Ref - Callback Ref</h1>
        <h3>Value: {this.state.value}</h3>
        <Input inputRef={el => (this.inputElement = el)} />
        <button onClick={this.handleSubmit}>Submit</button>
      </div>
    );
  }
}

In the App component, we want to obtain the text that is entered in the input field (which is in the child component) so we can render it. The ref is created using a callback like we did in the first example of this section. The key lies in how we access the DOM of the input element in the Input component from the App component. If you look closely, we access it using this.inputElement. So, when updating the state of value in the App component, we get the text that was entered in the input field using this.inputElement.value.

The ref attribute as a string

This is the old way of creating a ref and it will likely be removed in a future release because of some issues associated with it. The React team advises against using it, going so far as to label it as „legacy” in the documentation. We’re including it here anyway because there’s a chance you could come across it in a codebase.

See the Pen React Ref – String Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Going back to our example of an input whose value is used to update text value on submit:

class App extends React.Component {
    state = {
    value: ''
  }
  
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: this.refs.textInput.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - String Ref</h1>
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          <input type="text" ref="textInput" />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

The component is initialized and we start with a default state value set to an empty string (value='’). The component renders the text and form, as usual and, like before, the H3 text updates its state when the form is submitted with the contents entered in the input field.

We created a ref by setting the ref prop of the input field to textInput. That gives us access to the value of the input in the handleSubmit() method using this.refs.textInput.value.

Forwarding a ref from one component to another

**Ref forwarding is the technique of passing a ref from a component to a child component by making use of the React.forwardRef() method.

See the Pen React Ref – forward Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Back to our running example of a input field that updates the value of text when submitted:

class App extends React.Component {
    constructor(props) {
      super(props)
      this.inputRef = React.createRef();
      this.state = {
        value: ''
      }
    }
  
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: this.inputRef.current.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - createRef</h1>
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          <Input ref={this.inputRef} />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

We’ve created the ref in this example with inputRef, which we want to pass to the child component as a ref attribute that we can use to update the state of our text.

const Input = React.forwardRef((props, ref) => (
  <input type="text" ref={ref} />
));

Here is an alternative way to do it by defining the ref outside of the App component:

const Input = React.forwardRef((props, ref) => (
  <input type="text" ref={ref} />
));

const inputRef = React.createRef();

class App extends React.Component {
    constructor(props) {
      super(props)
      
      this.state = {
        value: ''
      }
    }
  
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: inputRef.current.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - createRef</h1>
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          <Input ref={inputRef} />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

Using ref for form validation

We all know that form validation is super difficult but something React is well-suited for. You know, things like making sure a form cannot be submitted with an empty input value. Or requiring a password with at least six characters. Refs can come in handy for these types of situations.

See the Pen React ref Pen – validation by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

class App extends React.Component {
  constructor(props) {
    super(props);

    this.username = React.createRef();
    this.password = React.createRef();
    this.state = {
      errors: []
    };
  }

  handleSubmit = (event) => {
    event.preventDefault();
    const username = this.username.current.value;
    const password = this.password.current.value;
    const errors = this.handleValidation(username, password);

    if (errors.length > 0) {
      this.setState({ errors });
      return;
    }
    // Submit data
  };

  handleValidation = (username, password) => {
    const errors = [];
    // Require username to have a value on submit
    if (username.length === 0) {
      errors.push("Username cannot be empty");
    }
    
    // Require at least six characters for the password
    if (password.length < 6) {
      errors.push("Password should be at least 6 characters long");
    }
    
    // If those conditions are met, then return error messaging
    return errors;
  };

  render() {
    const { errors } = this.state;
    return (
      <div>
        <h1>React Ref Example</h1>
        <form onSubmit={this.handleSubmit}>
          // If requirements are not met, then display errors
          {errors.map(error => <p key={error}>{error}</p>)}
          <div>
            <label>Username:</label>
            // Input for username containing the ref
            <input type="text" ref={this.username} />
          </div>
          <div>
            <label>Password:</label>
            // Input for password containing the ref
            <input type="text" ref={this.password} />
          </div>
          <div>
            <button>Submit</button>
          </div>
        </form>
      </div>
    );
  }
}

We used the createRef() to create refs for the inputs which we then passed as parameters to the validation method. We populate the errors array when either of the input has an error, which we then display to the user.

That’s a ref… er, a wrap!

Hopefully this walkthrough gives you a good understanding of how powerful refs can be. They’re an excellent way to update part of a component without the need to re-render the entire thing. That’s convenient for writing leaner code and getting better performance.

At the same time, it’s worth heeding the advice of the React docs themselves and avoid using ref too much:

Your first inclination may be to use refs to „make things happen” in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to „own” that state is at a higher level in the hierarchy.

Get it? Got it? Good.

The post Working with refs in React appeared first on CSS-Tricks.

Using data in React with the Fetch API and axios

Post pobrano z: Using data in React with the Fetch API and axios

If you are new to React, and perhaps have only played with building to-do and counter apps, you may not yet have run across a need to pull in data for your app. There will likely come a time when you’ll need to do this, as React apps are most well suited for situations where you’re handling both data and state.

The first set of data you may need to handle might be hard-coded into your React application, like we did for this demo from our Error Boundary tutorial:

See the Pen error boundary 0 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

What if you want to handle data from an API? That’s the purpose of this tutorial. Specifically, we’ll make use of the Fetch API and axios as examples for how to request and use data.

The Fetch API

The Fetch API provides an interface for fetching resources. We’ll use it to fetch data from a third-party API and see how to use it when fetching data from an API built in-house.

Using Fetch with a third-party API

See the Pen React Fetch API Pen 1 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

We will be fetching random users from JSONPlaceholder, a fake online REST API for testing. Let’s start by creating our component and declaring some default state.

class App extends React.Component {
  state = {
    isLoading: true,
    users: [],
    error: null
  }

  render() {
    <React.Fragment>
    </React.Fragment>
  }
}

There is bound to be a delay when data is being requested by the network. It could be a few seconds or maybe a few milliseconds. Either way, during this delay, it’s good practice to let users know that something is happening while the request is processing.

To do that we’ll make use of isLoading to either display the loading message or the requested data. The data will be displayed when isLoading is false, else a loading message will be shown on the screen. So the render() method will look like this:

render() {
  const { isLoading, users, error } = this.state;
  return (
    <React.Fragment>
      <h1>Random User</h1>
      // Display a message if we encounter an error
      {error ? <p>{error.message}</p> : null}
      // Here's our data check
      {!isLoading ? (
        users.map(user => {
          const { username, name, email } = user;
          return (
            <div key={username}>
              <p>Name: {name}</p>
              <p>Email Address: {email}</p>
              <hr />
            </div>
          );
        })
      // If there is a delay in data, let's let the user know it's loading
      ) : (
        <h3>Loading...</h3>
      )}
    </React.Fragment>
  );
}

The code is basically doing this:

  1. De-structures isLoading, users and error from the application state so we don’t have to keep typing this.state.
  2. Prints a message if the application encounters an error establishing a connection
  3. Checks to see if data is loading
  4. If loading is not happening, then we must have the data, so we display it
  5. If loading is happening, then we must still be working on it and display „Loading…” while the app is working

For Steps 3-5 to work, we need to make the request to fetch data from an API. This is where the JSONplaceholder API will come in handy for our example.

fetchUsers() {
  // Where we're fetching data from
  fetch(`https://jsonplaceholder.typicode.com/users`)
    // We get the API response and receive data in JSON format...
    .then(response => response.json())
    // ...then we update the users state
    .then(data =>
      this.setState({
        users: data,
        isLoading: false,
      })
    )
    // Catch any errors we hit and update the app
    .catch(error => this.setState({ error, isLoading: false }));
}

We create a method called fetchUser() and use it to do exactly what you might think: request user data from the API endpoint and fetch it for our app. Fetch is a promise-based API which returns a response object. So, we make use of the json() method to get the response object which is stored in data and used to update the state of users in our application. We also need to change the state of isLoading to false so that our application knows that loading has completed and all is clear to render the data.

The fact that Fetch is promise-based means we can also catch errors using the .catch() method. Any error encountered is used a value to update our error’s state. Handy!

The first time the application renders, the data won’t have been received — it can take seconds. We want to trigger the method to fetch the users when the application state can be accessed for an update and the application re-rendered. React’s componentDidMount() is the best place for this, so we’ll place the fetchUsers() method in it.

componentDidMount() {
  this.fetchUsers();
}

Using Fetch With Self-Owned API

So far, we’ve looked at how to put someone else’s data to use in an application. But what if we’re working with our own data in our own API? That’s what we’re going to cover right now.

See the Pen React Fetch API Pen 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

I built an API which is available on GitHub. The JSON response you get has been placed on AWS — that’s what we will use for this tutorial.

As we did before, let’s create our component and set up some default state.

class App extends React.Component {
  state = {
    isLoading: true,
    posts: [],
    error: null
  }

  render() {
    <React.Fragment>
    </React.Fragment>
  }
}

Our method for looping through the data will be different from the one we used before but only because of the data’s structure, which is going to be different. You can see the difference between our data structure here and the one we obtained from JSONPlaceholder.

Here is how the render() method will look like for our API:

render() {
  const { isLoading, posts, error } = this.state;
  return (
    <React.Fragment>
      <h1>React Fetch - Blog</h1>
      <hr />
      {!isLoading ? Object.keys(posts).map(key => <Post key={key} body={posts[key]} />) : <h3>Loading...</h3>}
    </React.Fragment>
  );
}

Let’s break down the logic

{
  !isLoading ? 
  Object.keys(posts).map(key => <Post key={key} body={posts[key]} />) 
  : <h3>Loading...</h3>
}

When isLoading is not true, we return an array, map through it and pass the information to the Post component as props. Otherwise, we display a „Loading…” message while the application is at work. Very similar to before.

The method to fetch posts will look like the one used in the first part.

fetchPosts() {
  // The API where we're fetching data from
  fetch(`https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json`)
    // We get a response and receive the data in JSON format...
    .then(response => response.json())
    // ...then we update the state of our application
    .then(
      data =>
        this.setState({
          posts: data,
          isLoading: false,
        })
    )
    // If we catch errors instead of a response, let's update the app
    .catch(error => this.setState({ error, isLoading: false }));
}

Now we can call the fetchPosts method inside a componentDidMount() method

componentDidMount() {
  this.fetchPosts();
}

In the Post component, we map through the props we received and render the title and content for each post:

const Post = ({ body }) => {
  return (
    <div>
      {body.map(post => {
        const { _id, title, content } = post;
        return (
          <div key={_id}>
            <h2>Using data in React with the Fetch API and axios</h2>
            <p>{content}</p>
            <hr />
          </div>
        );
      })}
    </div>
  );
};

There we have it! Now we know how to use the Fetch API to request data from different sources and put it to use in an application. High fives. ✋

axios

OK, so we’ve spent a good amount of time looking at the Fetch API and now we’re going to turn our attention to axios.

Like the Fetch API, axios is a way we can make a request for data to use in our application. Where axios shines is how it allows you to send an asynchronous request to REST endpoints. This comes in handy when working with the REST API in a React project, say a headless WordPress CMS.

There’s ongoing debate about whether Fetch is better than axios and vice versa. We’re not going to dive into that here because, well, you can pick the right tool for the right job. If you’re curious about the points from each side, you can read here and here.

Using axios with a third-party API

See the Pen React Axios 1 Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Like we did with the Fetch API, let’s start by requesting data from an API. For this one, we’ll fetch random users from the Random User API.

First, we create the App component like we’ve done it each time before:

class App extends React.Component {
  state = {
    users: [],
    isLoading: true,
    errors: null
  };

  render() {
    return (
      <React.Fragment>
      </React.Fragment>
    );
  }
}

The idea is still the same: check to see if loading is in process and either render the data we get back or let the user know things are still loading.

To make the request to the API, we’ll need to create a function. We’ll call the function getUsers(). Inside it, we’ll make the request to the API using axios. Let’s see how that looks like before explaining further.

getUsers() {
  // We're using axios instead of Fetch
  axios
    // The API we're requesting data from
    .get("https://randomuser.me/api/?results=5")
    // Once we get a response, we'll map the API endpoints to our props
    .then(response =>
      response.data.results.map(user => ({
        name: `${user.name.first} ${user.name.last}`,
        username: `${user.login.username}`,
        email: `${user.email}`,
        image: `${user.picture.thumbnail}`
      }))
    )
    // Let's make sure to change the loading state to display the data
    .then(users => {
      this.setState({
        users,
        isLoading: false
      });
    })
    // We can still use the `.catch()` method since axios is promise-based
    .catch(error => this.setState({ error, isLoading: false }));
}

Quite different from the Fetch examples, right? The basic structure is actually pretty similar, but now we’re in the business of mapping data between endpoints.

The GET request is passed from the API URL as a parameter. The response we get from the API contains an object called data and that contains other objects. The information we want is available in data.results, which is an array of objects containing the data of individual users.

Here we go again with calling our method inside of the componentDidMount() method:

componentDidMount() {
  this.getUsers();
}

Alternatively, you can do this instead and basically combine these first two steps:

componentDidMount() {
  axios
    .get("https://randomuser.me/api/?results=5")
    .then(response =>
      response.data.results.map(user => ({
        name: `${user.name.first} ${user.name.last}`,
        username: `${user.login.username}`,
        email: `${user.email}`,
        image: `${user.picture.thumbnail}`
      }))
    )
    .then(users => {
      this.setState({
        users,
        isLoading: false
      });
    })
    .catch(error => this.setState({ error, isLoading: false }));
}

If you are coding locally from your machine, you can temporarily edit the getUsers() function to look like this:

getUsers() {
  axios
    .get("https://randomuser.me/api/?results=5")
    .then(response => console.log(response))
    .catch(error => this.setState({ error, isLoading: false }));
}

Your console should get something similar to this:

We map through the results array to obtain the information we need for each user. The array of users is then used to set a new value for our users state. With that done, we can then change the value of isLoading.

By default, isLoading is set to true. When the state of users is updated, we want to change the value of isLoading to false since this is the cue our app is looking for to make the switch from „Loading…” to rendered data.

render() {
  const { isLoading, users } = this.state;
  return (
    <React.Fragment>
      <h2>Random User</h2>
      <div>
        {!isLoading ? (
          users.map(user => {
            const { username, name, email, image } = user;
            return (
              <div key={username}>
                <p>{name}</p>
                <div>
                  <img src={image} alt={name} />
                </div>
                <p>{email}</p>
                <hr />
              </div>
            );
          })
        ) : (
          <p>Loading...</p>
        )}
      </div>
    </React.Fragment>
  );
}

If you log the users state to the console, you will see that it is an array of objects:

The empty array shows the value before the data was obtained. The returned data contains only the name, username, email address and image of individual users because those are the endpoints we mapped out. There is a lot more data available from the API, of course, but we’d have to add those to our getUsers method.

Using axios with your own API

See the Pen React Axios 2 Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

You have seen how to use axios with a third-party API but we can look at what it’s like to request data from our own API, just like we did with the Fetch API. In fact, let’s use same JSON file we used for Fetch so we can see the difference between the two approaches.

Here is everything put together:

class App extends React.Component {
  // State will apply to the posts object which is set to loading by default
  state = {
    posts: [],
    isLoading: true,
    errors: null
  };
  // Now we're going to make a request for data using axios
  getPosts() {
    axios
      // This is where the data is hosted
      .get("https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json")
      // Once we get a response and store data, let's change the loading state
      .then(response => {
        this.setState({
          posts: response.data.posts,
          isLoading: false
        });
      })
      // If we catch any errors connecting, let's update accordingly
      .catch(error => this.setState({ error, isLoading: false }));
  }
  // Let's our app know we're ready to render the data
  componentDidMount() {
    this.getPosts();
  }
  // Putting that data to use
  render() {
    const { isLoading, posts } = this.state;
    return (
      <React.Fragment>
        <h2>Random Post</h2>
        <div>
          {!isLoading ? (
            posts.map(post => {
              const { _id, title, content } = post;
              return (
                <div key={_id}>
                  <h2>Using data in React with the Fetch API and axios</h2>
                  <p>{content}</p>
                  <hr />
                </div>
              );
            })
          ) : (
            <p>Loading...</p>
          )}
        </div>
      </React.Fragment>
    );
  }
}

The main difference between this method and using axios to fetch from a third-party is how the data is formatted. We’re getting straight-up JSON this way rather than mapping endpoints.

The posts data we get from the API is used to update the value of the component’s posts state. With this, we can map through the array of posts in render(). We then obtain the id, title and content of each post using ES6 de-structuring, which is then rendered to the user.

Like we did before, what is displayed depends on the value of isLoading. When we set a new state for posts using the data obtained from the API, we had to set a new state for isLoading, too. Then we can finally let the user know data is loading or render the data we’ve received.

async and await

Another thing the promise-based nate of axios allows us to do is take advantage of is async and await . Using this, the getPosts() function will look like this.

async getPosts() {
  const response = await axios.get("https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json");
  try {
    this.setState({
      posts: response.data.posts,
      isLoading: false
    });
  } catch (error) {
    this.setState({ error, isLoading: false });
  }
}

Base instance

With axios, it’s possible to create a base instance where we drop in the URL for our API like so:

const api = axios.create({
  baseURL: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json"
});

…then make use of it like this:

async getPosts() {
  const response = await api.get();
  try {
    this.setState({
      posts: response.data.posts,
      isLoading: false
    });
  } catch (error) {
    this.setState({ error, isLoading: false });
  }
}

Simply a nice way of abstracting the API URL.

Now, data all the things!

As you build React applications, you will run into lots of scenarios where you want to handle data from an API. Hopefully you know feel armed and ready to roll with data from a variety of sources with options for how to request it.

Want to play with more data? Sarah recently wrote up the steps for creating your own serverless API from a list of public APIs.

The post Using data in React with the Fetch API and axios appeared first on CSS-Tricks.

VS Code extensions for the discerning developer palate

Post pobrano z: VS Code extensions for the discerning developer palate

I am a VS Code extension snob. I like to hunt down the most obscure extensions for VS Code — the ones that nobody knows about — and impress people at parties with my knowledge of finely aged and little-known VS Code capabilities… then watch as they look around desperately for someone else to talk to. It’s like the “Sideways” of VS Code.

In my endless pursuit of the perfect VS Code setup, I reached out to my colleagues here on the Azure team and asked them to share their favorite extension in their own words. So clear your pallet and breathe in the aromatic flavors of productivity; I am your VS Code Extension Sommelier.


Christina Warren – Settings Sync

I cannot live without this extension. If you use multiple machines (especially on multiple platforms, where a sym-linked Dropbox folder won’t really work), this extension is for you. It syncs your extensions, settings file, keybinding file, launch file, snippets folder, extension settings, and workspaces folder. This means that when you login to a new machine, you can quickly get back to work with your own settings and workflow tools in just a few minutes.

👉 Get Settings SyncExtension


Shayne Boyer – Paste JSON as Code

Consuming an endpoint that produces JSON is like breathing, but no one wants to choke on the hand cranking of an object by looking back and forth between JSON and the target language. This is a long loved feature in Visual Studio for .NET developers, but now you too can copy the JSON and paste that class into the editor as your target language and save a ton of time. Currently supports C#, Go, C++, Java, TypeScript, Swift, Elm, and JSON Schema.

👉 Get Paste JSON as Code Extension


Jeremy Likness – Spell Right

I find myself authoring blog posts, articles, and documentation almost every day. After embracing the power of Markdown (it is, after all, what is used to drive our own https://docs.com), I began writing my content in Visual Studio Code. It has a built-in preview window so I can edit the Markdown source and see the rendered result side-by-side. As much as I’ve written over the years, mastering the fine art of spelling still eludes me. Maybe it’s because I’m lazy, and this extension doesn’t help at all. With Spell Right, I get to reunite with my same favorite red squiggly lines that I first met in Word. It does a great job of catching spelling mistakes in real time, then illuminates my mistakes with a handy light bulb with alternative suggestions that give me single-click corrections. It enables me to be highly productive and look like I know what I’m doing. I recommend this for anyone who uses Code to write.

👉 Get Spell Right Extension


Aaron Wislang – Go

I live in VS Code and use it for everything from code and content to its integrated terminal. This extension enables first-class support for IntelliSense, testing, refactoring and more, making Code the best place to me to write Go. And it turns out I’m not the only one who thinks so; it helped to make Code the most popular editor amongst Gophers, just ahead of vim-go, as of the Go 2017 Survey!

👉 Get Go Extension


Cecil Phillip – C# Extensions

This extension was created by one of our community members, and it’s a great companion to the official C# extension from Microsoft. The “New Class|Interface” actions make it easy to add new types, and takes some of the hassle out of fixing up the namespaces. It also comes with a few interesting refactorings like „Initialize fields from constructors,” which I use pretty often. Whenever I’m teaching a C# course, I always have my students that are using Visual Studio Code install this extension.

👉 Get C# Extension


Brian Clark – VS Live Share

Pair programming just got way better. Gone are the days where I need to set up screen sharing to review code with coworkers. Instead I fire up a live share session, invite the other party and we can all view and edit code directly from our editors. I’ve used it in a situations where I review someone else’s C# code on my machine while it runs on THEIR machine! I didn’t have anything installed on my Mac for C# and yet I could debug their code!

👉 Get VS Live Share Extension


David Smith – Rewrap

I write a lot of text, and sometimes I just want (or need) to write in a plain-text environment. Easy reflowing of text is essential. (Surprised this isn’t built in, in fact.)

👉 Get Rewrap Extension


Anthony Chu – Git Lens

At a glance, GitLens shows me contextual information from Git about the line of code and the file I’m working in. It adds some useful commands to view history and diffs, search commits, and browse local and remote branches… all without leaving VS Code.

👉 Get Git Lens Extension


Asim Hussain – AsciiDoc

I used to write with Markdown, we all make mistakes. The solution to my Markdown mistake is AsciiDoc, especially if you write a lot of code snippets as I do. Out of the box it let’s you add line numbers, annotate and highlight lines and provides an incredible amount of customization. Plus, as a bonus it also can convert your blog posts into PDFs, ePubs, Mobis which is perfect for ebooks.

Once you start with AsciiDoc it’s hard to go back to Markdown and this plugin lets you preview your AsciiDoc right inside the editor.

👉 Get AsciiDoctor Extension


Seth Juarez) – VS Code Tools For AI

With Visual Studio Code Tools for AI, I can finally use machines I need but might never have access to in order to build the next Skynet — all within the comfort of my favorite lightweight editor. We live in amazing times, friends…

👉 Get VS Code Tools For AI Extension


Alena Hall – Ionide

Ionide is an awesome Visual Studio Code extension for cross-platform F# development. It’s open-source and it was created by the F# Community. I use it every day on multiple machines I have. It runs perfectly on both my Mac and Linux machines. Ionide conveniently integrates with Paket, Project Scaffold, and you can experiment away as much as you want in F# Interactive!

👉 Get Ionide Extension


Matt Soucoup – VSCodeVim

There’s an old joke that goes: “How do you know if a developer uses vim? They’ll tell you.” Well, I use vim! But… I want more. I want to tell everybody I use vim and I want to use all the great features and extensions that VS Code offers. (I mean, look at the list here!) So that’s where VSCodeVim saves the day for me. It puts a full-featured vim emulator into my VS Code editor, letting me edit files super fast by typing esoteric commands like h, 10 k, i, and u (lots and lots of u) and I still get to use all the awesome features of VS Code.

👉 Get VSCodeVim Extension


John Papa – Docker

If you like it put a container on it. Yeah, containers are the latest craze, but in a constantly evolving containerization world, it’s nice to have great tooling make it easy to use containers. Enter the Docker extension for VS Code. It handles the complete container development and deployment lifecycle! Start by generating docker files to your project, create an image, run it, and even push it to a container registry. If you’re like me, you like to make sure you still have complete control over your code and your app, even when they are inside of containers. Accessing the files, showing logs, and debugging the running container are all essential tools for development. This extension puts all of this within your reach without having to learn the docker command line!

👉 Get Docker Extension


Suz Hinton – Arduino

My favorite extension for VS Code is Arduino. I’m pretty sure anyone who knows me wouldn’t be surprised about that. Traditionally, developing programs for Arduino-compatible micro-controller boards has been done in the Arduino IDE. It’s a powerful program which smooths over the compilation and uploading experiences for dozens of boards. It is, however, not a full code IDE. It’s missing some of the features you love, such as autocomplete, a file tree, and fine-grained tuning of the editor itself.

The good news is that the Arduino extension allows you to finally develop freely for all of your favorite micro-controller boards without leaving VS Code!

Here are some of my favorite things about the extension:

  1. It’s open source! So reporting bugs and contributing improvements is a straightforward experience.
  2. The Command Palette integration is so handy. Compile and upload your code to an Arduino with one simple shortcut.
  3. Access all the great tools from the Arduino IDE right in VS Code. Yes, that even means board / library management and the serial monitor!
  4. Scaffolding brand new Arduino projects is a command away. No more copy + pasting older project directories to get set up.

👉 Get Arduino Extension


Burke Holland – Azure Functions

Serverless is like Hansel — so hot right now. But Serverless shouldn’t be a black box. The Azure Functions extensions for VS Code puts Serverless right inside of the editor. I love it because it lets me create new Serverless projects, new functions for all of the available trigger types (http, timer, blob storage, etc.), and most importantly, I can run them locally and debug them. Not that I would ever need to debug. My code is always perfect.

👉 Get Azure Functions Extension

The post VS Code extensions for the discerning developer palate appeared first on CSS-Tricks.

​Experience a Simpler Cloud Computing Platform with DigitalOcean

Post pobrano z: ​Experience a Simpler Cloud Computing Platform with DigitalOcean

(This is a sponsored post.)

From deploying static sites and blogging platforms to managing multiple client websites, DigitalOcean provides a flexible platform for developers and their teams to deliver an unparalleled end-user experience with a lightning-fast network, pre-configured applications, and a 99.99% uptime SLA. Simply let us know your needs and our solutions engineers will provide the best options available.

Direct Link to Article — Permalink

The post ​Experience a Simpler Cloud Computing Platform with DigitalOcean appeared first on CSS-Tricks.

On Switching Code Editors

Post pobrano z: On Switching Code Editors

I’m sure a lot of you are like me and have switched code editors a number of times. I think my first major editor was Coda. Then I moved to TextMate when I started working primarily on local. Then Sublime Text. And, most recently, VS Code. I bet your journey was different. I know lots of folks that quite love Atom, Brackets, WebStorm, and even BBedit. You do you!

For me, that’s four changes in a dozen years, or a change every three years. Moving isn’t something I do quickly. Here’s a collection of thoughts around the idea of changing editors.

When moving, I have to take time to make sure it works pretty much like the old one.

Otherwise, I’ll just end up disliking it to the point that I switch back a day or two later. It’s happened to me every time I switch. I have little false-starts after a switch where I go back to the old editor because something bugged me too much or it affected my productivity and I gave up. (Now that I know I do this, I don’t let a single false-start make me feel like the editor I’m trying is never a possibility.)

My latest switch was from Sublime Text to VS Code. I’d become become very used to the key bindings (e.g. CMD+Shift+d to duplicate a line) in Sublime Text, so thankfully VS Code has that covered.

I was amazed to find even my VIM friends happy and comfortable in VS Code. (Fun fact: we have key bindings choices in CodePen, too.)

Nothing can be too obnoxious.

In one of my first attempts at switching, I found the UI in VS code to be too cluttered and the find-in-project feature to be a little slow and awkward. Those things bugged me to the point they caused false-starts and I went back to Sublime Text.

On this last switch attempt (my 3rd or 4th maybe?) I finally have a theme I quite like (customized a smidge), found some settings to clean up the UI (I removed the whitespace indicators which were overwhelming to me, and overrode that intense blue footer with something more chill).

In working with find-in-project a bit more, I’ve grown to get used to it. I finally might even like it more than Sublime, as the sidebar approach is more consistent than opening a new tab of results. I find the jump-to-line feature works more consistently and search feels more the first-class citizen it should be.

Another factor would be Emmet. I’m quite sure that I’d be too annoyed writing HTML and CSS in an editor without Emmet, and I’d just give up and use something else that had it. Emmet isn’t even an extension in VS Code, it’s built in.

I’m cool with making small changes after a successful switch.

Once I’ve actually done it, and made the switch to full-time use, then I can make some changes. Maybe I’ll learn some new key commands. Maybe I’ll add an extension that adds functionality I’ve never had before. Maybe the editor affects some workflow thing in a way I’m now willing to try.

The new editor better have some killer feature that incentivizes me to switch.

If it’s exactly the same, why bother?

The new editor needs to be faster (or feel just as fast). Or should look better. Or it should have some awesome package that is only available on it. Ideally all of that.

In this recent switch for me, it was GitLens.

How cool is that?

It ought to have a plugin architecture.

Meaning that anyone can write code to extend the editor. I’m fairly certain that having a plugin architecture (plus a healthy amount of community momentum) is what is key to any editor’s success. Sublime’s package manager, and the subsequent built-in packages feature of VS Code, seem crucial. Not only for functionality but even just for the look of the editor. I wouldn’t use an editor with a look I hate, but I’d be tempted to if the functionality was awesome. That’s a non-issue with a plugin-based editor. Open source seems smart as well.

Careful for those GOTCHAs.

One of those was spell-checking for me. In Sublime Text, it was an option under the View menu. I had it checked all the time, and it spell-checked all the time.

This is not a thing in VS Code. That was dangerous after switching because, who knows, I may have been committing typos all over the place. Fortunately, this extension seems to be doing the trick. Thank jeepers for extensions!

Your thoughts!

I thought it might be interesting to ask what y’all think about when switching code editors. There were lots of responses. I picked out as many as I could here and focused on one thing that you mentioned.

The post On Switching Code Editors appeared first on CSS-Tricks.

What bit of advice would you share with someone new to your field?

Post pobrano z: What bit of advice would you share with someone new to your field?

The most FA of all the FAQs.

Here’s Laura Kalbag:

Find what you love. Don’t worry about needing to learn every language, technique or tool. Start with what interests you, and carve your own niche. And then use your powers for good!

And my own:

Buy a domain name. Figure out how to put an HTML file up there. Isn’t that a powerful feeling? Now you’ve got table stakes. Build something.

Definitely, go read other A Book Apart author answers because they are all great. My other favorite is just three words.

Direct Link to Article — Permalink

The post What bit of advice would you share with someone new to your field? appeared first on CSS-Tricks.

Automate Your Workflow with Node

Post pobrano z: Automate Your Workflow with Node

You know those tedious tasks you have to do at work: Updating configuration files, copying and pasting files, updating Jira tickets.

Time adds up after a while. This was very much the case when I worked for an online games company back in 2016. The job could be very rewarding at times when I had to build configurable templates for games, but about 70% of my time was spent on making copies of those templates and deploying re-skinned implementations.

What is a reskin?

The definition of a reskin at the company was using the same game mechanics, screens and positioning of elements, but changing the visual aesthetics such as color and assets. So in the context of a simple game like ‘Rock Paper Scissors,’ we would create a template with basic assets like below.

But when we create a reskin of this, we would use different assets and the game would still work. If you look at games like Candy Crush or Angry Birds, you’ll find that they have many varieties of the same game. Usually Halloween, Christmas or Easter releases. From a business perspective it makes perfect sense.

Now… back to our implementation. Each of our games would share the same bundled JavaScript file, and load in a JSON file that had different content and asset paths. The result?

The good thing about extracting configurable values into a JSON file is that you can modify the properties without having to recompile/build the game again. Using Node.js and the original breakout game created by Mozilla, we will make a very simple example of how you can create a configurable template, and make releases from it by using the command line.

Our game

This is the game we’ll be making. Reskins of MDN Breakout, based on the existing source code.

Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.

The primary color will paint the text, paddle, ball and blocks, and the secondary color will paint the background. We will proceed with an example of a dark blue background and a light sky blue for the foreground objects.

Prerequisites

You will need to ensure the following:

We have tweaked the original Firefox implementation so that we first read in the JSON file and then build the game using HTML Canvas. The game will read in a primary color, and a secondary color from our game.json file.

{
  "primaryColor": "#fff",
  "secondaryColor": "#000"
}

We will be using example 20 from the book Automating with Node.js. The source code can be found here.

Open up a new command line (CMD for Windows, Terminal for Unix-like Operating systems) and change into the following directory once you have cloned the repository locally.

$ cd nobot-examples/examples/020

Remember the game server should be running in a separate terminal.

Our JSON file sits beside an index.html file inside a directory called template. This is the directory that we will copy from whenever we want to do a new release/copy.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Paddle Game</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }
    canvas {
      background: #eee;
      display: block;
      margin: 0 auto;
    }
  </style>
</head>
<body>
  <canvas id="game" width="480" height="320"></canvas>
  <script type="text/javascript" src="../../core/game-1.0.0.js"></script>
</body>
</html>

You see above that every game we release will point to the same core bundle JavaScript file. Let’s have a look at our JavaScript implementation under the core directory.

Don’t look too much into the mechanics of how the game works, more so how we inject values into the game to make it configurable.

(function boot(document) {
  function runGame(config) {
    const canvas = document.getElementById('game');
    canvas.style.backgroundColor = config.secondaryColor;
    // rest of game source code gets executed... hidden for brevity
    // source can be found here: https://git.io/vh1Te
  }

  function loadConfig() {
    fetch('game.json')
      .then(response => response.json())
      .then(runGame);
  }

  document.addEventListener('DOMContentLoaded', () => {
    loadConfig();
  });
}(document));

The source code is using ES6 features and may not work in older browsers. Run through Babel if this is a problem for you.

You can see that we are waiting for the DOM content to load, and then we are invoking a method called loadConfig. This is going to make an AJAX request to game.json, fetch our JSON values, and once it has retrieved them, it will initiate the game and assign the styles in the source code.

Here is an example of the configuration setting the background color.

const canvas = document.getElementById('game');
canvas.style.backgroundColor = config.secondaryColor; // overriding color here

So, now that we have a template that can be configurable, we can move on to creating a Node.js script that will allow the user to either pass the name of the game and the colors as options to our new script, or will prompt the user for: the name of the game, the primary color, and then the secondary color. Our script will enforce validation to make sure that both colors are in the format of a hex code (e.g. #101b6b).

When we want to create a new game reskin, we should be able to run this command to generate it:

$ node new-reskin.js --gameName='blue-reskin' --gamePrimaryColor='#76cad8' --gameSecondaryColor='#10496b'

The command above will build the game immediately, because it has the three values it needs to release the reskin.

We will create this script new-reskin.js, and this file carries out the following steps:

  1. It will read in the options passed in the command line and store them as variables. Options can be read in by looking in the process object (process.argv).
  2. It will validate the values making sure that the game name, and the colors are not undefined.
  3. If there are any validation issues, it will prompt the user to re-enter it correctly before proceeding.
  4. Now that it has the values, it will make a copy of the template directory and place a copy of it into the releases directory and name the new directory with the name of the game we gave it.
  5. It will then read the JSON file just recently created under the releases directory and override the values with the values we passed (the colors).
  6. At the end, it will prompt the user to see if they would like to open the game in a browser. It adds some convenience, rather than us trying to remember what the URL is.

Here is the full script. We will walk through it afterwards.

require('colors');
const argv = require('minimist')(process.argv.slice(2));
const path = require('path');
const readLineSync = require('readline-sync');
const fse = require('fs-extra');
const open = require('opn');
const GAME_JSON_FILENAME = 'game.json';

let { gameName, gamePrimaryColor, gameSecondaryColor } = argv;

if (gameName === undefined) {
  gameName = readLineSync.question('What is the name of the new reskin? ', {
    limit: input => input.trim().length > 0,
    limitMessage: 'The project has to have a name, try again'
  });
}

const confirmColorInput = (color, colorType = 'primary') => {
  const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
  if (hexColorRegex.test(color)) {
    return color;
  }
  return readLineSync.question(`Enter a Hex Code for the game ${colorType} color `, {
    limit: hexColorRegex,
    limitMessage: 'Enter a valid hex code: #efefef'
  });
};

gamePrimaryColor = confirmColorInput(gamePrimaryColor, 'primary');
gameSecondaryColor = confirmColorInput(gameSecondaryColor, 'secondary');

console.log(`Creating a new reskin '${gameName}' with skin color: Primary: '${gamePrimaryColor}' Secondary: '${gameSecondaryColor}'`);

const src = path.join(__dirname, 'template');
const destination = path.join(__dirname, 'releases', gameName);
const configurationFilePath = path.join(destination, GAME_JSON_FILENAME);
const projectToOpen = path.join('http://localhost:8080', 'releases', gameName, 'index.html');

fse.copy(src, destination)
  .then(() => {
    console.log(`Successfully created ${destination}`.green);
    return fse.readJson(configurationFilePath);
  })
  .then((config) => {
    const newConfig = config;
    newConfig.primaryColor = gamePrimaryColor;
    newConfig.secondaryColor = gameSecondaryColor;
    return fse.writeJson(configurationFilePath, newConfig);
  })
  .then(() => {
    console.log(`Updated configuration file ${configurationFilePath}`green);
    openGameIfAgreed(projectToOpen);
  })
  .catch(console.error);

const openGameIfAgreed = (fileToOpen) => {
  const isOpeningGame = readLineSync.keyInYN('Would you like to open the game? ');
  if (isOpeningGame) {
    open(fileToOpen);
  }
};

At the top of the script, we require the packages needed to carry out the process.

  • colors to be used to signify success or failure using green or red text.
  • minimist to make it easier to pass arguments to our script and to parse them optionally. Pass input without being prompted to enter.
  • path to construct paths to the template and the destination of the new game.
  • readline-sync to prompt user for information if it’s missing.
  • fs-extra so we can copy and paste our game template. An extension of the native fs module.
  • opn is a library that is cross platform and will open up our game in a browser upon completion.

The majority of the modules above would’ve been downloaded/installed when you ran npm install in the root of the nobot-examples repository. The rest are native to Node.

We check if the game name was passed as an option through the command line, and if it hasn’t been, we prompt the user for it.

// name of our JSON file. We store it as a constant
const GAME_JSON_FILENAME = 'game.json';

// Retrieved from the command line --gameName='my-game' etc.
let { gameName, gamePrimaryColor, gameSecondaryColor } = argv;

// was the gameName passed?
if (gameName === undefined) {
  gameName = readLineSync.question('What is the name of the new reskin? ', {
    limit: input => input.trim().length > 0,
    limitMessage: 'The project has to have a name, try again'
  });
}

Because two of our values need to be hex codes, we create a function that can do the check for both colors: the primary and the secondary. If the color supplied by the user does not pass our validation, we prompt for the color until it does.

// Does the color passed in meet our validation requirements?
const confirmColorInput = (color, colorType = 'primary') => {
  const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
  if (hexColorRegex.test(color)) {
    return color;
  }
  return readLineSync.question(`Enter a Hex Code for the game ${colorType} color `, {
    limit: hexColorRegex,
    limitMessage: 'Enter a valid hex code: #efefef'
  });
};

We use the function above to obtain both the primary and secondary colors.

gamePrimaryColor = confirmColorInput(gamePrimaryColor, 'primary');
gameSecondaryColor = confirmColorInput(gameSecondaryColor, 'secondary');

In the next block of code, we are printing to standard output (console.log) to confirm the values that will be used in the process of building the game. The statements that follow are preparing the paths to the relevant files and directories.

The src will point to the template directory. The destination will point to a new directory under releases. The configuration file that will have its values updated will reside under this new game directory we are creating. And finally, to preview our new game, we construct the URL using the path to the local server we booted up earlier on.

console.log(`Creating a new reskin '${gameName}' with skin color: Primary: '${gamePrimaryColor}' Secondary: '${gameSecondaryColor}'`);
const src = path.join(__dirname, 'template');
const destination = path.join(__dirname, 'releases', gameName);
const configurationFilePath = path.join(destination, GAME_JSON_FILENAME);
const projectToOpen = path.join('http://localhost:8080', 'releases', gameName, 'index.html');

In the code following this explanation, we:

  • Copy the template files to the releases directory.
  • After this is created, we read the JSON of the original template values.
  • With the new configuration object, we override the existing primary and secondary colors provided by the user’s input.
  • We rewrite the JSON file so it has the new values.
  • When the JSON file has been updated, we ask the user if they would like to open the new game in a browser.
  • If anything went wrong, we catch the error and log it out.
fse.copy(src, destination)
  .then(() => {
    console.log(`Successfully created ${destination}`green);
    return fse.readJson(configurationFilePath);
  })
  .then((config) => {
    const newConfig = config;
    newConfig.primaryColor = gamePrimaryColor;
    newConfig.secondaryColor = gameSecondaryColor;
    return fse.writeJson(configurationFilePath, newConfig);
  })
  .then(() => {
    console.log(`Updated configuration file ${configurationFilePath}`green);
    openGameIfAgreed(projectToOpen);
  })
  .catch(console.error);

Below is the function that gets invoked when the copying has completed. It will then prompt the user to see if they would like to open up the game in the browser. The user responds with y or n

const openGameIfAgreed = (fileToOpen) => {
  const isOpeningGame = readLineSync.keyInYN('Would you like to open the game? ');
  if (isOpeningGame) {
    open(fileToOpen);
  }
};

Let’s see it in action when we don’t pass any arguments. You can see it doesn’t break, and instead prompts the user for the values it needs.

$ node new-reskin.js
What is the name of the new reskin? blue-reskin
Enter a Hex Code for the game primary color #76cad8
Enter a Hex Code for the game secondary color #10496b
Creating a new reskin 'blue-reskin' with skin color: Primary: '#76cad8' Secondary: '#10496b'
Successfully created nobot-examples\examples\020\releases\blue-reskin
Updated configuration file nobot-examples\examples\020\releases\blue-reskin\game.json
Would you like to open the game? [y/n]: y
(opens game in browser)

My game opens on my localhost server automatically and the game commences, with the new colors. Sweet!

Oh… I’ve lost a life already. Now if you navigate to the releases directory, you will see a new directory called blue-reskin This contains the values in the JSON file we entered during the script execution.

Below are a few more releases I made by running the same command. You can imagine if you were releasing games that could configure different: images, sounds, labels, content and fonts, you would have a rich library of games based on the same mechanics.

Even better, if the stakeholders and designers had all of this information in a Jira ticket, you could integrate the Jira API into the Node script to inject these values in without the user having to provide any input. Winning!


This is one of many examples that can be found in Automating with Node.js. In this book, we will be looking at a more advanced example using „Rock Paper Scissors” as the basis of a build tool created from scratch.

The post Automate Your Workflow with Node appeared first on CSS-Tricks.