├── config ├── jest │ ├── CSSStub.js │ └── FileStub.js ├── polyfills.js ├── env.js ├── paths.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── .babelrc ├── .gitignore ├── public ├── favicon.ico ├── profile.jpg └── index.html ├── README.md ├── src ├── components │ ├── About.js │ ├── Skills.js │ ├── Work.js │ ├── Education.js │ ├── WorkItem.js │ ├── App.js │ └── Profile.js ├── index.js ├── styles │ └── main.scss └── resume.json ├── .eslintrc ├── .editorconfig ├── scripts ├── test.js ├── build.js └── start.js ├── .circleci └── config.yml ├── package.json ├── .bootstraprc ├── CODE_OF_CONDUCT.md └── LICENSE /config/jest/CSSStub.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /config/jest/FileStub.js: -------------------------------------------------------------------------------- 1 | module.exports = "test-file-stub"; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | yarn.lock 4 | /build 5 | .DS_Store -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freaksauce/React-Resume-ES6/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freaksauce/React-Resume-ES6/HEAD/public/profile.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repo is deprecated please refer to https://github.com/freaksauce/jonbloomer.com.au instead -------------------------------------------------------------------------------- /src/components/About.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const About = props => { 4 | return ( 5 |
6 |

About

7 |
{props.aboutData}
8 |
9 | ); 10 | }; 11 | 12 | export default About; 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './components/App'; 4 | require('bootstrap-loader'); 5 | require('font-awesome-webpack-sass'); 6 | const json = require('./resume.json'); // load resume file 7 | 8 | ReactDOM.render( 9 | , 10 | document.getElementById('root') 11 | ); 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react" 5 | ], 6 | "ecmaFeatures": { 7 | "modules": true, 8 | "jsx": true 9 | }, 10 | "env": { 11 | "browser": true, 12 | "es6": true, 13 | "node": true, 14 | "mocha": true 15 | }, 16 | "rules": { 17 | "quotes": [ 18 | 2, 19 | "single" 20 | ], 21 | "eqeqeq": [ 22 | 2, 23 | "smart" 24 | ], 25 | "keyword-spacing": 2, 26 | "no-console": 1 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /src/components/Skills.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Skills = props => { 4 | const getSkills = props.skillsData[0].keywords.map(function(item, index) { 5 | return (
  • {item}
  • ) 6 | }); 7 | 8 | return ( 9 |
    10 |

    Skills

    11 | 12 |
    13 | ) 14 | }; 15 | 16 | export default Skills; 17 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test'; 2 | process.env.PUBLIC_URL = ''; 3 | 4 | // Load environment variables from .env file. Suppress warnings using silent 5 | // if this file is missing. dotenv will never modify any environment variables 6 | // that have already been set. 7 | // https://github.com/motdotla/dotenv 8 | require('dotenv').config({silent: true}); 9 | 10 | const jest = require('jest'); 11 | const argv = process.argv.slice(2); 12 | 13 | // Watch unless on CI 14 | if (!process.env.CI) { 15 | argv.push('--watch'); 16 | } 17 | 18 | 19 | jest.run(argv); 20 | -------------------------------------------------------------------------------- /src/components/Work.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import WorkItem from './WorkItem'; 3 | 4 | const Work = props => { 5 | const getWorkExperience = () => { 6 | const workItems = []; 7 | props.workData.forEach((val, index) => { 8 | workItems.push(); 9 | }) 10 | return workItems; 11 | } 12 | 13 | return ( 14 |
    15 |

    Work experience

    16 | {getWorkExperience()} 17 |
    18 | ); 19 | }; 20 | 21 | export default Work; 22 | -------------------------------------------------------------------------------- /config/polyfills.js: -------------------------------------------------------------------------------- 1 | if (typeof Promise === 'undefined') { 2 | // Rejection tracking prevents a common issue where React gets into an 3 | // inconsistent state due to an error, but it gets swallowed by a Promise, 4 | // and the user has no idea what causes React's erratic future behavior. 5 | require('promise/lib/rejection-tracking').enable(); 6 | window.Promise = require('promise/lib/es6-extensions.js'); 7 | } 8 | 9 | // fetch() polyfill for making API calls. 10 | require('whatwg-fetch'); 11 | 12 | // Object.assign() is commonly used with React. 13 | // It will use the native implementation if it's present and isn't buggy. 14 | Object.assign = require('object-assign'); 15 | -------------------------------------------------------------------------------- /src/components/Education.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import moment from 'moment'; 3 | 4 | const Education = props => { 5 | const getEducation = props.educationData.map(function(item, index) { 6 | const startdate = moment(item.startDate).format('MMM, YYYY'); 7 | const enddate = moment(item.endDate).format('MMM, YYYY'); 8 | return ( 9 |
    10 |

    {item.studyType} {item.area}

    11 |

    {item.institution}

    12 |

    Studied: {startdate} - {enddate}

    13 |
    14 | ) 15 | }); 16 | 17 | return ( 18 |
    19 |

    Education

    20 | {getEducation} 21 |
    22 | ) 23 | }; 24 | 25 | export default Education; 26 | -------------------------------------------------------------------------------- /src/components/WorkItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import moment from 'moment'; 3 | 4 | const WorkItem = props => { 5 | const getWorkDates = () => { 6 | const startdate = moment(props.workItemData.startDate).format('MMM, YYYY'); 7 | let enddate = null; 8 | if (props.workItemData.endDate !== '') { 9 | enddate = moment(props.workItemData.endDate).format('MMM, YYYY'); 10 | } else { 11 | enddate = 'Present'; 12 | } 13 | 14 | return {startdate} - {enddate} 15 | } 16 | 17 | const getHighlights = props.workItemData.highlights.map(function(item, index) { 18 | return (
  • {item}
  • ) 19 | }); 20 | 21 | return ( 22 |
    23 |

    {props.workItemData.position}, {props.workItemData.company}

    24 |

    {getWorkDates()}

    25 |

    {props.workItemData.summary}

    26 |
      {getHighlights}
    27 |
    28 | ) 29 | }; 30 | 31 | export default WorkItem; 32 | -------------------------------------------------------------------------------- /config/env.js: -------------------------------------------------------------------------------- 1 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be 2 | // injected into the application via DefinePlugin in Webpack configuration. 3 | 4 | var REACT_APP = /^REACT_APP_/i; 5 | 6 | function getClientEnvironment(publicUrl) { 7 | var processEnv = Object 8 | .keys(process.env) 9 | .filter(key => REACT_APP.test(key)) 10 | .reduce((env, key) => { 11 | env[key] = JSON.stringify(process.env[key]); 12 | return env; 13 | }, { 14 | // Useful for determining whether we’re running in production mode. 15 | // Most importantly, it switches React into the correct mode. 16 | 'NODE_ENV': JSON.stringify( 17 | process.env.NODE_ENV || 'development' 18 | ), 19 | // Useful for resolving the correct path to static assets in `public`. 20 | // For example, . 21 | // This should only be used as an escape hatch. Normally you would put 22 | // images into the `src` and `import` them in code to get their paths. 23 | 'PUBLIC_URL': JSON.stringify(publicUrl) 24 | }); 25 | return {'process.env': processEnv}; 26 | } 27 | 28 | module.exports = getClientEnvironment; 29 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 16 | Jonathan Bloomer - Resume 17 | 18 | 19 |
    20 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/components/App.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import Profile from './Profile'; 3 | import About from './About'; 4 | import Work from './Work'; 5 | import Skills from './Skills'; 6 | import Education from './Education'; 7 | 8 | const App = props => { 9 | const profileData = props.jsonObj.basics; 10 | const aboutData = profileData.summary; 11 | const workData = props.jsonObj.work; 12 | const skillsData = props.jsonObj.skills; 13 | const educationData = props.jsonObj.education; 14 | // console.log(profileData) 15 | return ( 16 |
    17 |
    18 | 23 |
    24 |
    25 | 26 | 27 | 28 | 29 |
    30 |
    31 |
    32 |
    33 | ) 34 | }; 35 | 36 | App.propTypes = { 37 | jsonObj: PropTypes.object.isRequired 38 | } 39 | 40 | export default App; 41 | -------------------------------------------------------------------------------- /src/styles/main.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background: #f0f0f0; 3 | } 4 | aside, main { 5 | padding: 10px!important; 6 | } 7 | @media (min-width: 992px) { 8 | main { 9 | padding-left: 0!important; 10 | } 11 | } 12 | aside .inner, main .inner { 13 | background: #fff; 14 | padding: 20px; 15 | } 16 | h1 { 17 | font-size: 24px; 18 | margin-bottom: 0; 19 | font-weight: 700; 20 | } 21 | h2 { 22 | font-size: 20px; 23 | margin-top: 10px; 24 | color: #777; 25 | } 26 | h3 { 27 | font-size: 16px; 28 | font-weight: 700; 29 | margin-bottom: 0; 30 | } 31 | h4 { 32 | font-size: 15px; 33 | font-weight: 700; 34 | } 35 | section h2 { 36 | padding-bottom: 10px; 37 | border-bottom: 1px solid #f0f0f0; 38 | margin-bottom: 20px; 39 | } 40 | a { 41 | -webkit-transition: all 0.5s ease-out; 42 | -moz-transition: all 0.5s ease-out; 43 | -o-transition: all 0.5s ease-out; 44 | -ms-transition: all 0.5s ease-out; 45 | transition: all 0.5s ease-out; 46 | } 47 | 48 | .divider { 49 | padding: 10px 20px 0 20px; 50 | border-bottom: 1px solid #f0f0f0; 51 | margin-bottom: 20px; 52 | } 53 | .fa { 54 | color: #777; 55 | margin-right: 5px; 56 | top: 4px; 57 | } 58 | 59 | .contact-links li { 60 | margin-bottom: 15px; 61 | } 62 | .profileLinks li a { 63 | text-decoration: none; 64 | color: #000; 65 | } 66 | .profileLinks li a:hover { 67 | color: #23527c; 68 | } 69 | 70 | .about, .work, .education, .skills { 71 | margin-bottom: 30px; 72 | } 73 | .skills-list li { 74 | font-size: 18px; 75 | } 76 | .workDates { 77 | color: #777; 78 | } 79 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | 7 | defaults: &defaults 8 | working_directory: ~/repo 9 | docker: 10 | - image: circleci/node:8 11 | 12 | jobs: 13 | build: 14 | <<: *defaults 15 | 16 | steps: 17 | - checkout 18 | # Download and cache dependencies 19 | - restore_cache: 20 | keys: 21 | - v1-dependencies-{{ checksum "package.json" }} 22 | # fallback to using the latest cache if no exact match is found 23 | - v1-dependencies- 24 | 25 | - run: yarn install 26 | 27 | - save_cache: 28 | paths: 29 | - node_modules 30 | key: v1-dependencies-{{ checksum "package.json" }} 31 | 32 | - run: yarn build 33 | 34 | - persist_to_workspace: 35 | root: ~/repo 36 | paths: . 37 | 38 | deploy: 39 | <<: *defaults 40 | 41 | steps: 42 | - attach_workspace: 43 | at: ~/repo 44 | - run: 45 | name: Install AWS CLI 46 | command: sudo apt-get -y -qq install awscli 47 | # - run: 48 | # name: Gzip css files 49 | # command: gzip -k -r build/static 50 | - run: 51 | name: Deploy to S3 52 | command: aws s3 sync build s3://$AWS_BUCKET/ --acl public-read 53 | 54 | workflows: 55 | version: 2 56 | build-deploy: 57 | jobs: 58 | - build 59 | - deploy: 60 | requires: 61 | - build 62 | filters: 63 | branches: 64 | only: master 65 | -------------------------------------------------------------------------------- /src/components/Profile.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Profile = props => { 4 | const profileObj = props.profileData; 5 | return
    6 |
    7 |

    {profileObj.name}

    8 |

    {profileObj.label}

    9 |
    10 |
      11 |
    • {profileObj.location.city}, {profileObj.location.region}, {profileObj.location.countryCode}
    • 12 |
    • {profileObj.email}
    • 13 |
    14 |
    15 |
      16 |
    • 17 |
    • 18 |
    19 |
    20 |

    I built this site with React components and a JSON Resume Schema. The full source code can be found in my Github repo.

    21 |
    22 | }; 23 | 24 | export default Profile; 25 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | 4 | // Make sure any symlinks in the project folder are resolved: 5 | // https://github.com/facebookincubator/create-react-app/issues/637 6 | var appDirectory = fs.realpathSync(process.cwd()); 7 | function resolveApp(relativePath) { 8 | return path.resolve(appDirectory, relativePath); 9 | } 10 | 11 | // We support resolving modules according to `NODE_PATH`. 12 | // This lets you use absolute paths in imports inside large monorepos: 13 | // https://github.com/facebookincubator/create-react-app/issues/253. 14 | 15 | // It works similar to `NODE_PATH` in Node itself: 16 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders 17 | 18 | // We will export `nodePaths` as an array of absolute paths. 19 | // It will then be used by Webpack configs. 20 | // Jest doesn’t need this because it already handles `NODE_PATH` out of the box. 21 | 22 | var nodePaths = (process.env.NODE_PATH || '') 23 | .split(process.platform === 'win32' ? ';' : ':') 24 | .filter(Boolean) 25 | .map(resolveApp); 26 | 27 | // config after eject: we're in ./config/ 28 | module.exports = { 29 | appBuild: resolveApp('build'), 30 | appPublic: resolveApp('public'), 31 | appHtml: resolveApp('public/index.html'), 32 | appIndexJs: resolveApp('src/index.js'), 33 | appPackageJson: resolveApp('package.json'), 34 | appSrc: resolveApp('src'), 35 | testsSetup: resolveApp('src/setupTests.js'), 36 | appNodeModules: resolveApp('node_modules'), 37 | ownNodeModules: resolveApp('node_modules'), 38 | nodePaths: nodePaths 39 | }; 40 | 41 | 42 | 43 | // config before publish: we're in ./packages/react-scripts/config/ 44 | if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) { 45 | module.exports = { 46 | appBuild: resolveOwn('../../../build'), 47 | appPublic: resolveOwn('../template/public'), 48 | appHtml: resolveOwn('../template/public/index.html'), 49 | appIndexJs: resolveOwn('../template/src/index.js'), 50 | appPackageJson: resolveOwn('../package.json'), 51 | appSrc: resolveOwn('../template/src'), 52 | testsSetup: resolveOwn('../template/src/setupTests.js'), 53 | appNodeModules: resolveOwn('../node_modules'), 54 | ownNodeModules: resolveOwn('../node_modules'), 55 | nodePaths: nodePaths 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "React-Resume-ES6-Webpack", 3 | "version": "0.1.0", 4 | "private": true, 5 | "devDependencies": { 6 | "autoprefixer": "6.5.1", 7 | "babel-core": "6.17.0", 8 | "babel-eslint": "7.0.0", 9 | "babel-jest": "16.0.0", 10 | "babel-loader": "6.2.5", 11 | "babel-preset-react-app": "^1.0.0", 12 | "bootstrap-loader": "^1.3.1", 13 | "bootstrap-sass": "^3.3.7", 14 | "case-sensitive-paths-webpack-plugin": "1.1.4", 15 | "chalk": "1.1.3", 16 | "connect-history-api-fallback": "1.3.0", 17 | "cross-spawn": "4.0.2", 18 | "css-loader": "^0.25.0", 19 | "detect-port": "1.0.1", 20 | "dotenv": "2.0.0", 21 | "eslint": "3.8.1", 22 | "eslint-config-react-app": "^0.3.0", 23 | "eslint-loader": "1.6.0", 24 | "eslint-plugin-flowtype": "2.21.0", 25 | "eslint-plugin-import": "2.0.1", 26 | "eslint-plugin-jsx-a11y": "2.2.3", 27 | "eslint-plugin-react": "6.4.1", 28 | "extract-text-webpack-plugin": "1.0.1", 29 | "file-loader": "0.9.0", 30 | "filesize": "3.3.0", 31 | "find-cache-dir": "0.1.1", 32 | "font-awesome": "^4.7.0", 33 | "font-awesome-webpack-sass": "0.0.3", 34 | "fs-extra": "0.30.0", 35 | "gzip-size": "3.0.0", 36 | "html-webpack-plugin": "2.24.0", 37 | "http-proxy-middleware": "0.17.2", 38 | "jest": "16.0.2", 39 | "json-loader": "0.5.4", 40 | "node-sass": "^3.13.0", 41 | "object-assign": "4.1.0", 42 | "path-exists": "2.1.0", 43 | "postcss-loader": "1.0.0", 44 | "promise": "7.1.1", 45 | "react-dev-utils": "^0.3.0", 46 | "recursive-readdir": "2.1.0", 47 | "resolve-url-loader": "^1.6.0", 48 | "rimraf": "2.5.4", 49 | "sass-loader": "^4.0.2", 50 | "strip-ansi": "3.0.1", 51 | "style-loader": "^0.13.1", 52 | "url-loader": "^0.5.7", 53 | "webpack": "1.13.2", 54 | "webpack-dev-server": "1.16.2", 55 | "webpack-manifest-plugin": "1.1.0", 56 | "whatwg-fetch": "1.0.0" 57 | }, 58 | "dependencies": { 59 | "moment": "^2.18.1", 60 | "react": "^15.4.1", 61 | "react-dom": "^15.4.1" 62 | }, 63 | "scripts": { 64 | "start": "node scripts/start.js", 65 | "build": "node scripts/build.js", 66 | "test": "node scripts/test.js --env=jsdom" 67 | }, 68 | "jest": { 69 | "moduleFileExtensions": [ 70 | "jsx", 71 | "js", 72 | "json" 73 | ], 74 | "moduleNameMapper": { 75 | "^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/config/jest/FileStub.js", 76 | "^.+\\.css$": "/config/jest/CSSStub.js" 77 | }, 78 | "setupFiles": [ 79 | "/config/polyfills.js" 80 | ], 81 | "testPathIgnorePatterns": [ 82 | "/(build|docs|node_modules)/" 83 | ], 84 | "testEnvironment": "node" 85 | }, 86 | "babel": { 87 | "presets": [ 88 | "react-app" 89 | ] 90 | }, 91 | "eslintConfig": { 92 | "extends": "react-app" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /.bootstraprc: -------------------------------------------------------------------------------- 1 | --- 2 | # Output debugging info 3 | # loglevel: debug 4 | 5 | # Major version of Bootstrap: 3 or 4 6 | bootstrapVersion: 3 7 | 8 | # If Bootstrap version 3 is used - turn on/off custom icon font path 9 | useCustomIconFontPath: false 10 | 11 | # Webpack loaders, order matters 12 | styleLoaders: 13 | - style 14 | - css 15 | - sass 16 | 17 | # Extract styles to stand-alone css file 18 | # Different settings for different environments can be used, 19 | # It depends on value of NODE_ENV environment variable 20 | # This param can also be set in webpack config: 21 | # entry: 'bootstrap-loader/extractStyles' 22 | #extractStyles: false 23 | env: 24 | development: 25 | extractStyles: false 26 | production: 27 | extractStyles: true 28 | 29 | 30 | # Customize Bootstrap variables that get imported before the original Bootstrap variables. 31 | # Thus, derived Bootstrap variables can depend on values from here. 32 | # See the Bootstrap _variables.scss file for examples of derived Bootstrap variables. 33 | # 34 | # preBootstrapCustomizations: ./path/to/bootstrap/pre-customizations.scss 35 | 36 | 37 | # This gets loaded after bootstrap/variables is loaded 38 | # Thus, you may customize Bootstrap variables 39 | # based on the values established in the Bootstrap _variables.scss file 40 | # 41 | # bootstrapCustomizations: ./path/to/bootstrap/customizations.scss 42 | 43 | 44 | # Import your custom styles here 45 | # Usually this endpoint-file contains list of @imports of your application styles 46 | # 47 | appStyles: ./src/styles/main.scss 48 | 49 | 50 | ### Bootstrap styles 51 | styles: 52 | 53 | # Mixins 54 | mixins: true 55 | 56 | # Reset and dependencies 57 | normalize: true 58 | print: true 59 | glyphicons: true 60 | 61 | # Core CSS 62 | scaffolding: true 63 | type: true 64 | code: true 65 | grid: true 66 | tables: false 67 | forms: false 68 | buttons: false 69 | 70 | # Components 71 | component-animations: false 72 | dropdowns: false 73 | button-groups: false 74 | input-groups: false 75 | navs: false 76 | navbar: false 77 | breadcrumbs: false 78 | pagination: false 79 | pager: false 80 | labels: true 81 | badges: true 82 | jumbotron: false 83 | thumbnails: true 84 | alerts: false 85 | progress-bars: false 86 | media: true 87 | list-group: true 88 | panels: true 89 | wells: false 90 | responsive-embed: false 91 | close: false 92 | 93 | # Components w/ JavaScript 94 | modals: false 95 | tooltip: false 96 | popovers: false 97 | carousel: false 98 | 99 | # Utility classes 100 | utilities: true 101 | responsive-utilities: true 102 | 103 | ### Bootstrap scripts 104 | scripts: false 105 | # scripts: 106 | # transition: false 107 | # alert: false 108 | # button: false 109 | # carousel: false 110 | # collapse: false 111 | # dropdown: false 112 | # modal: false 113 | # tooltip: false 114 | # popover: false 115 | # scrollspy: false 116 | # tab: false 117 | # affix: false 118 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jonbloomer@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /src/resume.json: -------------------------------------------------------------------------------- 1 | { 2 | "basics": { 3 | "name": "Jonathan Bloomer", 4 | "label": "Senior Front End Developer", 5 | "picture": "./profile.jpg", 6 | "email": "jonbloomer@gmail.com", 7 | "phone": "0403933281", 8 | "website": "http://freaksauce.com", 9 | "summary": "Over the past 18 years I have continuously challenged myself with new languages, frameworks and methodologies. My core languages have always been html, css & javascript but I have also worked as a full stack php developer building both bespoke CMS solutions and small business applications. My current role at IAG is Front End Developer (or Software Engineer as IAG prefer to label us) for a small React team and have been developing with React and Redux for the past 3 years.", 10 | "location": { 11 | "address": "Sutherland", 12 | "postalCode": "2232", 13 | "city": "Sydney", 14 | "countryCode": "Aus", 15 | "region": "NSW" 16 | }, 17 | "profiles": [ 18 | { 19 | "network": "Twitter", 20 | "username": "jonbloomer", 21 | "url": "" 22 | }, 23 | { 24 | "network": "Github", 25 | "username": "freaksauce", 26 | "url": "" 27 | } 28 | ] 29 | }, 30 | "work": [ 31 | { 32 | "company": "IAG", 33 | "position": "Lead Front End Developer", 34 | "website": "http://nrma.com.au", 35 | "startDate": "2016-08-01", 36 | "endDate": "", 37 | "summary": "I am currently working as a Front End Developer on a small React team building Insurance applications and I am across multiple applications that have been developed using our new technology stack. IAG are keen to utilise the latest technologies and we have had great success using React/Redux running on a Node Express server and using an API backend architecture (via APIGEE) to access the various IAG systems. I have also been a key part of a team developing an in-house Design System called Chroma, this is a platform and framework agnostic component library. We have then built a React component library on top of this system which is used for all IAG Customer Labs applications. As part of this team I have also been responsible for setting up a CI/CD pipeline using Github/CircleCI/Heroku/NPM & AWS.", 38 | "highlights": [] 39 | }, 40 | { 41 | "company": "Pacific Magazines", 42 | "position": "Senior Front End Developer", 43 | "website": "", 44 | "startDate": "2016-03-01", 45 | "endDate": "2016-08-01", 46 | "summary": "During my time at Pacific Magazines I worked on a couple of large React applications using React/Redux to integrate with a .NET MVC Application.", 47 | "highlights": [] 48 | }, 49 | { 50 | "company": "IAG", 51 | "position": "UI Developer", 52 | "website": "http://nrma.com.au", 53 | "startDate": "2014-11-01", 54 | "endDate": "2016-03-01", 55 | "summary": "Working as a UI developer as part of IAG Labs developing html/css/javascript solutions to integrate with the backend systems for the online quoting applications.", 56 | "highlights": [] 57 | }, 58 | { 59 | "company": "Reactive", 60 | "position": "Front End Developer", 61 | "website": "", 62 | "startDate": "2014-09-01", 63 | "endDate": "2014-11-30", 64 | "summary": "At Reactive I was responsible for working with a .NET team to deliver templates using javascript/sass/grunt and handlebars. I also had exposure to TFS for source control.", 65 | "highlights": [] 66 | }, 67 | { 68 | "company": "City of Sydney Council", 69 | "position": "Front End Developer", 70 | "website": "", 71 | "startDate": "2014-05-01", 72 | "endDate": "2014-08-31", 73 | "summary": "For City of Sydney I was a Front End Developer working with Wordpress on multiple key websites such as Sydneynewyearseve.com.au. All code was developed using LESS and Bootstrap for a consistent responsive interface.", 74 | "highlights": [] 75 | }, 76 | { 77 | "company": "Self Employed", 78 | "position": "Freelance Web Developer", 79 | "website": "", 80 | "startDate": "2010-03-01", 81 | "endDate": "2014-05-01", 82 | "summary": "As a freelance web developer I mainly concentrated on building bespoke CMS solutions for agencies using Wordpress. As a full stack developer my responsibilities included setting up hosting, domains, databases and delivering an easy to use custom Wordpress theme with Advanced Custom Fields and toward the latter end of my freelance venture, responsive layouts.", 83 | "highlights": [] 84 | }, 85 | { 86 | "company": "Soap Creative", 87 | "position": "Senior Web Developer", 88 | "website": "http://soapcreative.com", 89 | "startDate": "2006-07-01", 90 | "endDate": "2010-03-01", 91 | "summary": "At SOAP I was required to carry out full stack duties across a broad range of projects including php/MySQL with front end technologies ranging from html/css to Flash.", 92 | "highlights": [] 93 | }, 94 | { 95 | "company": "M&C Saatchi", 96 | "position": "Web Developer", 97 | "website": "http://mcsaatchi.com.au/", 98 | "startDate": "2006-05-01", 99 | "endDate": "2006-08-31", 100 | "summary": "Flash development with xml & amfphp for php/mysql integration.", 101 | "highlights": [] 102 | }, 103 | { 104 | "company": "Wunderman/GPY&R", 105 | "position": "Web Developer", 106 | "website": "http://www.gpyr.com.au/", 107 | "startDate": "2005-07-01", 108 | "endDate": "2006-05-01", 109 | "summary": "Flash developer using xml & amfphp, html/css with php/mysql backend integration and CMS development.", 110 | "highlights": [] 111 | }, 112 | { 113 | "company": "Federal Publishing Company", 114 | "position": "Web Developer", 115 | "website": "", 116 | "startDate": "2004-07-01", 117 | "endDate": "2005-03-31", 118 | "summary": "Lead web developer on homehound.com.au, html/css/javascript development with php & SQL server integration.", 119 | "highlights": [] 120 | } 121 | ], 122 | "volunteer": [], 123 | "education": [ 124 | { 125 | "institution": "Birmingham Conservatoire", 126 | "area": "Music", 127 | "studyType": "Bachelor (hons)", 128 | "startDate": "1994-08-01", 129 | "endDate": "1998-07-01", 130 | "gpa": "", 131 | "courses": [] 132 | } 133 | ], 134 | "awards": [], 135 | "publications": [], 136 | "skills": [ 137 | { 138 | "name": "Front End Development", 139 | "level": "Master", 140 | "keywords": [ 141 | "HTML", 142 | "CSS", 143 | "Javascript", 144 | "ES2015", 145 | "ES2016", 146 | "ES2017", 147 | "ES6", 148 | "jQuery", 149 | "React", 150 | "Handlebars", 151 | "SASS", 152 | "LESS", 153 | "Gulp", 154 | "Grunt", 155 | "Babel", 156 | "AWS", 157 | "CircleCI", 158 | "TravisCI", 159 | "Heroku", 160 | "CI", 161 | "CD", 162 | "Bootstrap", 163 | "Semantic UI", 164 | "Material css", 165 | "Node", 166 | "php", 167 | "MySQL", 168 | "Git", 169 | "Jira", 170 | "Responsive" 171 | ] 172 | } 173 | ], 174 | "languages": [ 175 | { 176 | "language": "English", 177 | "fluency": "Native speaker" 178 | } 179 | ], 180 | "interests": [ 181 | { 182 | "name": "Guitar", 183 | "keywords": [] 184 | } 185 | ], 186 | "references": [] 187 | } 188 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | // Do this as the first thing so that any code reading it knows the right env. 2 | process.env.NODE_ENV = 'production'; 3 | 4 | // Load environment variables from .env file. Suppress warnings using silent 5 | // if this file is missing. dotenv will never modify any environment variables 6 | // that have already been set. 7 | // https://github.com/motdotla/dotenv 8 | require('dotenv').config({silent: true}); 9 | 10 | var chalk = require('chalk'); 11 | var fs = require('fs-extra'); 12 | var path = require('path'); 13 | var filesize = require('filesize'); 14 | var gzipSize = require('gzip-size').sync; 15 | var rimrafSync = require('rimraf').sync; 16 | var webpack = require('webpack'); 17 | var config = require('../config/webpack.config.prod'); 18 | var paths = require('../config/paths'); 19 | var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); 20 | var recursive = require('recursive-readdir'); 21 | var stripAnsi = require('strip-ansi'); 22 | 23 | // Warn and crash if required files are missing 24 | if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { 25 | process.exit(1); 26 | } 27 | 28 | // Input: /User/dan/app/build/static/js/main.82be8.js 29 | // Output: /static/js/main.js 30 | function removeFileNameHash(fileName) { 31 | return fileName 32 | .replace(paths.appBuild, '') 33 | .replace(/\/?(.*)(\.\w+)(\.js|\.css)/, (match, p1, p2, p3) => p1 + p3); 34 | } 35 | 36 | // Input: 1024, 2048 37 | // Output: "(+1 KB)" 38 | function getDifferenceLabel(currentSize, previousSize) { 39 | var FIFTY_KILOBYTES = 1024 * 50; 40 | var difference = currentSize - previousSize; 41 | var fileSize = !Number.isNaN(difference) ? filesize(difference) : 0; 42 | if (difference >= FIFTY_KILOBYTES) { 43 | return chalk.red('+' + fileSize); 44 | } else if (difference < FIFTY_KILOBYTES && difference > 0) { 45 | return chalk.yellow('+' + fileSize); 46 | } else if (difference < 0) { 47 | return chalk.green(fileSize); 48 | } else { 49 | return ''; 50 | } 51 | } 52 | 53 | // First, read the current file sizes in build directory. 54 | // This lets us display how much they changed later. 55 | recursive(paths.appBuild, (err, fileNames) => { 56 | var previousSizeMap = (fileNames || []) 57 | .filter(fileName => /\.(js|css)$/.test(fileName)) 58 | .reduce((memo, fileName) => { 59 | var contents = fs.readFileSync(fileName); 60 | var key = removeFileNameHash(fileName); 61 | memo[key] = gzipSize(contents); 62 | return memo; 63 | }, {}); 64 | 65 | // Remove all content but keep the directory so that 66 | // if you're in it, you don't end up in Trash 67 | rimrafSync(paths.appBuild + '/*'); 68 | 69 | // Start the webpack build 70 | build(previousSizeMap); 71 | 72 | // Merge with the public folder 73 | copyPublicFolder(); 74 | }); 75 | 76 | // Print a detailed summary of build files. 77 | function printFileSizes(stats, previousSizeMap) { 78 | var assets = stats.toJson().assets 79 | .filter(asset => /\.(js|css)$/.test(asset.name)) 80 | .map(asset => { 81 | var fileContents = fs.readFileSync(paths.appBuild + '/' + asset.name); 82 | var size = gzipSize(fileContents); 83 | var previousSize = previousSizeMap[removeFileNameHash(asset.name)]; 84 | var difference = getDifferenceLabel(size, previousSize); 85 | return { 86 | folder: path.join('build', path.dirname(asset.name)), 87 | name: path.basename(asset.name), 88 | size: size, 89 | sizeLabel: filesize(size) + (difference ? ' (' + difference + ')' : '') 90 | }; 91 | }); 92 | assets.sort((a, b) => b.size - a.size); 93 | var longestSizeLabelLength = Math.max.apply(null, 94 | assets.map(a => stripAnsi(a.sizeLabel).length) 95 | ); 96 | assets.forEach(asset => { 97 | var sizeLabel = asset.sizeLabel; 98 | var sizeLength = stripAnsi(sizeLabel).length; 99 | if (sizeLength < longestSizeLabelLength) { 100 | var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength); 101 | sizeLabel += rightPadding; 102 | } 103 | console.log( 104 | ' ' + sizeLabel + 105 | ' ' + chalk.dim(asset.folder + path.sep) + chalk.cyan(asset.name) 106 | ); 107 | }); 108 | } 109 | 110 | // Print out errors 111 | function printErrors(summary, errors) { 112 | console.log(chalk.red(summary)); 113 | console.log(); 114 | errors.forEach(err => { 115 | console.log(err.message || err); 116 | console.log(); 117 | }); 118 | } 119 | 120 | // Create the production build and print the deployment instructions. 121 | function build(previousSizeMap) { 122 | console.log('Creating an optimized production build...'); 123 | webpack(config).run((err, stats) => { 124 | if (err) { 125 | printErrors('Failed to compile.', [err]); 126 | process.exit(1); 127 | } 128 | 129 | if (stats.compilation.errors.length) { 130 | printErrors('Failed to compile.', stats.compilation.errors); 131 | process.exit(1); 132 | } 133 | 134 | console.log(chalk.green('Compiled successfully.')); 135 | console.log(); 136 | 137 | console.log('File sizes after gzip:'); 138 | console.log(); 139 | printFileSizes(stats, previousSizeMap); 140 | console.log(); 141 | 142 | var openCommand = process.platform === 'win32' ? 'start' : 'open'; 143 | var homepagePath = require(paths.appPackageJson).homepage; 144 | var publicPath = config.output.publicPath; 145 | if (homepagePath && homepagePath.indexOf('.github.io/') !== -1) { 146 | // "homepage": "http://user.github.io/project" 147 | console.log('The project was built assuming it is hosted at ' + chalk.green(publicPath) + '.'); 148 | console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.'); 149 | console.log(); 150 | console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); 151 | console.log('To publish it at ' + chalk.green(homepagePath) + ', run:'); 152 | console.log(); 153 | console.log(' ' + chalk.cyan('npm') + ' install --save-dev gh-pages'); 154 | console.log(); 155 | console.log('Add the following script in your ' + chalk.cyan('package.json') + '.'); 156 | console.log(); 157 | console.log(' ' + chalk.dim('// ...')); 158 | console.log(' ' + chalk.yellow('"scripts"') + ': {'); 159 | console.log(' ' + chalk.dim('// ...')); 160 | console.log(' ' + chalk.yellow('"deploy"') + ': ' + chalk.yellow('"gh-pages -d build"')); 161 | console.log(' }'); 162 | console.log(); 163 | console.log('Then run:'); 164 | console.log(); 165 | console.log(' ' + chalk.cyan('npm') + ' run deploy'); 166 | console.log(); 167 | } else if (publicPath !== '/') { 168 | // "homepage": "http://mywebsite.com/project" 169 | console.log('The project was built assuming it is hosted at ' + chalk.green(publicPath) + '.'); 170 | console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.'); 171 | console.log(); 172 | console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); 173 | console.log(); 174 | } else { 175 | // no homepage or "homepage": "http://mywebsite.com" 176 | console.log('The project was built assuming it is hosted at the server root.'); 177 | if (homepagePath) { 178 | // "homepage": "http://mywebsite.com" 179 | console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.'); 180 | console.log(); 181 | } else { 182 | // no homepage 183 | console.log('To override this, specify the ' + chalk.green('homepage') + ' in your ' + chalk.cyan('package.json') + '.'); 184 | console.log('For example, add this to build it for GitHub Pages:') 185 | console.log(); 186 | console.log(' ' + chalk.green('"homepage"') + chalk.cyan(': ') + chalk.green('"http://myname.github.io/myapp"') + chalk.cyan(',')); 187 | console.log(); 188 | } 189 | console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); 190 | console.log('You may also serve it locally with a static server:') 191 | console.log(); 192 | console.log(' ' + chalk.cyan('npm') + ' install -g pushstate-server'); 193 | console.log(' ' + chalk.cyan('pushstate-server') + ' build'); 194 | console.log(' ' + chalk.cyan(openCommand) + ' http://localhost:9000'); 195 | console.log(); 196 | } 197 | }); 198 | } 199 | 200 | function copyPublicFolder() { 201 | fs.copySync(paths.appPublic, paths.appBuild, { 202 | dereference: true, 203 | filter: file => file !== paths.appHtml 204 | }); 205 | } 206 | -------------------------------------------------------------------------------- /config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var autoprefixer = require('autoprefixer'); 3 | var webpack = require('webpack'); 4 | var findCacheDir = require('find-cache-dir'); 5 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 6 | var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); 7 | var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); 8 | var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); 9 | var getClientEnvironment = require('./env'); 10 | var paths = require('./paths'); 11 | 12 | // Webpack uses `publicPath` to determine where the app is being served from. 13 | // In development, we always serve from the root. This makes config easier. 14 | var publicPath = '/'; 15 | // `publicUrl` is just like `publicPath`, but we will provide it to our app 16 | // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. 17 | // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. 18 | var publicUrl = ''; 19 | // Get environment variables to inject into our app. 20 | var env = getClientEnvironment(publicUrl); 21 | 22 | // This is the development configuration. 23 | // It is focused on developer experience and fast rebuilds. 24 | // The production configuration is different and lives in a separate file. 25 | module.exports = { 26 | // This makes the bundle appear split into separate modules in the devtools. 27 | // We don't use source maps here because they can be confusing: 28 | // https://github.com/facebookincubator/create-react-app/issues/343#issuecomment-237241875 29 | // You may want 'cheap-module-source-map' instead if you prefer source maps. 30 | devtool: 'eval', 31 | // These are the "entry points" to our application. 32 | // This means they will be the "root" imports that are included in JS bundle. 33 | // The first two entry points enable "hot" CSS and auto-refreshes for JS. 34 | entry: [ 35 | // Include an alternative client for WebpackDevServer. A client's job is to 36 | // connect to WebpackDevServer by a socket and get notified about changes. 37 | // When you save a file, the client will either apply hot updates (in case 38 | // of CSS changes), or refresh the page (in case of JS changes). When you 39 | // make a syntax error, this client will display a syntax error overlay. 40 | // Note: instead of the default WebpackDevServer client, we use a custom one 41 | // to bring better experience for Create React App users. You can replace 42 | // the line below with these two lines if you prefer the stock client: 43 | // require.resolve('webpack-dev-server/client') + '?/', 44 | // require.resolve('webpack/hot/dev-server'), 45 | require.resolve('react-dev-utils/webpackHotDevClient'), 46 | // We ship a few polyfills by default: 47 | require.resolve('./polyfills'), 48 | // Finally, this is your app's code: 49 | paths.appIndexJs 50 | // We include the app code last so that if there is a runtime error during 51 | // initialization, it doesn't blow up the WebpackDevServer client, and 52 | // changing JS code would still trigger a refresh. 53 | ], 54 | output: { 55 | // Next line is not used in dev but WebpackDevServer crashes without it: 56 | path: paths.appBuild, 57 | // Add /* filename */ comments to generated require()s in the output. 58 | pathinfo: true, 59 | // This does not produce a real file. It's just the virtual path that is 60 | // served by WebpackDevServer in development. This is the JS bundle 61 | // containing code from all our entry points, and the Webpack runtime. 62 | filename: 'static/js/bundle.js', 63 | // This is the URL that app is served from. We use "/" in development. 64 | publicPath: publicPath 65 | }, 66 | resolve: { 67 | // This allows you to set a fallback for where Webpack should look for modules. 68 | // We read `NODE_PATH` environment variable in `paths.js` and pass paths here. 69 | // We use `fallback` instead of `root` because we want `node_modules` to "win" 70 | // if there any conflicts. This matches Node resolution mechanism. 71 | // https://github.com/facebookincubator/create-react-app/issues/253 72 | fallback: paths.nodePaths, 73 | // These are the reasonable defaults supported by the Node ecosystem. 74 | // We also include JSX as a common component filename extension to support 75 | // some tools, although we do not recommend using it, see: 76 | // https://github.com/facebookincubator/create-react-app/issues/290 77 | extensions: ['.js', '.json', '.jsx', ''], 78 | alias: { 79 | // Support React Native Web 80 | // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ 81 | 'react-native': 'react-native-web' 82 | } 83 | }, 84 | 85 | module: { 86 | // First, run the linter. 87 | // It's important to do this before Babel processes the JS. 88 | preLoaders: [ 89 | { 90 | test: /\.(js|jsx)$/, 91 | loader: 'eslint', 92 | include: paths.appSrc, 93 | } 94 | ], 95 | loaders: [ 96 | // Process JS with Babel. 97 | { 98 | test: /\.(js|jsx)$/, 99 | include: paths.appSrc, 100 | loader: 'babel', 101 | query: { 102 | 103 | // This is a feature of `babel-loader` for webpack (not Babel itself). 104 | // It enables caching results in ./node_modules/.cache/react-scripts/ 105 | // directory for faster rebuilds. We use findCacheDir() because of: 106 | // https://github.com/facebookincubator/create-react-app/issues/483 107 | cacheDirectory: findCacheDir({ 108 | name: 'react-scripts' 109 | }) 110 | } 111 | }, 112 | // "postcss" loader applies autoprefixer to our CSS. 113 | // "css" loader resolves paths in CSS and adds assets as dependencies. 114 | // "style" loader turns CSS into JS modules that inject