de

The Web We Lost: Luke Dorny Redesign

Like 90s hip-hop, The Web We Lost™ retains a near-mystical hold on the hearts and minds of those who were lucky enough to be part of it. Luke Dorny’s recent, lovingly hand-carved redesign of his personal site encompasses several generations of that pioneering creative web. As such, it will repay your curiosity.

The post The Web We Lost: Luke Dorny Redesign appeared first on Zeldman on Web & Interaction Design.




de

Introducing the New React DevTools

We are excited to announce a new release of the React Developer Tools, available today in Chrome, Firefox, and (Chromium) Edge!

What’s changed?

A lot has changed in version 4! At a high level, this new version should offer significant performance gains and an improved navigation experience. It also offers full support for React Hooks, including inspecting nested objects.

Visit the interactive tutorial to try out the new version or see the changelog for demo videos and more details.

Which versions of React are supported?

react-dom

  • 0-14.x: Not supported
  • 15.x: Supported (except for the new component filters feature)
  • 16.x: Supported

react-native

  • 0-0.61: Not supported
  • 0.62: Will be supported (when 0.62 is released)

How do I get the new DevTools?

React DevTools is available as an extension for Chrome and Firefox. If you have already installed the extension, it should update automatically within the next couple of hours.

If you use the standalone shell (e.g. in React Native or Safari), you can install the new version from NPM:

npm install -g react-devtools@^4

Where did all of the DOM elements go?

The new DevTools provides a way to filter components from the tree to make it easier to navigate deeply nested hierarchies. Host nodes (e.g. HTML <div>, React Native <View>) are hidden by default, but this filter can be disabled:

How do I get the old version back?

If you are working with React Native version 60 (or older) you can install the previous release of DevTools from NPM:

npm install --dev react-devtools@^3

For older versions of React DOM (v0.14 or earlier) you will need to build the extension from source:

# Checkout the extension source
git clone https://github.com/facebook/react-devtools

cd react-devtools

# Checkout the previous release branch
git checkout v3

# Install dependencies and build the unpacked extension
yarn install
yarn build:extension

# Follow the on-screen instructions to complete installation

Thank you!

We’d like to thank everyone who tested the early release of DevTools version 4. Your feedback helped improve this initial release significantly.

We still have many exciting features planned and feedback is always welcome! Please feel free to open a GitHub issue or tag @reactjs on Twitter.




de

Building Great User Experiences with Concurrent Mode and Suspense

At React Conf 2019 we announced an experimental release of React that supports Concurrent Mode and Suspense. In this post we’ll introduce best practices for using them that we’ve identified through the process of building the new facebook.com.

This post will be most relevant to people working on data fetching libraries for React.

It shows how to best integrate them with Concurrent Mode and Suspense. The patterns introduced here are based on Relay — our library for building data-driven UIs with GraphQL. However, the ideas in this post apply to other GraphQL clients as well as libraries using REST or other approaches.

This post is aimed at library authors. If you’re primarily an application developer, you might still find some interesting ideas here, but don’t feel like you have to read it in its entirety.

Talk Videos

If you prefer to watch videos, some of the ideas from this blog post have been referenced in several React Conf 2019 presentations:

This post presents a deeper dive on implementing a data fetching library with Suspense.

Putting User Experience First

The React team and community has long placed a deserved emphasis on developer experience: ensuring that React has good error messages, focusing on components as a way to reason locally about app behavior, crafting APIs that are predictable and encourage correct usage by design, etc. But we haven’t provided enough guidance on the best ways to achieve a great user experience in large apps.

For example, the React team has focused on framework performance and providing tools for developers to debug and tune application performance (e.g. React.memo). But we haven’t been as opinionated about the high-level patterns that make the difference between fast, fluid apps and slow, janky ones. We always want to ensure that React remains approachable to new users and supports a variety of use-cases — not every app has to be “blazing” fast. But as a community we can and should aim high. We should make it as easy as possible to build apps that start fast and stay fast, even as they grow in complexity, for users on varying devices and networks around the world.

Concurrent Mode and Suspense are experimental features that can help developers achieve this goal. We first introduced them at JSConf Iceland in 2018, intentionally sharing details very early to give the community time to digest the new concepts and to set the stage for subsequent changes. Since then we’ve completed related work, such as the new Context API and the introduction of Hooks, which are designed in part to help developers naturally write code that is more compatible with Concurrent Mode. But we didn’t want to implement these features and release them without validating that they work. So over the past year, the React, Relay, web infrastructure, and product teams at Facebook have all collaborated closely to build a new version of facebook.com that deeply integrates Concurrent Mode and Suspense to create an experience with a more fluid and app-like feel.

Thanks to this project, we’re more confident than ever that Concurrent Mode and Suspense can make it easier to deliver great, fast user experiences. But doing so requires rethinking how we approach loading code and data for our apps. Effectively all of the data-fetching on the new facebook.com is powered by Relay Hooks — new Hooks-based Relay APIs that integrate with Concurrent Mode and Suspense out of the box.

Relay Hooks — and GraphQL — won’t be for everyone, and that’s ok! Through our work on these APIs we’ve identified a set of more general patterns for using Suspense. Even if Relay isn’t the right fit for you, we think the key patterns we’ve introduced with Relay Hooks can be adapted to other frameworks.

Best Practices for Suspense

It’s tempting to focus only on the total startup time for an app — but it turns out that users’ perception of performance is determined by more than the absolute loading time. For example, when comparing two apps with the same absolute startup time, our research shows that users will generally perceive the one with fewer intermediate loading states and fewer layout changes as having loaded faster. Suspense is a powerful tool for carefully orchestrating an elegant loading sequence with a few, well-defined states that progressively reveal content. But improving perceived performance only goes so far — our apps still shouldn’t take forever to fetch all of their code, data, images, and other assets.

The traditional approach to loading data in React apps involves what we refer to as “fetch-on-render”. First we render a component with a spinner, then fetch data on mount (componentDidMount or useEffect), and finally update to render the resulting data. It’s certainly possible to use this pattern with Suspense: instead of initially rendering a placeholder itself, a component can “suspend” — indicate to React that it isn’t ready yet. This will tell React to find the nearest ancestor <Suspense fallback={<Placeholder/>}>, and render its fallback instead. If you watched earlier Suspense demos this example may feel familiar — it’s how we originally imagined using Suspense for data-fetching.

It turns out that this approach has some limitations. Consider a page that shows a social media post by a user, along with comments on that post. That might be structured as a <Post> component that renders both the post body and a <CommentList> to show the comments. Using the fetch-on-render approach described above to implement this could cause sequential round trips (sometimes referred to as a “waterfall”). First the data for the <Post> component would be fetched and then the data for <CommentList> would be fetched, increasing the time it takes to show the full page.

There’s also another often-overlooked downside to this approach. If <Post> eagerly requires (or imports) the <CommentList> component, our app will have to wait to show the post body while the code for the comments is downloading. We could lazily load <CommentList>, but then that would delay fetching comments data and increase the time to show the full page. How do we resolve this problem without compromising on the user experience?

Render As You Fetch

The fetch-on-render approach is widely used by React apps today and can certainly be used to create great apps. But can we do even better? Let’s step back and consider our goal.

In the above <Post> example, we’d ideally show the more important content — the post body — as early as possible, without negatively impacting the time to show the full page (including comments). Let’s consider the key constraints on any solution and look at how we can achieve them:

  • Showing the more important content (the post body) as early as possible means that we need to load the code and data for the view incrementally. We don’t want to block showing the post body on the code for <CommentList> being downloaded, for example.
  • At the same time we don’t want to increase the time to show the full page including comments. So we need to start loading the code and data for the comments as soon as possible, ideally in parallel with loading the post body.

This might sound difficult to achieve — but these constraints are actually incredibly helpful. They rule out a large number of approaches and spell out a solution for us. This brings us to the key patterns we’ve implemented in Relay Hooks, and that can be adapted to other data-fetching libraries. We’ll look at each one in turn and then see how they add up to achieve our goal of fast, delightful loading experiences:

  1. Parallel data and view trees
  2. Fetch in event handlers
  3. Load data incrementally
  4. Treat code like data

Parallel Data and View Trees

One of the most appealing things about the fetch-on-render pattern is that it colocates what data a component needs with how to render that data. This colocation is great — an example of how it makes sense to group code by concerns and not by technologies. All the issues we saw above were due to when we fetch data in this approach: upon rendering. We need to be able to fetch data before we’ve rendered the component. The only way to achieve that is by extracting the data dependencies into parallel data and view trees.

Here’s how that works in Relay Hooks. Continuing our example of a social media post with body and comments, here’s how we might define it with Relay Hooks:

// Post.js
function Post(props) {
  // Given a reference to some post - `props.post` - *what* data
  // do we need about that post?
  const postData = useFragment(graphql`
    fragment PostData on Post @refetchable(queryName: "PostQuery") {
      author
      title
      # ...  more fields ...
    }
  `, props.post);

  // Now that we have the data, how do we render it?
  return (
    <div>
      <h1>{postData.title}</h1>
      <h2>by {postData.author}</h2>
      {/* more fields  */}
    </div>
  );
}

Although the GraphQL is written within the component, Relay has a build step (Relay Compiler) that extracts these data-dependencies into separate files and aggregates the GraphQL for each view into a single query. So we get the benefit of colocating concerns, while at runtime having parallel data and view trees. Other frameworks could achieve a similar effect by allowing developers to define data-fetching logic in a sibling file (maybe Post.data.js), or perhaps integrate with a bundler to allow defining data dependencies with UI code and automatically extracting it, similar to Relay Compiler.

The key is that regardless of the technology we’re using to load our data — GraphQL, REST, etc — we can separate what data to load from how and when to actually load it. But once we do that, how and when do we fetch our data?

Fetch in Event Handlers

Imagine that we’re about to navigate from a list of a user’s posts to the page for a specific post. We’ll need to download the code for that page — Post.js — and also fetch its data.

Waiting until we render the component has problems as we saw above. The key is to start fetching code and data for a new view in the same event handler that triggers showing that view. We can either fetch the data within our router — if our router supports preloading data for routes — or in the click event on the link that triggered the navigation. It turns out that the React Router folks are already hard at work on building APIs to support preloading data for routes. But other routing frameworks can implement this idea too.

Conceptually, we want every route definition to include two things: what component to render and what data to preload, as a function of the route/url params. Here’s what such a route definition might look like. This example is loosely inspired by React Router’s route definitions and is primarily intended to demonstrate the concept, not a specific API:

// PostRoute.js (GraphQL version)

// Relay generated query for loading Post data
import PostQuery from './__generated__/PostQuery.graphql';

const PostRoute = {
  // a matching expression for which paths to handle
  path: '/post/:id',

  // what component to render for this route
  component: React.lazy(() => import('./Post')),

  // data to load for this route, as function of the route
  // parameters
  prepare: routeParams => {
    // Relay extracts queries from components, allowing us to reference
    // the data dependencies -- data tree -- from outside.
    const postData = preloadQuery(PostQuery, {
      postId: routeParams.id,
    });

    return { postData };
  },
};

export default PostRoute;

Given such a definition, a router can:

  • Match a URL to a route definition.
  • Call the prepare() function to start loading that route’s data. Note that prepare() is synchronous — we don’t wait for the data to be ready, since we want to start rendering more important parts of the view (like the post body) as quickly as possible.
  • Pass the preloaded data to the component. If the component is ready — the React.lazy dynamic import has completed — the component will render and try to access its data. If not, React.lazy will suspend until the code is ready.

This approach can be generalized to other data-fetching solutions. An app that uses REST might define a route like this:

// PostRoute.js (REST version)

// Manually written logic for loading the data for the component
import PostData from './Post.data';

const PostRoute = {
  // a matching expression for which paths to handle
  path: '/post/:id',

  // what component to render for this route
  component: React.lazy(() => import('./Post')),

  // data to load for this route, as function of the route
  // parameters
  prepare: routeParams => {
    const postData = preloadRestEndpoint(
      PostData.endpointUrl, 
      {
        postId: routeParams.id,
      },
    );
    return { postData };
  },
};

export default PostRoute;

This same approach can be employed not just for routing, but in other places where we show content lazily or based on user interaction. For example, a tab component could eagerly load the first tab’s code and data, and then use the same pattern as above to load the code and data for other tabs in the tab-change event handler. A component that displays a modal could preload the code and data for the modal in the click handler that triggers opening the modal, and so on.

Once we’ve implemented the ability to start loading code and data for a view independently, we have the option to go one step further. Consider a <Link to={path} /> component that links to a route. If the user hovers over that link, there’s a reasonable chance they’ll click it. And if they press the mouse down, there’s an even better chance that they’ll complete the click. If we can load code and data for a view after the user clicks, we can also start that work before they click, getting a head start on preparing the view.

Best of all, we can centralize that logic in a few key places — a router or core UI components — and get any performance benefits automatically throughout our app. Of course preloading isn’t always beneficial. It’s something an application would tune based on the user’s device or network speed to avoid eating up user’s data plans. But the pattern here makes it easier to centralize the implementation of preloading and the decision of whether to enable it or not.

Load Data Incrementally

The above patterns — parallel data/view trees and fetching in event handlers — let us start loading all the data for a view earlier. But we still want to be able to show more important parts of the view without waiting for all of our data. At Facebook we’ve implemented support for this in GraphQL and Relay in the form of some new GraphQL directives (annotations that affect how/when data is delivered, but not what data). These new directives, called @defer and @stream, allow us to retrieve data incrementally. For example, consider our <Post> component from above. We want to show the body without waiting for the comments to be ready. We can achieve this with @defer and <Suspense>:

// Post.js
function Post(props) {
  const postData = useFragment(graphql`
    fragment PostData on Post {
      author
      title

      # fetch data for the comments, but don't block on it being ready
      ...CommentList @defer
    }
  `, props.post);

  return (
    <div>
      <h1>{postData.title}</h1>
      <h2>by {postData.author}</h2>
      {/* @defer pairs naturally with <Suspense> to make the UI non-blocking too */}
      <Suspense fallback={<Spinner/>}>
        <CommentList post={postData} />
      </Suspense>
    </div>
  );
}

Here, our GraphQL server will stream back the results, first returning the author and title fields and then returning the comment data when it’s ready. We wrap <CommentList> in a <Suspense> boundary so that we can render the post body before <CommentList> and its data are ready. This same pattern can be applied to other frameworks as well. For example, apps that call a REST API might make parallel requests to fetch the body and comments data for a post to avoid blocking on all the data being ready.

Treat Code Like Data

But there’s one thing that’s still missing. We’ve shown how to preload data for a route — but what about code? The example above cheated a bit and used React.lazy. However, React.lazy is, as the name implies, lazy. It won’t start downloading code until the lazy component is actually rendered — it’s “fetch-on-render” for code!

To solve this, the React team is considering APIs that would allow bundle splitting and eager preloading for code as well. That would allow a user to pass some form of lazy component to a router, and for the router to trigger loading the code alongside its data as early as possible.

Putting It All Together

To recap, achieving a great loading experience means that we need to start loading code and data as early as possible, but without waiting for all of it to be ready. Parallel data and view trees allow us to load the data for a view in parallel with loading the view (code) itself. Fetching in an event handler means we can start loading data as early as possible, and even optimistically preload a view when we have enough confidence that a user will navigate to it. Loading data incrementally allows us to load important data earlier without delaying the fetching of less important data. And treating code as data — and preloading it with similar APIs — allows us to load it earlier too.

Using These Patterns

These patterns aren’t just ideas — we’ve implemented them in Relay Hooks and are using them in production throughout the new facebook.com (which is currently in beta testing). If you’re interested in using or learning more about these patterns, here are some resources:

  • The React Concurrent docs explore how to use Concurrent Mode and Suspense and go into more detail about many of these patterns. It’s a great resource to learn more about the APIs and use-cases they support.
  • The experimental release of Relay Hooks implements the patterns described here.
  • We’ve implemented two similar example apps that demonstrate these concepts:

    • The Relay Hooks example app uses GitHub’s public GraphQL API to implement a simple issue tracker app. It includes nested route support with code and data preloading. The code is fully commented — we encourage cloning the repo, running the app locally, and exploring how it works.
    • We also have a non-GraphQL version of the app that demonstrates how these concepts can be applied to other data-fetching libraries.

While the APIs around Concurrent Mode and Suspense are still experimental, we’re confident that the ideas in this post are proven by practice. However, we understand that Relay and GraphQL aren’t the right fit for everyone. That’s ok! We’re actively exploring how to generalize these patterns to approaches such as REST, and are exploring ideas for a more generic (ie non-GraphQL) API for composing a tree of data dependencies. In the meantime, we’re excited to see what new libraries will emerge that implement the patterns described in this post to make it easier to build great, fast user experiences.




de

It's time to upgrade those Ruby 2.4 apps

#497 — April 16, 2020

Read on the Web

Ruby Weekly

Bye Bye Ruby 2.4, Support Has Ended — From the end of April 2019 till now, Ruby 2.4 has been in its ‘security maintenance’ phase but now you won’t even get that, Ruby 2.4.10 should be the final 2.4 release. 2.5 will follow in 2.4’s footsteps next year, so upgrading to 2.6 or 2.7 should now be a priority for those older apps.

Ruby Core Team

Testing Ruby Decorators with super_method — Have you ever wondered how you can properly test the behavior of a method overridden by Module#prepend? Enter super_method which returns a Method object of which superclass method would be called when super is used or nil if none exists.

Simone Bravo

You Hacked the Gibson? Yeah, They Built Their Own Login — Don't let Crash Override pwn your app. FusionAuth adds secure login, registration and user management to your app in minutes not months. Download our community edition for free.

FusionAuth sponsor

Heya: A Sequence Mailer for Rails — “Think of it like ActionMailer, but for timed email sequences.” Note: It’s open source but not free for commercial use beyond a certain point.

Honeybadger Industries LLC

A Final Report on Ruby Concurrency Developments — A report on work funded by a 2019 Ruby Association Grant that puts forth a proposal of using non-blocking fibers to improve Ruby’s concurrency story.

Samuel Williams

Mocking in Ruby with Minitest — Minitest has basic mocking functionality baked in, but be judicious in your use of it.

Heidar Bernhardsson

???? Jobs

Ruby Backend Developer (Austria) — We’re seeking mid-level and senior devs to join us and build top-class backend infrastructure for our adidas apps, used by millions. Our stack includes: jRuby, Sinatra, Sidekiq, MySQL, & MongoDB.

Runtastic

Find a Job Through Vettery — Vettery specializes in tech roles and is completely free for job seekers. Create a profile to get started.

Vettery

▶️ Get ready for your next role: Pluralsight is free for the entire month of April. Stay Home. Skill Up. #FreeApril — SPONSORED

???? Articles & Tutorials

Predicting the Future With Linear Regression in Ruby — Linear regression is a mathematical approach to modelling a relationship between multiple variables and is demonstrated here by exploring whether the tempo of a song predicts its popularity on Spotify.

Julie Kent

Feature Flags: A Simple Way to 'De-Stress' Production Releases — Feature flags bridge a gap between the abstract concept of continuous delivery and tactical release of features.

Matt Swanson

A Guide to Deprecation Warnings in Rails — If you’ve upgraded Rails and you start seeing warnings screaming at you, you can either get Googling or.. read this ????

Luciano Becerra

What's the Difference Between Monitoring Webhooks and Background Jobs

AppSignal sponsor

Understanding webpacker.yml — Have you ever really gone through the Webpack config?

Ross Kaffenberger

Using Optimizer Hints in Rails — Rails 6 removes the need to write raw SQL to use optimizer hints, so that’s cool.

Prateek Choudhary

Dissecting Rails Migrations — You should pick up something new about migrations by reading this article as it covers all of the essentials and a little more.

Prathamesh Sonpatki

The Basics of Custom Exception Handling — Never hurts to revise the basics of effective exceptions.

Mark Michon

How to Improve Code Readability with Closures

Andrey Koleshko

???? Code and Tools

ruby-prolog: A Pure Ruby Prolog-like DSL for Logical Programming — Solve complex logic problems on the fly using a dynamic, Prolog-like DSL inline with your normal code.

Preston Lee

Anyway Config: Keep Your Ruby Configuration Sensible — Get your Ruby project out of ‘ENV Hell’ with anyway_config, a framework for managing configuration.

Vladimir Dementyev

The End of Heroku Alerts — Rails Autoscale keeps your app healthy. Simple and effective autoscaling for Web, Sidekiq, Delayed Job, and Que.

Rails Autoscale sponsor

Tomo 1.0: A Friendly CLI for Deploying Rails Apps — There’s a short tutorial for deploying Rails, and the documentation is thorough.

Matt Brictson

ActiveLdap 6.0: An Object Oriented Interface to LDAP — A very long standing project (16 years!) that has just had an update. LDAP stands for Lightweight Directory Access Protocol and while I don’t hear about it much anymore, it has plenty of established use cases.

Sutou Kouhei

Elasticsearch Integrations for ActiveModel/Record and Rails

Elastic

RubyMine 2020.1 Released

Natalie Kudanova




de

A transpiler for futuristic Ruby, and the RailsConf 2020 videos

#500 — May 7, 2020

Read on the Web

???? Welcome to issue 500! A bit of an arbitrary milestone but thanks to you all :-)

Ruby Weekly

Ruby Next: Make All Rubies Quack Alike — Ruby Next is a Ruby-to-Ruby transpiler that allows you to use the latest features of Ruby in previous versions without monkey patching or refinements. Could this be how experimental features are released going forward?

Vladimir Dementyev

Ruby 3 'Guilds' Proposal Now Called Ractor — This documentation is in Japanese (though the source code examples are easy to follow) but the news is that the new, proposed concurrency mechanism for Ruby 3 called Guilds (explained here) has been renamed to Ractor (as in ‘Ruby actors’, Ruby’s take on the actor model).

Koichi Sasada

Don’t Do Auth From Scratch. Focus On Your App — Spend less time on authentication and authorization and more time developing your awesome app. Auth built for <devs>. Download our community edition for free.

FusionAuth sponsor

Take the 2020 Ruby on Rails Survey — This is the sixth outing for Planet Argon’s survey which began in 2009. We try and support it each time as the results always make for interesting reading (see 2018’s results). Participate and become data ????

Planet Argon Team

???? RailsConf 2020 Videos

If you recall, RailsConf 2020 was cancelled in its in-person form to be replaced by a 'couch edition'. This has been taking place and the videos have been released! Here are some of the highlights:

If you want the full collection, here's the YouTube playlist.

Alt::BrightonRuby: A Slightly Odd, Quasi-Conference for Strange Times — Alt::BrightonRuby is not happening in-person this year. Instead, you can buy the recorded talks, get a _why book, and get some podcasts with the speakers.

Alt::BrightonRuby

???? Jobs

Find a Job Through Vettery — Vettery specializes in tech roles and is completely free for job seekers. Create a profile to get started.

Vettery

Security Engineer (Remote) — Are you an engineer with experience in Rails and/or Go? Join our team and help secure our apps and cloud infrastructure.

Shogun

ℹ️ Interested in running a job listing in Ruby Weekly? There's more info here.

???? Articles & Tutorials

▶  How To Begin Contributing to a Gem — If you’ve been using a library for a while and you want to contribute back, how do you get started? A 12 minute introduction here.

Drifting Ruby

How to Set Up Factory Bot on a Fresh Rails Project — Factory Bot is a library for setting up Ruby objects as test data – an alternative to fixtures, essentially.

Jason Swett

Using Postgres's DISTINCT ON to Avoid an N+1 Query“Recently I fixed a tricky N+1 query and thought I should write it up..”

John Nunemaker

Need to Upgrade Rails? Don’t Know How Long It Will Take? — Get an action plan for your Rails upgrade and an in-depth report about your technical debt and outdated dependencies ????.

FastRuby.io | Rails Upgrade Services sponsor

5 Uses for 'Splats' — 5 different ways to leverage Ruby’s splat (*) operator.

Jason Dinsmore

Running Multiple Instances of Webpacker — If you’re working on multiple Rails apps at once, changing where Rails gets served up is easy by configuring the port, but what about Webpacker? That requires another tweak.

Scott Watermasysk

Performing Asynchronous HTTP requests in Rails — How to update parts an app’s pages with asynchronous HTTP requests. A step-by-step how-to with JavaScript’s fetch() function, and Rails native server-side partial rendering.

Remi Mercier

How to Use AWS SimpleDB from Ruby — If you haven’t heard of AWS SimpleDB, you wouldn’t be alone as it’s not very popular, but it’s a pretty simple and cheap way to store simple documents in the cloud.

Peter Cooper

What's The Difference Between Monitoring Webhooks and Background Jobs

AppSignal sponsor

Ways to Reduce Your Heroku App's Slug Size — You might be surprised Heroku didn’t already do some of this for you.

Rohit Kumar

A Chat with Thibaut Barrère — If you missed our interview with Thibaut Barrere (Rubyist, and creator of the Kiba ETL framework) in last week’s issue, you can catch up here.

Glenn Goodrich

???? Code and Tools

Rodauth 2.0: Ruby's 'Most Advanced' Authentication Framework — A authentication framework that can work in any Rack-based webapp. Built using Roda and Sequel, Rodauth can be used with other frameworks and database libraries if you wish. Why’s it so advanced? More info on that here.

Jeremy Evans

RubyGems 3.1.3 Released — Lots of little bug fixes and tweaks.

RubyGems Blog

Business: Business Day Calculations for Ruby — Define your working days and holidays and then you can do ‘business day arithmetic’ (for example, what’s in 5 working days after now taking holidays and weekends into account?)

GoCardless

Lockbox: Modern Encryption for Rails

Andrew Kane

split: The Rack Based A/B 'Split' Testing Framework — A mature framework with robust configuration and multiple options for determining the winning option.

Split

P.S. In last week's issue, one of the links to our sponsors was incorrect and some readers emailed us to say they really wanted to read the promised article, Let’s Explore Big-O Notation with Ruby, so here it is. Apologies for any inconvenience.




de

Node 14 has been released

#335 — April 23, 2020

Read on the Web

Node Weekly

Node.js 14 Released — Woo-hoo another major release of Node.js is here. v14 now becomes the current ‘release’ line with it becoming a LTS (Long Term Support) release in October.. so production apps would, ideally, remain on v12 for now. So what’s new..?

  • Diagnostic reports are now a stable feature.
  • It's based on V8 8.1.
  • An experimental Async Local Storage API
  • Improvements to streams.
  • An experimental WebAssembly System Interface (WASI) to support future WebAssembly use cases.
  • Bye bye to the ESM module ‘experimental’ warning (though it still is experimental).

Michael Dawson and Bethany Griggs

Learn Hardcore Functional Programming in JavaScript — Join Brian Lonsdorf and learn how to apply such concepts as pure functions, currying, composition, functors, monads and more.

Frontend Masters sponsor

Puppeteer 3.0: Say Hello to Firefox — Best known as a way to headlessly control Chrome from Node, Puppeteer has recently seen some competition in the form of the cross-browser Playwright recently. But competition can be good and Puppeteer now supports Firefox too.

Mathias Bynens

ZEIT Is Now Vercel — You probably best know ZEIT as the creators and maintainers of the popular Next.js React framework and their ‘Now’ deployment and hosting platform.

Vercel

New OpenSSL Security Release To Require Node Updates? Maybe Not.. — A key security update to OpenSSL raised the possibility of widespread Node releases to incorporate the fixes, but initial suggestions are that Node isn’t affected. Fingers crossed!

Sam Roberts

???? Jobs

Node.js Developer at X-Team (Remote) — Join the most energizing community for developers. Work from anywhere with the world's leading brands.

X-Team

Find a Job Through Vettery — Vettery specializes in tech roles and is completely free for job seekers. Create a profile to get started.

Vettery

ℹ️ If you're interested in running a job listing in this newsletter, there's more info here.

???? Articles & Tutorials

OneTesselAway: Building a Real-Time Public Transit Status Device — A developer wanted to know when the next bus would arrive.. while using lots of cool tech, including Node, the OneBusAway API, and the Tessel 2 IoT platform.

Robert McGuire

What is the toJSON() Function? — If an object has a toJSON function, JSON.stringify() calls toJSON() and serializes the return value from toJSON() instead.

Valeri Karpov

Top GitHub Best Practices for Developers - Expanded Guide — Implementing these best practices could save you time, improve code maintainability, and prevent security risks.

Datree.io sponsor

Refactor Your Node and Express APIs to Serverless with Azure Functions — John Papa points out a Microsoft tutorial that walks through the process of taking a Node API serverless with Azure’s Functions service.

John Papa

Querying SQL Server from Node with async/await

Rob Tomlin

Why I Stopped Using Microservices

Robin Wieruch

???? Tools, Resources and Libraries

lazynpm: A Terminal UI for npm — One of those sort of things you don’t realize you need until you give it a go. There’s a four-minute screencast if you want to see how it works without downloading.

Jesse Duffield

node-sqlite3 4.2: Async, Non-blocking SQLite3 Bindings for Node4.2.0 just came out.

Mapbox

ts-gphoto2-driver: A Node Wrapper for libgphoto2libgphoto2 provides a way to control a variety of digital cameras/DSLRs.

Lenzotti Romain

AppSignal Now Supports Node.js: Roadmap for the Coming Weeks

AppSignal sponsor

Rosetta: A General Purpose Internationalization Library in 292 Bytes — Less than 300 bytes, but does have a few dependencies. Aims to be very simple and is targeted at basic string use cases.

Luke Edwards

nodejs-dns 2.0: The Google Cloud DNS Client for Node

Google

node-osc 5.0: Open Sound Control Protocol LibraryOSC is a protocol used to communicate between media devices.

Myles Borins

ts-node: TypeScript Execution and REPL for Node

TypeStrong

???? And One for Fun..

npm trends: Compare NPM Package Downloads — A site to compare package download counts over time. For example, what about koa vs restify vs fastify?

John Potter




de

Can you build Node add-ons in Rust? Yes.

#336 — April 30, 2020

Read on the Web

Be sure to check out the Tools and Libraries section today as there have been quite a lot of (minor) releases.. from MIDI parsing and JPEG decoding to generating TypeScript types from a Postgres database.. maybe there's something for you ????

Node Weekly

Middy 1.0: A Node Middleware Framework for AWS Lambda — Middy’s aim is to make writing serverless functions (hosted on AWS Lambda) easier by providing a familiar middleware abstraction to Node developers. The example in this post shows off the main benefit.

Luciano Mammino

Rust and Node.js: A Match Made in Heaven? — This is technical stuff but using other languages, such as Rust, for building add-ons for Node is an interesting area.

Anshul Goyal

Faster CI/CD for All Your Software Projects Using Buildkite — See how Shopify scaled from 300 to 1800 engineers while keeping their build times under 5 minutes.

Buildkite sponsor

Editly: Slick, Declarative Command Line Video Editing — I’ve long wondered why there isn’t a good way to “code” video editing at the command line other than wrangling with arcane ffmpeg options. Well.. this uses ffmpeg, but it handles a lot of the wrangling for you.

Mikael Finstad

Node v14.1.0 (Current) ReleasedLast week we featured the release of Node 14.0 and 14.1 is already with us. Principally bug fixes, plus an update to the OpenSSL dependency.

Bethany Nicolle Griggs

???? Jobs

Backend Developer (Skien, Norway) — We are looking for a full-stack dev with a solid track record to help us adapt to tomorrow's security requirements.

OKAY

Find a Job Through Vettery — Vettery specializes in tech roles and is completely free for job seekers. Create a profile to get started.

Vettery

ℹ️ If you're interested in running a job listing in this newsletter, there's more info here.

???? Articles & Tutorials

Four Tools for Web Scraping in Node — A walk through of a few different libraries (for scraping and parsing data directly from websites) to see how they work and how they compare to each other.

Sam Agnew

Six Platforms for Hosting a Node App in 2020 — Of course, you can run a Node app pretty much anywhere there’s a server, but some platforms make it easier than others. These all have free tiers too. Glitch, Now.sh (now Vercel) and Heroku are particular favorites of ours at Cooperpress.

Amit Bendor

Getting Started with NuxtJS — Learn how to create Vue.js-powered server-side rendered apps with NuxtJS including configuring an app and deploying it on Heroku.

Timi Omoyeni

The Node.js Security Handbook — Improve the security of your Node.js app with the Node.js security handbook made for developers.

Sqreen sponsor

A Collection of Challenging TypeScript Exercises“The goal: Let everyone play with many different TypeScript features and get an overview of TypeScript capabilities and principles.”

Marat Dulin

Exploring Node.js Internals — It’s reasonably elementary but Aleem Isiaka explains how the internals of Node.js interact with one another on a simple task such as creating a file.

Smashing Magazine

Creating CommonJS-Based npm Packages via TypeScript

Dr. Axel Rauschmayer

Turning Vue Components Into Reusable npm Packages — Outlines how you can reuse Vue components across your projects by automating your process to bundle, test, document, and publish your components.

Sjoerd de voorhoede

???? Tools, Resources and Libraries

Node v12.16.3 (LTS) Released — OpenSSL gets an update, and warnings are no longer printed for modules that use conditional exports or package name self resolution.

Node.js

pm2 4.4 Released: The Node Production Process Manager — A very mature and widely used process manager that includes a load balancer for keeping Node apps alive forever and to reload them without downtime. v4.4 improves the Node 14 compatibility.

Alexandre Strzelewicz

jpeg-js: A Pure JavaScript JPEG Encoder and Decoder — It admits it’s far slower than native alternatives but if you need a pure JavaScript JPEG encoder/decoder, this is where to go.

Eugene Ware

AppSignal Now Supports Node.js: Roadmap for the Coming Weeks

AppSignal sponsor

node-stream-zip: For Fast Reading of ZIP Archives — Reads chunk by chunk rather than all in one go so it’s memory friendly.

Dimitri Witkowski

JZZ: A MIDI Library for Node and Web Browsers — Send, receive and play MIDI messages from both Node and the browser on Linux, macOS and Windows.

Sema

Vegemite: A Pub/Sub State Manager — Inspired by Immer and Redux, full TypeScript support, and sized at only 623 bytes, which includes one dependency.

Luke Edwards

Kanel: Generate TypeScript Types from Postgres

Kristian Dupont

web-worker: Consistent Web Workers for the Browser and Node — In Node it works as a web-compatible Worker implementation atop worker_threads. In the browser it’s an alias for Worker.

Jason Miller

node-csv-parse: A CSV Parser Implementing the stream.Transform API

Adaltas




de

Node 14.2.0, plus Deno 1.0 is coming

#337 — May 7, 2020

Read on the Web

✍️ With a few of the links today, this is a good time to note we sometimes link to things we disagree with or that are controversial if they are newsworthy or of relevance to our community. Inclusion is not always endorsement but you can read any summaries we write alongside items to get our take on things ????

Node Weekly

Node v14.2.0 (Current) Released — The latest version of Node gains a new experimental way — assert.CallTracker — to track and verify function calls and the amount of times they occur. Also, require('console').Console now supports different group indentations

Node.js

Deno 1.0: What You Need to Know — Two years ago Ryan Dahl, the original creator of Node, gave a popular talk called 10 Things I Regret About Node.js where he revealed Deno, his prototype of how he'd build a better V8-based JavaScript runtime. With 1.0 due next week, Deno is poised to be a particularly exciting release and this article does a good job of cruising through the reasons why.

David Else

Enhance Node.js Performance with Datadog APM — Debug errors and bottlenecks in your code by tracing requests across web servers and services in your environment. Then correlate between distributed request traces, metrics, and logs to troubleshoot issues without switching tools or contexts. Try Datadog APM free.

Datadog APM sponsor

Deno Weekly: Our Newest Newsletter — We really like what we see from Deno (above) so far, so we're launching a new newsletter all about it! ???? Rather than keep mentioning Deno in Node Weekly, we'll be giving it its own space. Even if you're not planning to use Deno, feel free to subscribe for a while, see what happens, then unsubscribe if it doesn't suit you — the next issue will drop on 1.0's release (due next Wednesday).

Cooperpress

Controlling GUIs Automatically with Nut.js — Write Node code that clicks on things, opens apps, types, clicks buttons, etc. Works on Windows, macOS and Linux. Hit the GitHub repo to learn more or check out some examples.

Simon Hofmann

A Practical Guide to Node Buffers — You’ll often encounter Buffer objects for holding binary data in the form of a sequence of bytes during interactions with the operating system, working with files, network transfers, etc.

DigitalOcean

???? Jobs

Node.js Developer at X-Team (Remote) — Join X-Team and work on projects for companies like Riot Games, FOX, Coinbase, and more. Work from anywhere.

X-Team

Find a Job Through Vettery — Vettery specializes in tech roles and is completely free for job seekers. Create a profile to get started.

Vettery

ℹ️ If you're interested in running a job listing in this newsletter, there's more info here.

???? Articles & Opinions

How to Build a REST Service with Fastify — How to build a basic RESTful service using Fastify, a popular Node Web framework focused on performance/low overheads.

Wisdom Ekpot

▶  How to Use Node.js for Load Testing — A straightforward tour of an approach for hitting a Web site over and over from multiple child processes.

Tom Baranowicz

How to Fix ESLint Errors Upon Save in VS Code — A quick fire tip.

David Walsh

Faster CI/CD for All Your Software Projects Using Buildkite — See how Shopify scaled from 300 to 1800 engineers while keeping their build times under 5 minutes.

Buildkite sponsor

Avoiding Memory Leaks in Node: Best Practices for Performance — Covers very similar ground to another memory leak article we linked recently.

Deepu K Sasidharan

'Some thoughts on the npm acquisition..' — The creator of Hapi and an investor in npm Inc. shared his thoughts on GitHub’s acquisition of npm. I disagree with his conclusion (and his views have also caused concern on Twitter) but it’s nonetheless interesting to get views from behind the curtain.

Eran Hammer

???? Tools, Resources and Libraries

npm 6.14.5 Released — Just a couple of minor bug fixes.

The npm Blog

actions-cli: Monitor Your GitHub Actions in Real Time from the Command Line

Tommaso De Rossi

SQL Template Tag: Tagged Template Strings for Preparing SQL Statements — For use with pg and mysql, for example.

Blake Embrey

webpack-blocks: Configure webpack using Functional Feature Blocks

Andy Wermke

JavaScript Error Tracking with AppSignal v1.3.0 is Here

AppSignal sponsor

FarmHash 3.1: A Node Implementation of Google's High Performance Hash FunctionsFarmHash is a family of non-cryptographic hash functions built by Google mostly for quickly hashing strings.

Lovell Fuller

do-wrapper 4.0: A Node Wrapper for the DigitalOcean v2 API

Matthew Major




de

The 2019 Go developer survey results are available

#309 — April 24, 2020

Unsubscribe  :  Read on the Web

Golang Weekly

Go Developer Survey 2019 Results — The annual survey results are here but calculated differently than in previous years. See how the community feels, what tools we use, and what we’re really using Go for.

The Go Blog

Fiber: An Express.js Inspired Web Framework for Go — If you know Express (from the Node world) than Fiber will look very familiar. It supports middleware, WebSockets, and various template engines, all while boasting a low memory footprint. Built on top of FastHTTP.

Fiber

We Now Offer Remote Go, Docker or Kubernetes Training — We offer live-streaming remote training as well as video training for engineers and companies that want to learn Go, Docker and/or Kubernetes. Having trained over 5,000 engineers, we have carefully crafted these classes for students to get as much value as possible.

Ardan Labs sponsor

A Comparison of Three Programming Languages for Bioinformatics — This is quite an academic piece but basically Go, Java and C++ were put head to head in an intensive bioinformatics task. The good news? Go won on memory usage and beat the C++17 approach (which was admittedly less than ideal) in performance. The team in question chose Go going forward.

BMC Bioinformatics

Go for Cloud — A Few Reflections for FaaS with AWS Lambda — A response to a this article about Go’s pros and cons in the cloud. You should read both.

Filip Lubniewski

???? Jobs

Enjoy Building Scalable Infrastructure in Go? Stream Is Hiring — Like coding in Go? We do too. Stream is hiring in Amsterdam. Apply now.

Stream

Golang Developer at X-Team (Remote) — Join the most energizing community for developers. Work from anywhere with the world's leading brands.

X-Team

Find a Job Through Vettery — Vettery specializes in tech roles and is completely free for job seekers. Create a profile to get started.

Vettery

???? Articles & Tutorials

An Introduction to Debugging with Delve — If you’re in the “I don’t really use a debugger..” camp, Paschalis’s story and brief tutorial might help you dip a toe into the water.

Paschalis Tsilias

Object Ordering in Go — This is all about object comparison and the types of comparisons that are allowed in Go. Reading this post > Not reading this post.

Eyal Posener

How to Manage Database Timeouts and Cancellations in Go — How to cancel database queries from your app and what quirks and edge cases you need to be aware of.

Alex Edwards

The Go Security Checklist — From code to infrastructure, learn how to improve the security of your Go applications with the Go security checklist.

Sqreen sponsor

Data Logging with Go: How to Store Customer Details Securely — Specifically, this looks at using custom protobuf FieldOptions to mark fields as OK to log and reflection to check those options.

Vadzim Zapolski-Dounar

How to Install Go in FreeBSD in 5 Minutes — You can use a package manager, but this way has advantages and it’s easy.

Jeremy Morgan

???? Code & Tools

Fynedesk: A Fyne-Powered Full Desktop Environment for Linux/Unix — Previously we’ve linked to Fyne, a Go-based cross-platform GUI framework, but now it’s been used to create an entire Linux desktop environment!

Fyne.io

Lockgate: A Cross-Platform Locking Library — Has support for distributed locks using Kubernetes and OS file locks support.

Flant

Pomerium: An Identity-Aware Secure Access Proxy — An identity aware access-proxy modeled after Google’s BeyondCorp. Think VPN access benefits but without the VPN. Built in Go, naturally.

Pomerium

Beta Launch: Code Performance Profiling - Find & Fix Bottlenecks

Blackfire sponsor

Apex Log: A Structured Logging Package for Go — Inspired by Logrus.

Apex

mediary: Add Interceptors to the Go HTTP Client — This opens up a few options: tracing, request dumping, statistics collection, etc.

Here Mobility SDK

iso9660: A Go Library for Reading and Creating ISO9660 Images — The use cases for this will be a bit niche. The author created it to dynamically generate ISOs to be mounted in vSphere VMs.

Kamil Domański

pxy: A Go Livestream Proxy from WebSockets to External RTMP Endpoints

Chua Bing Quan




de

'My search for the boy in a child abuse video'

Lucy Proctor was horrified when she was WhatsApped a sex abuse video. And she wanted to find out if the boy was safe.




de

Birth in a pandemic: 'You are stronger than you think'

Coronavirus is throwing many birth plans up in the air and leading some health trusts to increase home births.




de

Coronavirus: 'Depression feels like my cat is sitting on my chest'

Two young people describe how the coronavirus pandemic and the lockdown have affected their mental health.




de

Coronavirus: 'I'm being bombarded by gambling ads'

Gambling companies have halted TV and radio ads during lockdown - but not online ads.




de

Bill Gates: Few countries will get 'A-grade' for coronavirus response

The Microsoft billionaire says we find ourselves in uncharted territory with the coronavirus pandemic.




de

Coronavirus: The unexpected items deemed 'essential'

Cheese shops and gun stores are among the services still open in locked down places around the world.




de

Coronavirus: Pint delivery service to challenge Belfast ban

A pub delivering Guinness to people's homes during lockdown says it was operating within the law.




de

Coronavirus: Should maternity and paternity leave be extended?

A petition calling for maternity leave to be extended due to coronavirus has attracted many signatures.




de

Coronavirus coffee farmer: 'We're definitely scared'

Many small coffee producers fear they will go under, as Covid-19 has shut down their usual buyers.




de

Coronavirus: Disease meets deforestation at heart of Brazil's Amazon

Coronavirus has overwhelmed Manaus, the Amazon's biggest city, and the worst is yet to come.




de

Life for asylum seekers in lockdown on the US-Mexico border

Magaly Contreras has spent nine months in a Tijuana shelter and is worried about her future.




de

Brazil's Amazon: Surge in deforestation as military prepares to deploy

The military is preparing to deploy to the region to try to stop illegal logging and mining.




de

Venezuela: Trump denies role in bungled incursion

Venezuela has accused the US of being behind a botched raid to oust President Maduro.




de

Coach of Brazil, Carlos Amadeu arrives at the stadium

KOLKATA, INDIA - OCTOBER 28: Coach of Brazil, Carlos Amadeu arrives at the stadium prior to the FIFA U-17 World Cup India 2017 3rd Place match between Brazil and Mali at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Coach of Brazil, Carlos Amadeu arrives at the stadium

KOLKATA, INDIA - OCTOBER 28: (EDITOR'S NOTE: This image has been processed using digital filters). Coach of Brazil, Carlos Amadeu arrives at the stadium prior to the FIFA U-17 World Cup India 2017 3rd Place match between Brazil and Mali at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Paulinho of Brazil and Fode Konate of Mali in action

KOLKATA, INDIA - OCTOBER 28: Paulinho of Brazil and Fode Konate of Mali in action during the FIFA U-17 World Cup India 2017 3rd Place match between Brazil and Mali at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Paulinho of Brazil battles for the ball with Fode Konate of Mali

KOLKATA, INDIA - OCTOBER 28: Paulinho (R) of Brazil battles for the ball with Fode Konate of Mali during the FIFA U-17 World Cup India 2017 3rd Place match between Brazil and Mali at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Buda Mendes - FIFA/FIFA via Getty Images)




de

Yuri Alberto (R) of Brazil celebrates scoring his sides second goal with Rodrigo Guth

Yuri Alberto (R) of Brazil celebrates scoring his sides second goal with Rodrigo Guth during the FIFA U-17 World Cup India 2017 3rd Place match between Brazil and Mali at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Yuri Alberto of Brazil scores his side's second goal

KOLKATA, INDIA - OCTOBER 28: Yuri Alberto of Brazil scores his side's second goal during the FIFA U-17 World Cup India 2017 3rd Place match between Brazil and Mali at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Yuri Alberto of Brazil celebrates scoring his side's second goal

Yuri Alberto of Brazil celebrates scoring his side's second goal during the FIFA U-17 World Cup India 2017 3rd Place match between Brazil and Mali at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Yuri Alberto of Brazil celebrates scoring his sides second goal

KOLKATA, INDIA - OCTOBER 28: Yuri Alberto (C) of Brazil celebrates scoring his sides second goal with Rodrigo Guth (L) during the FIFA U-17 World Cup India 2017 3rd Place match between Brazil and Mali at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Philip Foden of England and Juan Miranda of Spain in action

KOLKATA, INDIA - OCTOBER 28: Philip Foden of England and Juan Miranda of Spain in action during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Rhian Brewster of England celebrates scoring his side's first goal

KOLKATA, INDIA - OCTOBER 28: Rhian Brewster of England celebrates scoring his side's first goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Rhian Brewster of England scores his side's first goal

KOLKATA, INDIA - OCTOBER 28: Rhian Brewster of England scores his side's first goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Sergio Gomez of Spain celebrates scoring his sides second goal

Sergio Gomez of Spain celebrates scoring his sides second goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Jan Kruger - FIFA/FIFA via Getty Images)




de

Sergio Gomez of Spain celebrates scoring his sides second goal

Sergio Gomez of Spain celebrates scoring his sides second goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Jan Kruger - FIFA/FIFA via Getty Images)




de

Sergio Gomez of Spain celebrates scoring his sides second goal

KOLKATA, INDIA - OCTOBER 28: Sergio Gomez of Spain celebrates scoring his sides second goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Jan Kruger - FIFA/FIFA via Getty Images)




de

Head coach Santiago Denia of Spain looks on

KOLKATA, INDIA - OCTOBER 28: Head coach Santiago Denia of Spain looks on during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Buda Mendes - FIFA/FIFA via Getty Images)




de

Philip Foden of England reacts

KOLKATA, INDIA - OCTOBER 28: Philip Foden of England reacts during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Sergio Gomez of Spain scores his sides second goal

KOLKATA, INDIA - OCTOBER 28: Sergio Gomez of Spain scores his sides second goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Jan Kruger - FIFA/FIFA via Getty Images)




de

Sergio Gomez of Spain celebrates scoring his sides second goal

KOLKATA, INDIA - OCTOBER 28: Sergio Gomez of Spain celebrates scoring his sides second goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Jan Kruger - FIFA/FIFA via Getty Images)




de

Head coach Steve Cooper of England gives a gift for coach Santiago Denia of Spain

KOLKATA, INDIA - OCTOBER 28: Head coach Steve Cooper of England gives a gift for coach Santiago Denia of Spain during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Buda Mendes - FIFA/FIFA via Getty Images)




de

Morgan Gibbs White of England scores his sides second goal

KOLKATA, INDIA - OCTOBER 28: Morgan Gibbs White of England scores his sides second goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Morgan Gibbs White of England celebrates with the team scoring his sides second goal

KOLKATA, INDIA - OCTOBER 28: Morgan Gibbs White of England celebrates with the team scoring his sides second goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Morgan Gibbs White of England celebrates with the team scoring his sides second goal

KOLKATA, INDIA - OCTOBER 28: Morgan Gibbs White (2nd L) of England celebrates with the team scoring his sides second goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Players of England celebrate goal by Philip Foden

KOLKATA, INDIA - OCTOBER 28: Players of England celebrate goal by Philip Foden during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Tom Dulat - FIFA/FIFA via Getty Images)




de

Philip Foden of England celebrates scoring the 3rd goal

KOLKATA, INDIA - OCTOBER 28: Philip Foden of England celebrates scoring the 3rd goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Jan Kruger - FIFA/FIFA via Getty Images)




de

Philip Foden of England celebrates scoring the third goal

KOLKATA, INDIA - OCTOBER 28: Philip Foden of England celebrates scoring the 3rd goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Jan Kruger - FIFA/FIFA via Getty Images)




de

Philip Foden (L) of England celebrates with his teammates

KOLKATA, INDIA - OCTOBER 28: Philip Foden (L) of England celebrates with his teammates after scoring their third goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Buda Mendes - FIFA/FIFA via Getty Images)




de

Philip Foden (2nd L) of England celebrates with his teammates

KOLKATA, INDIA - OCTOBER 28: Philip Foden (2nd L) of England celebrates with his teammates after scoring their third goal during the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Buda Mendes - FIFA/FIFA via Getty Images)




de

FIFA President Gianni Infantino presents the winners trophy

KOLKATA, INDIA - OCTOBER 28: FIFA President Gianni Infantino presents the winners trophy to captain Angel Gomes of England after the FIFA U-17 World Cup India 2017 Final match between England and Spain at Vivekananda Yuba Bharati Krirangan on October 28, 2017 in Kolkata, India. (Photo by Buda Mendes - FIFA/FIFA via Getty Images)