Giter Site home page Giter Site logo

frontend-nanodegree-mobile-portfolio's Introduction

Website Performance Optimization portfolio project

Your challenge, if you wish to accept it (and we sure hope you will), is to optimize this online portfolio for speed! In particular, optimize the critical rendering path and make this page render as quickly as possible by applying the techniques you've picked up in the Critical Rendering Path course.

To get started, check out the repository and inspect the code.

Getting started

Part 1: Optimize PageSpeed Insights score for index.html

Some useful tips to help you get started:

  1. Check out the repository
  2. To inspect the site on your phone, you can run a local server
$> cd /path/to/your-project-folder
$> python -m SimpleHTTPServer 8080
  1. Open a browser and visit localhost:8080
  2. Download and install ngrok to the top-level of your project directory to make your local server accessible remotely.
$> cd /path/to/your-project-folder
$> ./ngrok http 8080
  1. Copy the public URL ngrok gives you and try running it through PageSpeed Insights! Optional: More on integrating ngrok, Grunt and PageSpeed.

Profile, optimize, measure... and then lather, rinse, and repeat. Good luck!

Part 2: Optimize Frames per Second in pizza.html

To optimize views/pizza.html, you will need to modify views/js/main.js until your frames per second rate is 60 fps or higher. You will find instructive comments in main.js.

You might find the FPS Counter/HUD Display useful in Chrome developer tools described here: Chrome Dev Tools tips-and-tricks.

Optimization Tips and Tricks

Customization with Bootstrap

The portfolio was built on Twitter's Bootstrap framework. All custom styles are in dist/css/portfolio.css in the portfolio repo.

Archival Note

This repository is deprecated; therefore, we are going to archive it. However, learners will be able to fork it to their personal Github account but cannot submit PRs to this repository. If you have any issues or suggestions to make, feel free to:

frontend-nanodegree-mobile-portfolio's People

Contributors

aaronbutler avatar cameronwp avatar durant-udacity avatar hkasemir avatar mrk-nguyen avatar nicolasartman avatar safadurimo avatar sudkul avatar susansmith avatar walesmd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

frontend-nanodegree-mobile-portfolio's Issues

Unclosed container

Hi, not sure if deliberate (didn't see it mentioned in the course content thus far!) but the div container tag is not closed in index.html

Small corrections you should make.

The file project-webperf.html, line 8:

<title>Cameron Pitman: Portfolio</title>

Every other page says Pittman, not Pitman.


The file project-2048.html, line 41:

<img class="img-responsive" src="http://cameronwp.github.io/udportfolio/img/2048.png">

That image file is hosted at that link, but I believe what you really meant was this instead...

<img class="img-responsive" src="img/2048.png">

...because the same file is also hosted there, in this repo's assets, and that's the only place students will have any control over the optimization of 2048.png — line 41 stands out from all other links to images in the repo img folder, so I'm pretty sure you meant my suggestion instead line 41.


The file views/js/main.js, lines 152–213:
(seems to have been resolved in a commit)

function getAdj(x){
  switch(x) {
    case "dark": [. . .]
    case "color": [. . .]
    case "whimsical": [. . .]
    case "shiny": [. . .]
    case "noisy": [. . .]
    case "apocalyptic": [. . .]
    case "insulting": [. . .]
    case "praise": [. . .]
    case "scientific": [. . .]
    default: [. . .]
  };
};

The final two semicolons are un-necessary. This same mistake happens again in exactly the same way for the next function, getNoun, as shown below.


The file views/js/main.js, lines 216–283:
(seems to have been resolved in a commit)

function getNoun(y) {
  switch(y) {
    [. . .]
  };
};

A problem identical to the one just described above — there are two un-necessary semicolons.


The file views/js/main.js, lines 202–206:
(seems to have been resolved in a commit)

case "scientific":
      var scientific = ["scientific", "technical", "digital", "programming", "calculating", "formulating", "cyberpunk", "mechanical", "technological", 
      "innovative", "brainy", "chemical", "quantum", "astro", "space", "theoretical", "atomic", "electronic", "gaseous", "investigative", "solar", 
      "extinct", "galactic"]
      return scientific;

Missing semicolon. The same semicolon is missing on line 210 where the same code was copy-pasted to make a default case for the switch statement. (It seems Cameron added default cases of "scientific" and "scifi" for the random adjective and noun generators — he loves science and physics but does he have enough scientific integrity to acknowledge the incontrovertible fact of controlled demolitions on 9/11, I wonder...?)

The semicolon is also missing at the code's source, so this seems to be a case of copying code with errors in it, with no linting.


The file views/js/main.js, lines 152–213:

function getAdj(x){
  switch(x) {
    case "dark": 
      var dark = [...];
      return dark;
    case "color": 
      var colors = [...];
      return colors;
    case "whimsical": 
      var whimsy = [...];
      return whimsy;
    case "shiny":
      var shiny = [...];
      return shiny;
    case "noisy":
      var noisy = [...];
      return noisy;
    case "apocalyptic":
      var apocalyptic = [...];
      return apocalyptic;
    case "insulting":
      var insulting = [...];
      return insulting;
    case "praise":
      var praise = [...];
      return praise;
    case "scientific":
      var scientific = [...];
      return scientific;
    default:
      var scientific = [...];
      return scientific;
  }
}

Besides the extraneous semicolons already mentioned, and besides the missing semicolon already mentioned, there is a bug that no linter will catch. Examine the execution path the app takes based on lines 285–303 of the same file:

var adjectives = ["dark", "color", "whimsical", "shiny", "noise", "apocalyptic", "insulting", "praise", "scientific"];
var nouns = ["animals", "everyday", "fantasy", "gross", "horror", "jewelry", "places", "scifi"];

// Generates random numbers for getAdj and getNoun functions and returns a new pizza name
function generator(adj, noun) {
  var adjectives = getAdj(adj);
  var nouns = getNoun(noun);
  var randomAdjective = parseInt(Math.random() * adjectives.length);
  var randomNoun = parseInt(Math.random() * nouns.length);
  var name = "The " + adjectives[randomAdjective].capitalize() + " " + nouns[randomNoun].capitalize();
  return name;
};

// Chooses random adjective and random noun
function randomName() {
  var randomNumberAdj = parseInt(Math.random() * adjectives.length);
  var randomNumberNoun = parseInt(Math.random() * nouns.length);
  return generator(adjectives[randomNumberAdj], nouns[randomNumberNoun]);
};

The bug here is that getAdj(adj) sometimes evaluates as getAdj('noise') (the 'noise' is passed in from line 302, and it needs to be 'noisy' instead!), and getAdj('noise') is (almost) undefined! It is undefined for the original source code, but in this file, it hits the default case and returns the scientific adjectives array.

So you're never returning any of the "noisy" adjectives from the switch block in getAdj. That's a full bug in the original (the original works when you select "noisy" from the drop-down menu, but it fails when the randomName function runs), but it's just kind of an unobserveable bug in Cameron's Udacity version.

You never get "noisy" adjectives, but users never know that noisy adjectives are possible, so they don't know there's any problem.

Long story short, to fix a bug, you should change "noise" to "noisy" on line 285.


The file views/js/main.js, line 370:

pizzaContainer  = document.createElement("div");

There are two spaces before the =, for no reason.


The file views/js/main.js, line 430:

//TODO: change to 3 sizes? no more xl?

That to-do is ta-done! The app is working with 3 sizes and there is no longer any trace of xl.


The file views/js/main.js, line 494:

console.log("Average time to generate last 10 frames: " + sum / 10 + "ms");

This might be too misleading for students, because it's only reporting the amount of time spent in JavaScript on average for the last 10 frames — while the browser may be spending large chunks of time each frame on Rendering and Painting.

Maybe this distinction is too small to care about, but it would be more correct to write something along the lines of "Average time scripting last 10 frames".


resizePizzas function using User Timing API incorrectly

The file views/js/main.js lines 402–467:

var resizePizzas = function(size) { 
  window.performance.mark("mark_start_resize");   // User Timing API function

  // Changes the value for the size of the pizza above the slider
  function changeSliderLabel(size) {
    ...
  }

  changeSliderLabel(size);

  // Returns the size difference to change a pizza element from one size to another. Called by changePizzaSlices(size).
  function determineDx (elem, size) {
    ...
  }

  // Iterates through pizza elements on the page and changes their widths
  function changePizzaSizes(size) {
    ...
  }

  changePizzaSizes(size);

  // User Timing API is awesome
  window.performance.mark("mark_end_resize");
  window.performance.measure("measure_pizza_resize", "mark_start_resize", "mark_end_resize");
      var timeToResize = window.performance.getEntriesByName("measure_pizza_resize");
      console.log("Time to resize pizzas: " + timeToResize[0].duration + "ms");
}

The problem here (and since it's more serious than all the problems I found in this issue, I am reporting it as a separate issue ) is that the code fails to report correctly after the first time a user resizes the pizzas with the slider bar.

Even though the resizePizzas code runs freshly from the top each time, the Timing API function window.performance.getEntriesByName(string) function returns an array based on data that isn't freshly renewed. Timing API remembers all of the measure_pizza_resize measurements and the array it returns contains each one.

So if you resize once, it reports element 0's duration and that is perfect.

But when you move the sliderbar and resize the pizzas again, the timeToResize array at element 0 has the data from the first resize and it re-reports old data and that is a failure. (The element at index 1 would contain the data we need to make the function perfectly in this case.)

To fix this, I think you can either make use of the clearMeasures method which is explained at the link on line 12 of the same file, and also at the W3, or change the code inside of resizePizzas to let it report from the correct measure_pizza_resize measures.


Technically, you have the exact same problem on line 481.

However, the problem shouldn't be visible to users because the performance measure there should only ever happen when the whole page loads or refreshes, and under those conditions the array will always be one element big, and thus timeToGenerate[0] always shows the correct measure.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.