Build a Universal JavaScript App with Nextjs

); function onSuccess(response) localStorage.setItem(isBlogSubscriber, true); var blogRegData = getBasicInfo(); blogRegData.trackData = value; blogRegData.email = value; blogRegData.formId = 1052; blogRegData.lpId = 1117; blogRegData.Blog_Subs__c = true; metricsLib.track(register:lead:blog-newsletter, blogRegData); $module.find(.title).text(Thanks for subscribing); $module.find(.fields).html(

Well be building a simple character-listing app withNext.js 1.0.2, just like we did withLaravel.

Sometimes you might need a more advanced routing than the option thatNext.jsprovides,Next.jsstill allows you to intercept the request and do whatever you want. Checkherefor comprehensive info on how to achieve that.

WithNext.js, we have been able to implement a Universal JavaScript web app in a very short time without overthinking the whole process. Im optimistic that this young framework will grow very quickly and provide lots of options and configurations that will make building Universal JavaScript apps a breeze.

import React from react export default class AuthService constructor(clientId, domain) // Configure Auth0 this.clientId = clientId; this.domain = domain; this.auth0 = new window.auth0.WebAuth( domain: domain, clientID: clientId, scope: openid profile, responseType: token id_token, redirectUri: ); // binds login functions to keep this context this.login = this.login.bind(this); parseHash(callback) this.auth0.parseHash((err, result) = if(err) console.log(err); callback(false); this.logout(); return; this.setToken(result.accessToken); callback(true); ); login() this.auth0.authorize(); loggedIn() // Checks if there is a saved token and its still valid return !!this.getToken(); setToken(accessToken) // Saves user token to localStorage localStorage.setItem(accessToken, accessToken); getToken() // Retrieves the user token from localStorage return localStorage.getItem(accessToken); logout() // Clear user token from localStorage localStorage.removeItem(accessToken);

We can easily set up authentication in ourNext.jsapps by using theAuth0.js library. If you dont already have an Auth0 account,sign upfor one now. Navigate to the Auth0management dashboard, click onNew clientby the right hand side, select Regular Web App from the dialog box and then go ahead to theSettingstab where the client ID and domain can be retreived.

The awesome thing aboutNext.jsis that it automatically maps a.jsfile within thepagesdirectory to a route. So basically,

Note:If you want to use Auth0 authentication to authorizeAPI requests, note that youll need to usea different flow depending on your use caseAccess tokens should be used to authorize APIs. You can read more aboutmaking API calls with Auth0 here.

This is basically React code but there are some new imports from thenextframework. Every route withinNext.jsis simply an ES6 module that exports a function or class that extends from ponent. IngetInitialProps, we are returning the posts array from theposts.jswe created earlier as aprop.

Go ahead and create apagesdirectory within the project. Add anindex.jsfile to thepagesdirectory like so:

Open up theposts.jsfile and add this code to it like so:

We know that the Reactrendermethod actually does the UI rendering. Within therendermethod, we looped through the postspropto display the characters in a table.

); ); function initialize() initBlogSubscriber(); $(pre code).each(function(i, block) hljs.highlightBlock(block); ); $(.post-info time).each(function() var $current = $(this); var dateString = new Date($current.text()); var diff = moment(dateString).diff(moment(new Date()), days); var dateFormat; dateFormat = moment(dateString).fromNow(); if(diff

import React from react import settings from ../data/settings import AuthService from ../utils/AuthService export default class extends React.Component componentDidMount() this.auth = new AuthService(settings.clientId, settings.domain); this.auth.parseHash(() = this.props.url.replaceTo(/); ); render () return script src=

Note:Make sure you set theAllowed Callback URLstoor whatever url/port you are running on.

import React from react import posts from ../data/posts import settings from ../data/settings import style from next/css import Link from next/link import AuthService from ../utils/AuthService export default class extends mponent static getInitialProps ( req, res) return posts: posts constructor(props) super(props) this.state = loggedIn: false componentDidMount() this.auth = new AuthService(settings.clientId, settings.domain); this.setState( loggedIn: this.auth.loggedIn() ); this.auth.callback = () = this.setState( loggedIn: this.auth.loggedIn() ); ; login() this.auth.login(); render() const loginButton = this.state.loggedIn ? divHELLO/div : button onClick=this.login.bind(this)Login/button; return ( div div className=style(styles.header) script src= loginButton h3 NEXTHRONE – THE REVELATION OF GAME OF THRONES CHARACTERS /h3 /div table className=style(styles.table) thead tr th className=style(styles.th)Character/th th className=style(styles.th)Real Name/th /tr /thead tbody this.props.posts.map( (post, i) = ( tr key=i td className=style(styles.td) post.codeName /td td className=style(styles.td) this.state.loggedIn ? Link href=`/account?id=$post.id` post.realName /Link : divYou need to login/div /td /tr )) /tbody /table /div ) const styles = th: background: 00cccc, color: fff, textTransform: uppercase, fontSize: 12px, padding: 12px 35px, , header: font: 15px Monaco, textAlign: center , table: fontFamily: Arial, margin: 25px auto, borderCollapse: collapse, border: 1px solid eee, borderBottom: 2px solid 00cccc , td: color: 999, border: 1px solid eee, padding: 12px 35px, borderCollapse: collapse , list: padding: 50px, textAlign: center , photo: display: inline-block , photoLink: color: 333, verticalAlign: middle, cursor: pointer, background: eee, display: inline-block, width: 250px, height: 250px, lineHeight: 250px, margin: 10px, border: 2px solid transparent, :hover: borderColor: blue

Next.jshas a default component,_error.jsthat handles 404 and 500 errors on both client and server side. You can override it like so:

The source code for the authentication part of the NexThrone app can be found on theadding-auth branch here

import React from react import css from next/css export default () = p className=styleHello World!/p const style = css( color: blue )

Next.jsis a small framework that is built on top of React, Webpack and Babel. It was built to enable easy creation of server-rendered React applications.Next.jssaves you time and effort because it ships with features out of the box that caters for server-rendering of JavaScript applications. These features include the following:

Now, run the app, the login button should appear at the top like so:

Open up yourindex.jsfile and this code to it like so:

Create a new fileaccount.jsinside thepagesdirectory and add this code to it like so:

Have you usedNext.js? What are your thoughts about it? Please let me know in the comments section!

Our Index page should look like this below:

Go ahead and installlodash. With the help of lodash, we can traverse the posts array to find the other properties of an object based on theidit receives from the query. This codeexport default ( url: query: id )grabs the value ofidthat is part of a url query. For examplewill returnjavascript. So, in our code above, it gets theidfrom the url, uses lodash to get the object properties based on the id, then assign them to theitemvariable. With that, we can now output therealName,codeName,storyanddisplay_srcon the screen like we did above!

Learn how to build Universal JavaScript apps with the new and shiny Next.js framework

Now, runyarn run devand go to Your homepage should look like so:

); $.ajax( type: POST, url: data: email: value , success: onSuccess, error: onFail ); function onFail(response) $module.find(.fields).html(

import React from react import posts from ../data/posts import settings from ../data/settings import style from next/css import * as _ from lodash import AuthService from ../utils/AuthService export default class extends ponent componentDidMount() this.auth = new AuthService(settings.clientId, settings.domain); if (!this.auth.loggedIn()) this.props.url.replaceTo(/); render () const item = _.find(posts, id: this.props.url.query.id ); return ( div className=style(styles.main) script src= div className=style(styles.header) h3 NEXTHRONE – THE REVELATION OF GAME OF THRONES CHARACTERS /h3 /div div className=style(styles.panel) h1 className=style(styles.heading) Character: deName br/ br/ Real Name: item.realName br/ br/ Brief Description: br/ br/ span item.story /span /h1 /div div className=style(styles.singlePhoto) img src= item.display_src alt=item.realName width=500 height=500 / /div /div ) const styles = main: padding: 50px , header: font: 15px Monaco, textAlign: center , panel: float: right, marginRight: 140px, width: 300px , singlePhoto: border: 1px solid 999, width: 500px, height: 500px, float: left , heading: font: 15px Monaco

Theres a problem subscribing to the list right now. Please try again later orcontact support.

Auth0issuesJSON Web Tokenson every login for your users. This means that you can have a solididentity infrastructure, includingsingle sign-on, user management, support for social identity providers (Facebook, Github, Twitter, etc.), enterprise identity providers (Active Directory, LDAP, SAML, etc.) and your own database of users with just a few lines of code.

Follow the instructions, also ensure that apackage.jsonfile was created in the end. Now, go ahead and installNext.jslike so:

const posts = [ codeName:Jon Snow, realName:Kit Harington, id:6503, display_src: story: Ned Starks bastard son, Jon joined the Nights Watch. On a mission for Lord Commander Mormont, Jon infiltrated the wildlings by pretending to forsake his Night Watch brothers. In doing so, he fell in love with Ygritte, a wildling woman , codeName:Arya Stark, realName:Maisie Williams, id:4781, display_src: story: The younger of the Stark daughters, Arya has put her survival skills to use as she continues to evade the Lannister forces that seek her. En route to the Twins in search of her mother and brother, she arrived at the castle after the Red Wedding. , codeName:Melisandre, realName:Carice van Houten, id:3752, display_src: story: A Red priestess from Asshai, Melisandre worships the Lord of Light. Her visions have told her that Stannis is the true king and as his advisor, she has encouraged him to pursue the throne at all costs , codeName:Tyrion Lannister, realName:Peter Dinklage, id:1229, display_src: story: What Tyrion lacks in size and strength, he makes up for in mental acuity. Former Hand of the King in his fathers absence, he now serves as Master of Coin on the Small Council. , codeName:Ramsay Bolton, realName:Iwan Rheon, id:9053, display_src: story: A bastard son of Roose Bolton, Ramsays bloodlust is even stronger than his fathers. After taking Winterfell, he captured Theon Greyjoy and slowly tortured him into submission. , codeName:Petyr Baelish, realName:Aidan Gillen, id:5365, display_src: story: Nakedly ambitious, Littlefinger left the Small Council to marry Lysa Arryn and secure the Vale to the Lannisters side. Beyond his official duties, he is the eyes and ears of Kings Landing along with Varys. , codeName:Brienne of Tarth, realName:Gwendoline Christie, id:9646, display_src: story: Brienne is a highborn lady who would rather be a knight. As Catelyn Starks envoy, she escorted Jaime Lannister back to Kings Landing. The two fighters developed a mutual respect for each other during their journey. , codeName:Lord Varys, realName:Conleth Hill, id:0553, display_src: story: A eunuch and a member of the Small Council, Varys is also a master of disguise. Along with Littlefinger, he is always aware of what goes on in Court. , codeName:Daenerys Targaryen, realName:Emilia Clarke, id:2320, display_src: story: Princess of House Targaryen, Daenerys lives in exile in Essos with her advisors and dragons. Dany rallied the Unsullied of Astapor to her cause and continues to grow the army she needs to take back the throne. ]; export default posts;

Ambassador Program img = document.getElementsByClassName(guest-author-image)[0]; img.src= img.alt = Auth0 Ambassador Program imgLink = document.getElementsByClassName(img-link)[0]; imgLink.href= learnLink = document.getElementsByClassName(guest-author-link)[0]; learnLink.href= )();

For Heroku lovers, there is a nicebuild adapter herethat helps deploy yourNext.jsapps to Heroku.

We have an index page that displaysHello Worldto the screen. Lets change that! The index page should display a list of game of thrones characters.

Now you are logged-in and theaccess tokenis present in Local Storage. You can now click on the link to have access to the account page.

© 2013-2016 Auth0 ® Inc. All Rights Reserved.

This is a special page that processes the information returned after a login attempt. This information is passed to theAuthServiceinstance so that Auth0.js can handle it. Nothing is rendered by this page.

Now, when we click on a character from the index page, we should be redirected to an account page that shows the full info of the character like so:

Every now and then, buzzwords pop up in the programming world and sometimes developers dont have a full grasp of these words. What is a Universal JavaScript app? What does the termUniversalmean in this context?

Open uppages/index.jsand modify the code to look like so:

import React from react export default class Error extends ponent static getInitialProps ( res, xhr ) const errorCode = res ? res.statusCode : xhr.status return errorCode render () return ( pAn error this.props.errorCode just occurred/p )

Finally, we have aLinkcomponent. We used theLinkcomponent thatnext.jsprovides. This enables client-side transitions between routes. TheLinkcomponent grabs the post id and links to an account route when clicked. Next, lets create the account route to be able to accept the id and render the appropriate content.

Open uputils/AuthService.jsand modify the code to look like this below:

We are building a very simple app today, it is calledNexThrone. The NexThrone app displays a list of Game of Thrones characters. It also provides a detailed information about each character when clicked upon. Well see howNext.jsmakes it so easy for us to build this server-rendered JavaScript web application.Next.jsdoes the heavy-lifting for us, while we focus on the applications core functionality! The full source code for the completed app can becloned at this GitHub repo.

Once you log in successfully, you will now have access to the links like so:

Its that simple. Now, we have a fully functional server-rendered universal JavaScript web application.

Any app. Any device. Hosted anywhere.

-10) $current.text(dateFormat); if (diff === 0) $current.text(Today); $current.addClass(rendered); ); // Social Buttons $(.social-stats work).cSButtons(); // Force content links to _blank if not explicitly set to _self $(.entry-content a).each(function() var _$this = $(this); var _target = _$this.attr(target); if (_target !== _self) _$this.attr(target, _blank); ); // Handle scroll pos if($(window).data(navScroll)) $(window).scrollTop($(window).data(navScroll)); $(window).data(navScroll, 0); else $(window).scrollTop(0); stickyElements(); function setEvents() nfigure( tabReplace: , // 4 spaces classPrefix: ); NProgress.configure( showSpinner: false, trickleSpeed: 600 ); metricsLib.page(); $(p).selectionSharer(); var selectionSharerFacebook = $(selectionSharerPopover-inner .action.facebook)[0]; $(selectionSharerFacebook).on(click, function() metricsLib.track(blog:share:custom:facebook); ); var selectionSharerTwitter = $(selectionSharerPopover-inner eet)[0]; $(selectionSharerTwitter).on(click, function() metricsLib.track(blog:share:custom:twitter); ); var selectionSharerEmail = $(selectionSharerPopover-inner .action.email)[0]; $(selectionSharerEmail).on(click, function() metricsLib.track(blog:share:custom:email); ); $(window).on(load, function() $(document.body).trigger(sticky_kit:recalc); ); $(body).on(click, .blog-navigation a, function() var tabs = $(.blog-navigation li); var activeTab = $(this).parent(); $(window).data(navScroll, $(window).scrollTop()); tabs.removeClass(active); activeTab.addClass(active); ); initialize(); setEvents(); );

NexThrone Index Non-loggedIn Status

User clicks on the login button and the Auth0 login screen displays like so:

import React from react import posts from ../data/posts import style from next/css import Link from next/link export default class extends ponent static getInitialProps () return posts: posts render () return ( div div className=style(styles.header) h3 NEXTHRONE – THE REVELATION OF GAME OF THRONES CHARACTERS /h3 /div table className=style(styles.table) thead tr th className=style(styles.th)Character/th th className=style(styles.th)Real Name/th /tr /thead tbody this.props.posts.map( (post, i) = ( tr key=i td className=style(styles.td) deName /td td className=style(styles.td) Link href=`/account?id=$post.id` post.realName /Link /td /tr )) /tbody /table /div ) const styles = th: background: 00cccc, color: fff, textTransform: uppercase, fontSize: 12px, padding: 12px 35px, , header: font: 15px Monaco, textAlign: center , table: fontFamily: Arial, margin: 25px auto, borderCollapse: collapse, border: 1px solid eee, borderBottom: 2px solid 00cccc , td: color: 999, border: 1px solid eee, padding: 12px 35px, borderCollapse: collapse , list: padding: 50px, textAlign: center , photo: display: inline-block , photoLink: color: 333, verticalAlign: middle, cursor: pointer, background: eee, display: inline-block, width: 250px, height: 250px, lineHeight: 250px, margin: 10px, border: 2px solid transparent, :hover: borderColor: blue

import React from react import posts from ../data/posts import style from next/css import * as _ from lodash export default ( url: query: id ) = const item = _.find(posts, id: id ) return ( div className=style(styles.main) div className=style(styles.header) h3 NEXTHRONE – THE REVELATION OF GAME OF THRONES CHARACTERS /h3 /div div className=style(styles.panel) h1 className=style(styles.heading) Character: deName br/ br/ Real Name: item.realName br/ br/ Brief Description: br/ br/ span item.story /span /h1 /div div className=style(styles.singlePhoto) img src= item.display_src alt=item.realName width=500 height=500 / /div /div ) const styles = main: padding: 50px , header: font: 15px Monaco, textAlign: center , panel: float: right, marginRight: 140px, width: 300px , singlePhoto: border: 1px solid 999, width: 500px, height: 500px, float: left , heading: font: 15px Monaco

Youll be getting lots of awesome content!

The creators ofNext.jsalso have a tool,nowthat you can deploy your app with. Check out the instructions on how to deployhere.

The officialNext.jsdocumentation usesnpm. Well useYarn, just because its faster and more effective. You havent tried Yarn before? check out5 things you can do with Yarn here.

Oncenext.jshas finished installing, open up yourpackage.jsonfile and add a script to it like so:

We still need to add one more special page for everything to work. Put this code in thepages/callback.jsfile:

In thecomponentDidMount, we just simply check if the user is logged in or not. If the user is not logged in, then the user will be redirected to the index page to log in.

Now, we have astylesobject in this file.Next.jsprovides us with astylefunction that we can use to select style properties and apply to DOM elements as shown in the example above.Next.jsleverages theglamorlibrary for the CSS-in-JS pattern. Another way of using CSS inside the JSX file withnext.jsis by importing thecssfunction fromnext/csslike so:

TL;DR:In the JavaScript land, there are a plethora of libraries and frameworks. And new libraries and frameworks keep showing up almost every other week. On Tuesday, October 25 2016, a small JavaScript framework,Next.jswas released to the public. Its a minimal framework for building server-rendered universal JavaScript web apps. In this article, Ill walk you through how to create a universal JavaScript web app withNext.js.

We are dealing with the game of thrones characters. So, we need their stage names, real names, bio and their avatars. Lets set up a file that contains such data.

The termUniversalsimply means the ability to run the same code on the server, browsers, mobile devices and any other platform.Universal Javascriptis a term people are leaning towards these days. A lot of developers still call itIsomorphic JavaScript. In short, there is a debate on theReact repoabout this term. Michael Jackson, a popular ReactJS developer wrote a blog post onUniversal JavaScript. Its indeed true thatnaming thingsis one of the most difficult aspects of Computer Science.

Replace client ID and Auth0 domain values in thesettingsobject with the values from yourdashboard. We created a state calledloggedInand instantiated the AuthService incomponentDidMount. Now Auth0.js is not isomorphic, so we need to load the script from the CDN to make it available in our component within the render method. Based on the state ofloggedIn, you will have the ability to have access to the link that redirects to the account or not!

Create a newdatadirectory in your root folder, then add aposts.jsfile to it.

Next.jsmakes good use of already written and well-tested modules from the JavaScript community. WithNext.js, every component inside thepages/directory gets server-rendered automatically and their scripts inlined. Wow! is it that easy? Yes!!!

); ); setTimeout(function() var banner = $(.banner); var dom = $(.banner .entry-thumbnail); if(getDOM === banner) dom = banner; else banner.addClass(export-icon); banner.addClass(export); html2canvas(dom.get(0), onrendered: function(canvas) var img = canvas.toDataURL(image/png); banner.removeClass(export); window.location = img; ); , 20); function convertToDataURLviaCanvas(url, callback, outputFormat) var img = new Image(); img.crossOrigin = Anonymous; img.onload = function() var canvas = document.createElement(CANVAS); var ctx = canvas.getContext(2d); var dataURL; canvas.height = this.height; canvas.width = this.width; ctx.drawImage(this, 0, 0); dataURL = canvas.toDataURL(outputFormat); callback(dataURL); canvas = null; ; img.src= url; ; var getBlogBanner = function() getBlogImage(banner); ; $(function() function stickyElements() function stickElement($elem, options) $elem.stick_in_parent(Object.assign(, offset_top: parseInt($elem.attr(data-sticky-padding)) 0 , options )); stickElement($(.sidebar-column)); stickElement($(.utility-bar)); stickElement($(.blog-navigation), parent: body); function initBlogSubscriber() if(localStorage.isBlogSubscriber !== true) $(form.newsletter-subscriber).removeClass(hide); function closeSticky($module, animation) $module.addClass(animated + animation ); $module.on(animationend webkitAnimationEnd oAnimationEnd, function () $module.remove() $(document.body).trigger(sticky_kit:recalc); ); $(form.newsletter-subscriber).on(click, [data-close], function() var $module = $(this).closest(form); closeSticky($module, fadeOutUp); ); $(.guest-author-widget).on(click, [data-close], function() var $module = $(this).closest(section); closeSticky($module, fadeOutRight); ); $(form.newsletter-subscriber).on(submit, function(e) var $module = $(this); var o_content = $module.html(); var value = $module.find(input).val(); e.preventDefault(); if(isValidEmail(value)) onValid(); else alert(Please enter a valid email); function isValidEmail(val) if(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]2,4)+$/.test(val)) return true; return false; function onValid() $module.find(.fields).html(

We need to restrict access to the account page if the user is not logged-in. If theaccess tokendoesnt exist, then it means the user has been logged out. So open up yourpages/account.jsand modify the code like so:

Create a new directory, cd into the directory and run this command below:

Leave a Comment