diff --git a/package.json b/package.json index 0420d71..a81ca6c 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ "dependencies": { "brace": "^0.5.1", "classnames": "^2.1.2", + "glamor": "^3.0.0-2", + "glamorous": "^3.23.5", "history": "^3.3.0", "markdown": "^0.5.0", "prop-types": "^15.5.10", @@ -53,4 +55,4 @@ "webpack": "^2.6.1", "webpack-dev-server": "^2.5.1" } -} \ No newline at end of file +} diff --git a/presentations/js-performance/Abandonment.js b/presentations/js-performance/Abandonment.js new file mode 100644 index 0000000..4df4b75 --- /dev/null +++ b/presentations/js-performance/Abandonment.js @@ -0,0 +1,13 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Link from './components/Link'; +import Attribution from './components/Attribution'; +import Statement from './components/Statement'; + +export default function () { + return ( + + 53% of mobile site visits are abandoned when pages take longer than 3 seconds to load + - Google Double Click + ); +} diff --git a/presentations/js-performance/Animation.js b/presentations/js-performance/Animation.js new file mode 100644 index 0000000..c3a4764 --- /dev/null +++ b/presentations/js-performance/Animation.js @@ -0,0 +1,14 @@ +import React from 'react'; +import css from 'glamor'; +import glamorous from 'glamorous'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import eventLoopSrc from './images/event-loop.png'; + +export default function () { + return ( + + Animation - 60fps + + ); +} diff --git a/presentations/js-performance/CostGuesstimate.js b/presentations/js-performance/CostGuesstimate.js new file mode 100644 index 0000000..d980f6d --- /dev/null +++ b/presentations/js-performance/CostGuesstimate.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import chartSrc from './images/perf-chart.png'; + +export default function () { + return ( + + optimization cost guesstimate + + ); +} diff --git a/presentations/js-performance/DaveQuote.js b/presentations/js-performance/DaveQuote.js new file mode 100644 index 0000000..62c5547 --- /dev/null +++ b/presentations/js-performance/DaveQuote.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Attribution from './components/Attribution'; +import Title from './components/Title'; + +export default function () { + return ( + + not measuring performance is the root of all evil + - Me + ); +} diff --git a/presentations/js-performance/FrameworkSpecific.js b/presentations/js-performance/FrameworkSpecific.js new file mode 100644 index 0000000..071ebc1 --- /dev/null +++ b/presentations/js-performance/FrameworkSpecific.js @@ -0,0 +1,11 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Statement from './components/Statement'; + +export default function () { + return ( + + react-addons-perf + ng-stats + ); +} \ No newline at end of file diff --git a/presentations/js-performance/Idle.js b/presentations/js-performance/Idle.js new file mode 100644 index 0000000..a6c9a81 --- /dev/null +++ b/presentations/js-performance/Idle.js @@ -0,0 +1,15 @@ +import React from 'react'; +import css from 'glamor'; +import glamorous from 'glamorous'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import Statement from './components/Statement'; + +export default function () { + return ( + + Idle - maximize idle time + perform background tasks + pre-load resources + ); +} diff --git a/presentations/js-performance/Intro.js b/presentations/js-performance/Intro.js new file mode 100644 index 0000000..fda12de --- /dev/null +++ b/presentations/js-performance/Intro.js @@ -0,0 +1,10 @@ +import React from 'react'; +import Slide from './components/Slide'; +import bunnySrc from './images/bunny.gif'; + +export default function () { + return ( + + bunny + ); +} diff --git a/presentations/js-performance/KnuthQuote.js b/presentations/js-performance/KnuthQuote.js new file mode 100644 index 0000000..ad3771d --- /dev/null +++ b/presentations/js-performance/KnuthQuote.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Attribution from './components/Attribution'; +import Title from './components/Title'; + +export default function () { + return ( + + premature optimization is the root of all evil + - Donald Knuth + ); +} diff --git a/presentations/js-performance/KnuthQuoteRevised.js b/presentations/js-performance/KnuthQuoteRevised.js new file mode 100644 index 0000000..16c1f75 --- /dev/null +++ b/presentations/js-performance/KnuthQuoteRevised.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Attribution from './components/Attribution'; +import Title from './components/Title'; + +export default function () { + return ( + + don't optimize before you measure + - What Donald Knuth really meant + ); +} diff --git a/presentations/js-performance/LazyCode.js b/presentations/js-performance/LazyCode.js new file mode 100644 index 0000000..e391148 --- /dev/null +++ b/presentations/js-performance/LazyCode.js @@ -0,0 +1,26 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import CodeBlock from '../../lib/components/CodeBlock'; + +const code = +`function init() { + const playAudio = () => { + fetchAudio().then(audio => audio.play()); + }; + + fetchBitmap().then( + bitmap => renderApp(bitmap, playAudio)); +} + +function fetchBitmap() { ... } + +function fetchAudio() { ... }`; + +export default function() { + return ( + + lazy code + { code } + ); +} diff --git a/presentations/js-performance/Load.js b/presentations/js-performance/Load.js new file mode 100644 index 0000000..059e485 --- /dev/null +++ b/presentations/js-performance/Load.js @@ -0,0 +1,36 @@ +import React from 'react'; +import css from 'glamor'; +import glamorous from 'glamorous'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import Statement from './components/Statement'; +import unicornSrc from './components/SparkleApp/images/unicorn.png'; + +const fadeIn = css.keyframes({ + '0%': {opacity: 0}, + '100%': {opacity: 0.5} +}); + +const Background = glamorous.div({ + position: 'absolute', + backgroundImage: `url(${unicornSrc})`, + backgroundRepeat: 'space', + backgroundPosition: 'center', + top: 0, + left: 0, + right: 0, + bottom: 0, + opacity: 0.5, + animation: `${fadeIn} 5s ease-in` +}); + +export default function () { + return ( + + Load - 1000 ms + initial site load + data and content loading + page and view change + + ); +} diff --git a/presentations/js-performance/Measurement.js b/presentations/js-performance/Measurement.js new file mode 100644 index 0000000..36af345 --- /dev/null +++ b/presentations/js-performance/Measurement.js @@ -0,0 +1,10 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; + +export default function () { + return ( + + develop a measurement plan + ); +} diff --git a/presentations/js-performance/OptimizeFramerate.js b/presentations/js-performance/OptimizeFramerate.js new file mode 100644 index 0000000..435d6d9 --- /dev/null +++ b/presentations/js-performance/OptimizeFramerate.js @@ -0,0 +1,13 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import SparkleApp from './components/SparkleApp'; +import { initWithLongFrames } from './components/SparkleApp/initialize'; + +export default function() { + return ( + + optimize framerate (animation) + + ); +} diff --git a/presentations/js-performance/OptimizeIdle.js b/presentations/js-performance/OptimizeIdle.js new file mode 100644 index 0000000..1e0da89 --- /dev/null +++ b/presentations/js-performance/OptimizeIdle.js @@ -0,0 +1,33 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import CodeBlock from '../../lib/components/CodeBlock'; + +const code = +`function init() { + fetchBitmap().then( + bitmap => { + const app = renderApp(bitmap); + + const idleCallback = requestIdleCallback || + requestAnimationFrame; + + idleCallback(() => { + fetchAudio().then( + audio => app.setAudio(audio)); + }); + } + ); +} + +function fetchBitmap() { ... } + +function fetchAudio() { ... }`; + +export default function() { + return ( + + use idle time to pre-fetch + { code } + ); +} diff --git a/presentations/js-performance/OptimizeLoad.js b/presentations/js-performance/OptimizeLoad.js new file mode 100644 index 0000000..b15af33 --- /dev/null +++ b/presentations/js-performance/OptimizeLoad.js @@ -0,0 +1,13 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import SparkleApp from './components/SparkleApp'; +import { initWithLargeImage } from './components/SparkleApp/initialize'; + +export default function() { + return ( + + optimize load time + + ); +} diff --git a/presentations/js-performance/OptimizeNetwork.js b/presentations/js-performance/OptimizeNetwork.js new file mode 100644 index 0000000..8d519f3 --- /dev/null +++ b/presentations/js-performance/OptimizeNetwork.js @@ -0,0 +1,14 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Statement from './components/Statement'; + +export default function () { + return ( + + minimize file count and size + configure cache headers + configure compression + use http2 + use a CDN + ); +} diff --git a/presentations/js-performance/OptimizeResponse.js b/presentations/js-performance/OptimizeResponse.js new file mode 100644 index 0000000..116d827 --- /dev/null +++ b/presentations/js-performance/OptimizeResponse.js @@ -0,0 +1,13 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import SparkleApp from './components/SparkleApp'; +import { initWithLazyAudio } from './components/SparkleApp/initialize'; + +export default function() { + return ( + + optimize response time + + ); +} diff --git a/presentations/js-performance/OptimizedApp.js b/presentations/js-performance/OptimizedApp.js new file mode 100644 index 0000000..ca5963a --- /dev/null +++ b/presentations/js-performance/OptimizedApp.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import SparkleApp from './components/SparkleApp'; + +export default function () { + return ( + + RAIL optimized + + ); +} diff --git a/presentations/js-performance/PageSpeedTools.js b/presentations/js-performance/PageSpeedTools.js new file mode 100644 index 0000000..65f607d --- /dev/null +++ b/presentations/js-performance/PageSpeedTools.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import pstSrc from './images/page-speed-tools.png'; + +export default function () { + return ( + + PageSpeed Tools (developers.google.com/speed) + + ); +} \ No newline at end of file diff --git a/presentations/js-performance/ParallelCode.js b/presentations/js-performance/ParallelCode.js new file mode 100644 index 0000000..7bb151c --- /dev/null +++ b/presentations/js-performance/ParallelCode.js @@ -0,0 +1,22 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import CodeBlock from '../../lib/components/CodeBlock'; + +const code = +`function init() { + Promise.all([fetchBitmap(), fetchAudio()]) + .then([bitmap, audio] => renderApp(bitmap, audio)); +} + +function fetchBitmap() { ... } + +function fetchAudio() { ... }`; + +export default function() { + return ( + + parallel code + { code } + ); +} diff --git a/presentations/js-performance/Plan.js b/presentations/js-performance/Plan.js new file mode 100644 index 0000000..1dfaa3f --- /dev/null +++ b/presentations/js-performance/Plan.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Statement from './components/Statement'; + +export default function () { + return ( + + Load and render app in < 1 second + Respond to Sparkle! in < 100ms + Animate sparkles at 60fps + ); +} diff --git a/presentations/js-performance/Rail.js b/presentations/js-performance/Rail.js new file mode 100644 index 0000000..af3a177 --- /dev/null +++ b/presentations/js-performance/Rail.js @@ -0,0 +1,30 @@ +import React from 'react'; +import glamorous from 'glamorous'; +import Slide from './components/Slide'; +import Title from './components/Title'; + +const Measurement = glamorous.div({ + textAlign: 'left', + width: '800px' +}); +const Label = glamorous.div({ + fontSize: '32px' +}); +const Emphasis = glamorous.span({ + fontSize: '96px', + fontWeight: 'bold', + marginRight: '8px' +}); + +export default function () { + return ( + + RAIL model + + + + + + + ); +} diff --git a/presentations/js-performance/RemoveSequential.js b/presentations/js-performance/RemoveSequential.js new file mode 100644 index 0000000..0864cac --- /dev/null +++ b/presentations/js-performance/RemoveSequential.js @@ -0,0 +1,13 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import SparkleApp from './components/SparkleApp'; +import { initWithSequentialAudio } from './components/SparkleApp/initialize'; + +export default function() { + return ( + + remove sequential blocking code + + ); +} diff --git a/presentations/js-performance/Response.js b/presentations/js-performance/Response.js new file mode 100644 index 0000000..81d2594 --- /dev/null +++ b/presentations/js-performance/Response.js @@ -0,0 +1,15 @@ +import React from 'react'; +import css from 'glamor'; +import glamorous from 'glamorous'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import Statement from './components/Statement'; + +export default function () { + return ( + + Response - 100ms + users perceive delays over 100ms + > 500ms should display indicator + ); +} diff --git a/presentations/js-performance/SequentialCode.js b/presentations/js-performance/SequentialCode.js new file mode 100644 index 0000000..ac99713 --- /dev/null +++ b/presentations/js-performance/SequentialCode.js @@ -0,0 +1,25 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import CodeBlock from '../../lib/components/CodeBlock'; + +const code = +`function init() { + fetchBitmap().then(bitmap => { + return fetchAudio().then(audio => { + renderApp(bitmap, audio); + }); + }); +} + +function fetchBitmap() { ... } + +function fetchAudio() { ... }`; + +export default function() { + return ( + + sequential code + { code } + ); +} diff --git a/presentations/js-performance/Sparkle.js b/presentations/js-performance/Sparkle.js new file mode 100644 index 0000000..ef3db8c --- /dev/null +++ b/presentations/js-performance/Sparkle.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import SparkleApp from './components/SparkleApp'; + +export default function () { + return ( + + Sparkle! the app + + ); +} diff --git a/presentations/js-performance/UserExpectation.js b/presentations/js-performance/UserExpectation.js new file mode 100644 index 0000000..7b9c451 --- /dev/null +++ b/presentations/js-performance/UserExpectation.js @@ -0,0 +1,10 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; + +export default function () { + return ( + + content vs responsiveness + ); +} diff --git a/presentations/js-performance/WebPageTest.js b/presentations/js-performance/WebPageTest.js new file mode 100644 index 0000000..8cc0c66 --- /dev/null +++ b/presentations/js-performance/WebPageTest.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Slide from './components/Slide'; +import Title from './components/Title'; +import wptSrc from './images/web-page-test.png'; + +export default function () { + return ( + + WebPageTest (www.webpagetest.org) + + ); +} \ No newline at end of file diff --git a/presentations/js-performance/components/Attribution.js b/presentations/js-performance/components/Attribution.js new file mode 100644 index 0000000..e991c6f --- /dev/null +++ b/presentations/js-performance/components/Attribution.js @@ -0,0 +1,6 @@ +import glamorous from 'glamorous'; + +export default glamorous.h3({ + textAlign: 'right', + marginRight: '100px' +}); \ No newline at end of file diff --git a/presentations/js-performance/components/Link.js b/presentations/js-performance/components/Link.js new file mode 100644 index 0000000..1c2c3b7 --- /dev/null +++ b/presentations/js-performance/components/Link.js @@ -0,0 +1,13 @@ +import glamorous from 'glamorous'; + +const color = '#999'; +const activeColor = '#FF80E1'; + +export default glamorous.a({ + color, + ':hover': { color: activeColor }, + ':visited': { + color, + ':hover': { color: activeColor } + } +}); \ No newline at end of file diff --git a/presentations/js-performance/components/Slide.js b/presentations/js-performance/components/Slide.js new file mode 100644 index 0000000..b10b549 --- /dev/null +++ b/presentations/js-performance/components/Slide.js @@ -0,0 +1,3 @@ +import glamorous from 'glamorous'; + +export default glamorous.div(); \ No newline at end of file diff --git a/presentations/js-performance/components/SparkleApp/ParticleCloud.js b/presentations/js-performance/components/SparkleApp/ParticleCloud.js new file mode 100644 index 0000000..2a3a168 --- /dev/null +++ b/presentations/js-performance/components/SparkleApp/ParticleCloud.js @@ -0,0 +1,107 @@ +const colorPalette = [ + '#029DAF', + '#E5D599', + '#FFC219', + '#FF80E1' +]; + +function isInBounds(config, particle) { + const { canvas } = config; + + if (config.longFrame) { + const calculateBounds = (delay) => { + const start = Date.now(); + while (Date.now() - start < delay) {} + } + calculateBounds(3); + } + + return particle.x - particle.size < canvas.width && + particle.x + particle.size > 0 && + particle.y - particle.size < canvas.height && + particle.y + particle.size > 0; +} + +function drawParticle(config, particle) { + const { canvas, ctx, gravity, velocity } = config; + + particle.vy += 0.04 * velocity; + particle.x += particle.vx * velocity; + particle.y += particle.vy * velocity; + particle.opacity -= 0.005; + + ctx.globalAlpha = particle.opacity; + ctx.fillStyle = particle.color; + ctx.fillRect(particle.x, particle.y, particle.size, particle.size); + + return isInBounds(config, particle); +} + +function initParticles(config) { + const particles = []; + for (let i = 0; i < config.particleCount; i++) { + const colorIdx = i % colorPalette.length; + const particle = { + color: colorPalette[colorIdx], + opacity: 0.5 + Math.random() * 0.5, + size: 6 + Math.random() * 6, + x: config.startX, + y: config.startY, + vx: (Math.random() * 3) + 1, + vy: (Math.random() * -2) - 1 + }; + + particles.push(particle); + } + + return particles; +} + +function drawBackground(config) { + const { canvas, ctx, backgroundBitmap } = config; + ctx.clearRect(0, 0, canvas.width, canvas.height); + + ctx.globalAlpha = 1; + ctx.drawImage(backgroundBitmap, 50, 0, 386, 500); +} + +export default class ParticleCloud { + constructor(canvas, backgroundBitmap, longFrame = false) { + this.config = { + canvas, + ctx: canvas.getContext('2d'), + longFrame, + particleCount: 50, + backgroundBitmap, + startX: 280, + startY: 320, + velocity: 1 + }; + + drawBackground(this.config); + } + + animate() { + this.activeParticles = (this.activeParticles || []).concat(initParticles(this.config)); + + if (!this._animate) { + this._animate = () => { + if (this._animate) { + const { ctx } = this.config; + + drawBackground(this.config); + this.activeParticles = this.activeParticles.filter((particle) => { + return drawParticle(this.config, particle); + }); + + window.requestAnimationFrame(this._animate); + } + }; + this._animate(); + } + } + + end() { + this._animate = null; + } +} diff --git a/presentations/js-performance/components/SparkleApp/audio/taste-the-rainbow.m4a b/presentations/js-performance/components/SparkleApp/audio/taste-the-rainbow.m4a new file mode 100644 index 0000000..6ec7821 Binary files /dev/null and b/presentations/js-performance/components/SparkleApp/audio/taste-the-rainbow.m4a differ diff --git a/presentations/js-performance/components/SparkleApp/images/unicorn-large.png b/presentations/js-performance/components/SparkleApp/images/unicorn-large.png new file mode 100644 index 0000000..1252e88 Binary files /dev/null and b/presentations/js-performance/components/SparkleApp/images/unicorn-large.png differ diff --git a/presentations/js-performance/components/SparkleApp/images/unicorn.png b/presentations/js-performance/components/SparkleApp/images/unicorn.png new file mode 100644 index 0000000..adb7824 Binary files /dev/null and b/presentations/js-performance/components/SparkleApp/images/unicorn.png differ diff --git a/presentations/js-performance/components/SparkleApp/index.js b/presentations/js-performance/components/SparkleApp/index.js new file mode 100644 index 0000000..6d94b7a --- /dev/null +++ b/presentations/js-performance/components/SparkleApp/index.js @@ -0,0 +1,100 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import glamorous from 'glamorous'; +import ParticleCloud from './ParticleCloud'; +import { initOptimized } from './initialize'; + +const SparkleButton = glamorous.button({ + fontSize: '32px', + backgroundColor: '#FF80E1', + borderRadius: '4px', + width: '100%', + zIndex: 100 +}); + +function sparkle(audio, particleCloud) { + if (audio) { + audio.currentTime = 0; + audio.play(); + } + + if (particleCloud) { + particleCloud.animate(); + } +} + +export default class SparkleApp extends React.Component { + static defaultProps = { + initResources: initOptimized + }; + + constructor(props) { + super(props); + + this.canvasRef = this.canvasRef.bind(this); + this.onSparkleClick = this.onSparkleClick.bind(this); + } + + componentDidMount() { + this.props.initResources().then(resources => { + // support different methods of audio initialization for demo purposes. + if (resources.idleAudio) { + const idleCallback = requestIdleCallback || requestAnimationFrame; + idleCallback(() => { + resources.idleAudio().then(audio => { + this.audio = audio; + }); + }); + } else if (resources.lazyAudio) { + this.lazyAudio = resources.lazyAudio; + } else if (resources.audio) { + this.audio = resources.audio; + } + + this.particleCloud = new ParticleCloud( + this.canvas, + resources.bitmap, + resources.longFrame || false); + }); + } + + componentWillUnmount() { + if (this.particleCloud) { + this.particleCloud.end(); + this.particleCloud = null; + } + + if (this.audio) { + this.audio = null; + } + } + + render() { + return ( +
+ + + Sparkle! + +
+ ); + } + + canvasRef(canvas) { + this.canvas = canvas; + } + + onSparkleClick(e) { + e.stopPropagation(); + e.preventDefault(); + + if (this.lazyAudio) { + this.lazyAudio().then(audio => { + sparkle(audio, this.particleCloud); + }); + } else if (this.audio) { + sparkle(this.audio, this.particleCloud); + } + } +} \ No newline at end of file diff --git a/presentations/js-performance/components/SparkleApp/initialize.js b/presentations/js-performance/components/SparkleApp/initialize.js new file mode 100644 index 0000000..a1d41fc --- /dev/null +++ b/presentations/js-performance/components/SparkleApp/initialize.js @@ -0,0 +1,74 @@ +import largeUnicornSrc from './images/unicorn-large.png'; +import unicornSrc from './images/unicorn.png'; +import rainbowSrc from './audio/taste-the-rainbow.m4a'; + +const slowAudioDelay = 900; + +function loadBitmap(imgSrc) { + return fetch(imgSrc).then(response => { + return response.blob().then(window.createImageBitmap); + }); +} + +function createAudio(blob, delay) { + const bufferAudio = (delay) => { + const start = Date.now(); + while (Date.now() - start < delay) {} + } + bufferAudio(delay); + + return new Audio(URL.createObjectURL(blob)); +} + +function loadAudio(delay = 0) { + return fetch(rainbowSrc).then(response => { + return response.blob().then(blob => createAudio(blob, delay)); + }); +} + +export function initWithLargeImage() { + return loadBitmap(largeUnicornSrc).then(bitmap => { + return loadAudio(slowAudioDelay).then(audio => { + return { + audio, + bitmap + }; + }); + }); +} + +export function initWithSequentialAudio() { + return loadBitmap(unicornSrc).then(bitmap => { + return loadAudio(slowAudioDelay).then(audio => { + return { + audio, + bitmap + }; + }); + }); +} + +export function initWithLazyAudio() { + return loadBitmap(unicornSrc).then(bitmap => { + return { + lazyAudio: () => loadAudio(slowAudioDelay), + bitmap + }; + }); +} + +export function initWithLongFrames() { + return initOptimized().then(resources => { + resources.longFrame = true; + return resources; + }); +} + +export function initOptimized() { + return loadBitmap(unicornSrc).then(bitmap => { + return { + idleAudio: loadAudio, + bitmap + }; + }); +} \ No newline at end of file diff --git a/presentations/js-performance/components/Statement.js b/presentations/js-performance/components/Statement.js new file mode 100644 index 0000000..83acc12 --- /dev/null +++ b/presentations/js-performance/components/Statement.js @@ -0,0 +1,3 @@ +import glamorous from 'glamorous'; + +export default glamorous.h2(); \ No newline at end of file diff --git a/presentations/js-performance/components/Title.js b/presentations/js-performance/components/Title.js new file mode 100644 index 0000000..3972839 --- /dev/null +++ b/presentations/js-performance/components/Title.js @@ -0,0 +1,3 @@ +import glamorous from 'glamorous'; + +export default glamorous.h1(); \ No newline at end of file diff --git a/presentations/js-performance/images/bunny.gif b/presentations/js-performance/images/bunny.gif new file mode 100644 index 0000000..bb15327 Binary files /dev/null and b/presentations/js-performance/images/bunny.gif differ diff --git a/presentations/js-performance/images/event-loop.png b/presentations/js-performance/images/event-loop.png new file mode 100644 index 0000000..1ee7ef8 Binary files /dev/null and b/presentations/js-performance/images/event-loop.png differ diff --git a/presentations/js-performance/images/page-speed-tools.png b/presentations/js-performance/images/page-speed-tools.png new file mode 100644 index 0000000..026883c Binary files /dev/null and b/presentations/js-performance/images/page-speed-tools.png differ diff --git a/presentations/js-performance/images/perf-chart.png b/presentations/js-performance/images/perf-chart.png new file mode 100644 index 0000000..3e48c0a Binary files /dev/null and b/presentations/js-performance/images/perf-chart.png differ diff --git a/presentations/js-performance/images/web-page-test.png b/presentations/js-performance/images/web-page-test.png new file mode 100644 index 0000000..75f95d6 Binary files /dev/null and b/presentations/js-performance/images/web-page-test.png differ diff --git a/presentations/js-performance/slideList.js b/presentations/js-performance/slideList.js new file mode 100644 index 0000000..3c83457 --- /dev/null +++ b/presentations/js-performance/slideList.js @@ -0,0 +1,65 @@ +import React from 'react'; + +import Intro from './Intro'; +import KnuthQuote from './KnuthQuote'; +import KnuthQuoteRevised from './KnuthQuoteRevised'; +import Abandonment from './Abandonment'; +import CostGuesstimate from './CostGuesstimate'; +import DaveQuote from './DaveQuote'; +import Measurement from './Measurement'; +import UserExpectation from './UserExpectation'; +import Sparkle from './Sparkle'; +import Rail from './Rail'; +import Load from './Load'; +import Idle from './Idle'; +import Response from './Response'; +import Animation from './Animation'; +import Plan from './Plan'; +import OptimizeLoad from './OptimizeLoad'; +import OptimizeNetwork from './OptimizeNetwork'; +import RemoveSequential from './RemoveSequential'; +import SequentialCode from './SequentialCode'; +import ParallelCode from './ParallelCode'; +import LazyCode from './LazyCode'; +import OptimizeResponse from './OptimizeResponse'; +import OptimizeIdle from './OptimizeIdle'; +import OptimizeFramerate from './OptimizeFramerate'; +import OptimizedApp from './OptimizedApp'; +import WebPageTest from './WebPageTest'; +import PageSpeedTools from './PageSpeedTools'; +import FrameworkSpecific from './FrameworkSpecific'; + +const slideComponents = [ + Intro, + KnuthQuote, + KnuthQuoteRevised, + Abandonment, + CostGuesstimate, + DaveQuote, + Measurement, + UserExpectation, + Sparkle, + Rail, + Load, + Idle, + Response, + Animation, + Plan, + OptimizeLoad, + OptimizeNetwork, + RemoveSequential, + SequentialCode, + ParallelCode, + LazyCode, + OptimizeResponse, + OptimizeIdle, + OptimizeFramerate, + OptimizedApp, + WebPageTest, + PageSpeedTools, + FrameworkSpecific +]; + +export default slideComponents.map((SlideComponent, idx) => { + return ; +}); diff --git a/webpack.config.js b/webpack.config.js index 633180b..9698210 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -47,7 +47,7 @@ module.exports = { loaders: ["babel-loader"] }, { - test: /\.((gif)|(png)|(jpg)|(html)|(mp4)|(mov))$/, + test: /\.((gif)|(png)|(jpg)|(html)|(mp4)|(mov)|(m4a))$/, loader: "file-loader?name=[name].[ext]" } ]