├── .gitignore ├── 0-base-app ├── .babelrc ├── .eslintrc.js ├── README.md ├── package.json ├── src │ ├── assets │ │ └── background.svg │ ├── browserslist │ ├── components │ │ ├── Cell.js │ │ ├── DesertScene.js │ │ ├── Heading.js │ │ ├── Nav.js │ │ └── Subheading.js │ ├── index.js │ ├── lib │ │ ├── SkyShader.js │ │ └── cactusModel.json │ └── views │ │ ├── about.js │ │ ├── countdown.js │ │ └── home.js ├── webpack.config.js └── yarn.lock ├── 1-scope-hoisting ├── .babelrc ├── .eslintrc.js ├── README.md ├── package.json ├── src │ ├── assets │ │ └── background.svg │ ├── browserslist │ ├── components │ │ ├── Cell.js │ │ ├── DesertScene.js │ │ ├── Heading.js │ │ ├── Nav.js │ │ └── Subheading.js │ ├── index.js │ ├── lib │ │ ├── SkyShader.js │ │ └── cactusModel.json │ └── views │ │ ├── about.js │ │ ├── countdown.js │ │ └── home.js ├── webpack.config.js └── yarn.lock ├── 3-dynamic-import ├── .babelrc ├── .eslintrc.js ├── README.md ├── package.json ├── src │ ├── assets │ │ └── background.svg │ ├── browserslist │ ├── components │ │ ├── Cell.js │ │ ├── DesertScene.js │ │ ├── Heading.js │ │ ├── Nav.js │ │ └── Subheading.js │ ├── index.js │ ├── lib │ │ ├── SkyShader.js │ │ └── cactusModel.json │ └── views │ │ ├── about.js │ │ ├── countdown.js │ │ └── home.js ├── webpack.config.js └── yarn.lock ├── 4-deterministic-hashes ├── .babelrc ├── .eslintrc.js ├── README.md ├── package.json ├── src │ ├── assets │ │ └── background.svg │ ├── browserslist │ ├── components │ │ ├── Cell.js │ │ ├── DesertScene.js │ │ ├── Heading.js │ │ ├── Nav.js │ │ └── Subheading.js │ ├── index.js │ ├── lib │ │ ├── SkyShader.js │ │ └── cactusModel.json │ └── views │ │ ├── about.js │ │ ├── countdown.js │ │ └── home.js ├── webpack.config.js └── yarn.lock ├── 5-commons-chunk ├── .babelrc ├── .eslintrc.js ├── README.md ├── package.json ├── src │ ├── assets │ │ └── background.svg │ ├── browserslist │ ├── components │ │ ├── Cell.js │ │ ├── DesertScene.js │ │ ├── Heading.js │ │ ├── Nav.js │ │ └── Subheading.js │ ├── index.js │ ├── lib │ │ ├── SkyShader.js │ │ └── cactusModel.json │ └── views │ │ ├── about.js │ │ ├── countdown.js │ │ └── home.js ├── webpack.config.js └── yarn.lock ├── 6-offline-plugin ├── .babelrc ├── .eslintrc.js ├── README.md ├── package.json ├── src │ ├── assets │ │ └── background.svg │ ├── browserslist │ ├── components │ │ ├── Cell.js │ │ ├── DesertScene.js │ │ ├── Heading.js │ │ ├── Nav.js │ │ └── Subheading.js │ ├── index.js │ ├── lib │ │ ├── SkyShader.js │ │ └── cactusModel.json │ └── views │ │ ├── about.js │ │ ├── countdown.js │ │ └── home.js ├── webpack.config.js └── yarn.lock ├── 7-webpack-bundle-analyzer ├── .babelrc ├── .eslintrc.js ├── README.md ├── package.json ├── src │ ├── assets │ │ └── background.svg │ ├── browserslist │ ├── components │ │ ├── Cell.js │ │ ├── DesertScene.js │ │ ├── Heading.js │ │ ├── Nav.js │ │ └── Subheading.js │ ├── index.js │ ├── lib │ │ ├── SkyShader.js │ │ └── cactusModel.json │ └── views │ │ ├── about.js │ │ ├── countdown.js │ │ └── home.js ├── stats.json ├── webpack.config.js └── yarn.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | -------------------------------------------------------------------------------- /0-base-app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"], 3 | "plugins": ["transform-react-jsx"] 4 | } 5 | -------------------------------------------------------------------------------- /0-base-app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb" 3 | }; -------------------------------------------------------------------------------- /0-base-app/README.md: -------------------------------------------------------------------------------- 1 | # Base App 2 | 3 | This is the plain, unoptimized version of an application, with a minimal 4 | webpack config. 5 | 6 | | Bundles | Before uglification | Uglified, `NODE_ENV=production` | Uglified, production, & gzipped | 7 | |------------|--------------------:|--------------------------------:|--------------------------------:| 8 | | `index.js` | 2.46MB | 986kB | 266KB | 9 | -------------------------------------------------------------------------------- /0-base-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "engines": { 3 | "node": "8.1.4" 4 | }, 5 | "scripts": { 6 | "build": "node_modules/.bin/webpack -p", 7 | "dev": "node_modules/.bin/webpack-dev-server" 8 | }, 9 | "dependencies": { 10 | "babel-core": "^6.25.0", 11 | "babel-loader": "^7.1.1", 12 | "babel-plugin-transform-react-jsx": "^6.24.1", 13 | "babel-preset-env": "^1.6.0", 14 | "file-loader": "^0.11.2", 15 | "html-webpack-plugin": "^2.29.0", 16 | "html-webpack-template": "^6.0.1", 17 | "moment": "^2.18.1", 18 | "react": "^15.6.1", 19 | "react-dom": "^15.6.1", 20 | "react-router": "^4.1.1", 21 | "react-router-dom": "^4.1.1", 22 | "styled-components": "^2.1.1", 23 | "three": "^0.86.0", 24 | "webpack": "^3.1.0", 25 | "webpack-dev-server": "^2.5.1" 26 | }, 27 | "devDependencies": { 28 | "eslint": "^3.19.0", 29 | "eslint-config-airbnb": "^15.0.2", 30 | "eslint-plugin-import": "^2.7.0", 31 | "eslint-plugin-jsx-a11y": "^5.1.1", 32 | "eslint-plugin-react": "^7.1.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /0-base-app/src/assets/background.svg: -------------------------------------------------------------------------------- 1 | Asset 2 -------------------------------------------------------------------------------- /0-base-app/src/browserslist: -------------------------------------------------------------------------------- 1 | > 5% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /0-base-app/src/components/Cell.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cell 3 | * Width-limiting container 4 | */ 5 | 6 | import styled from 'styled-components'; 7 | 8 | const Cell = styled.div` 9 | display: block; 10 | margin-left: auto; 11 | margin-right: auto; 12 | max-width: 800px; 13 | padding-left: 16px; 14 | padding-right: 16px; 15 | `; 16 | 17 | export default Cell; 18 | -------------------------------------------------------------------------------- /0-base-app/src/components/DesertScene.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Desert Scene 3 | * In the desert, you can’t remember your name… 4 | */ 5 | 6 | import React from 'react'; 7 | import * as THREE from 'three'; 8 | import ReactDOM from 'react-dom'; 9 | 10 | const cactusModel = require('../lib/cactusModel.json'); 11 | 12 | class DesertScene extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.paint.bind(this); 16 | } 17 | 18 | componentDidMount() { 19 | const canvasBox = this.canvas.getBoundingClientRect(); 20 | const canvasWidth = canvasBox.width; 21 | const canvasHeight = canvasBox.width * 0.4255; 22 | 23 | this.scene = new THREE.Scene(); 24 | this.scene.background = new THREE.Color(0xc8faeb); 25 | this.camera = new THREE.PerspectiveCamera(20, canvasWidth/canvasHeight, 0.1, 1000); 26 | this.camera.position.z = 100; 27 | this.renderer = new THREE.WebGLRenderer(); 28 | this.renderer.setPixelRatio(window.devicePixelRatio); 29 | this.renderer.setSize(canvasWidth, canvasHeight); 30 | this.canvas.appendChild(this.renderer.domElement); 31 | this.scene.add(this.camera); 32 | 33 | const lights = []; 34 | lights[0] = new THREE.HemisphereLight(0xffffbb, 0xf89316, 1); 35 | this.scene.add(lights[0]); 36 | 37 | // 🌵 38 | const cactusGeometry = new THREE.JSONLoader().parse(cactusModel).geometry; 39 | const cactusMaterial = new THREE.MeshPhongMaterial({ color: 0xA9DCAA, shininess: 50 }); 40 | for (var n = 0; n < 50; n += 1) { 41 | const cactus = new THREE.Mesh(cactusGeometry, cactusMaterial); 42 | cactus.position.x = Math.random() * 400 - 200; 43 | cactus.position.z = Math.random() * 400 - 200; 44 | cactus.rotation.y = Math.random() * 2 * Math.PI; 45 | const scalefactor = Math.random() * 4; 46 | cactus.scale.set(scalefactor, scalefactor, scalefactor); 47 | this.scene.add(cactus); 48 | } 49 | 50 | // 🏜 51 | this.desert = new THREE.Mesh( 52 | new THREE.BoxGeometry(500, 0.1, 500), 53 | new THREE.MeshPhongMaterial({ color: 0xe3d9c0 }), 54 | ); 55 | this.desert.rotation.x = Math.PI; 56 | this.scene.add(this.desert); 57 | this.paint(); 58 | } 59 | 60 | paint(frame) { 61 | const rotationSpeed = frame / 4000; 62 | this.camera.position.set( 63 | 100 * Math.sin(rotationSpeed), 64 | 10, 65 | 100 * Math.cos(rotationSpeed), 66 | ); 67 | this.desert.rotation.y += 0.01; 68 | this.camera.lookAt(this.scene.position); 69 | 70 | this.renderer.render(this.scene, this.camera); 71 | window.requestAnimationFrame(nextFrame => this.paint(nextFrame)); 72 | } 73 | 74 | render() { 75 | return
this.canvas = canvas} />; 76 | } 77 | } 78 | 79 | export default DesertScene; 80 | -------------------------------------------------------------------------------- /0-base-app/src/components/Heading.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Heading 3 | * Big Text 4 | */ 5 | 6 | import styled from 'styled-components'; 7 | 8 | const Heading = styled.div` 9 | background-color: #00ce67; 10 | color: white; 11 | font-size: 2.4em; 12 | font-weight: 700; 13 | line-height: 1.2; 14 | margin-bottom: 1em; 15 | margin-top: 0; 16 | padding-bottom: 16px; 17 | padding-top: 16px; 18 | text-align: center; 19 | `; 20 | 21 | export default Heading; 22 | -------------------------------------------------------------------------------- /0-base-app/src/components/Nav.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Nav 3 | * It goes where you go 4 | */ 5 | 6 | import React from 'react'; 7 | import { Link } from 'react-router-dom'; 8 | import styled from 'styled-components'; 9 | 10 | const Nav = styled.nav` 11 | background-color: white; 12 | box-shadow: 0 2px 4px rgba(0, 8, 16, 0.2); 13 | display: flex; 14 | margin-bottom: 32px; 15 | margin-left: 0; 16 | margin-right: 0; 17 | padding: 32px; 18 | `; 19 | 20 | const NavLink = styled.div` 21 | font-weight: 700; 22 | margin-left: 16px; 23 | margin-right: 16px; 24 | 25 | & a { 26 | color: #00ce67; 27 | text-decoration: none; 28 | transition: color 200ms; 29 | 30 | &:focus, 31 | &:hover { 32 | color: #00b85f; 33 | } 34 | } 35 | `; 36 | 37 | export default () => ( 38 | 42 | ); 43 | -------------------------------------------------------------------------------- /0-base-app/src/components/Subheading.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Heading 3 | * Big Text 4 | */ 5 | 6 | import styled, { keyframes } from 'styled-components'; 7 | 8 | const spin = keyframes` 9 | to { 10 | transform: rotate3d(0, 1, 0, 1turn); 11 | } 12 | `; 13 | 14 | const Subheading = styled.div` 15 | animation-duration: 4s; 16 | animation-iteration-count: 300; 17 | animation-name: ${spin}; 18 | animation-timing-function: linear; 19 | font-size: 1.5em; 20 | font-style: italic; 21 | font-weight: 400; 22 | letter-spacing: 0.125em; 23 | line-height: 1.2; 24 | margin-bottom: 1em; 25 | margin-top: 0.5em; 26 | text-align: center; 27 | text-transform: uppercase; 28 | `; 29 | 30 | export default Subheading; 31 | -------------------------------------------------------------------------------- /0-base-app/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Index 3 | * Where it all begins 4 | */ 5 | 6 | import React from 'react'; 7 | import ReactDOM from 'react-dom'; 8 | import { 9 | BrowserRouter as Router, 10 | Route, 11 | Link, 12 | Redirect, 13 | withRouter 14 | } from 'react-router-dom'; 15 | import styled, { injectGlobal } from 'styled-components'; 16 | 17 | import Countdown from './views/countdown'; 18 | import Home from './views/home'; 19 | import Nav from './components/Nav'; 20 | 21 | import backgroundImage from './assets/background.svg'; 22 | 23 | injectGlobal` 24 | html, 25 | body { 26 | height: 100%; 27 | margin: 0; 28 | } 29 | 30 | html { 31 | background-image: url(${backgroundImage}); 32 | background-repeat: repeat; 33 | background-size: auto 256px; 34 | } 35 | 36 | * { 37 | box-sizing: border-box; 38 | } 39 | `; 40 | 41 | const AppStyles = styled.div` 42 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 43 | `; 44 | 45 | const App = () => ( 46 | 47 | 48 |