├── config ├── flow │ ├── css.js.flow │ └── file.js.flow ├── jest │ ├── environment.js │ ├── CSSStub.js │ ├── FileStub.js │ └── transform.js ├── polyfills.js ├── env.js ├── babel.prod.js ├── babel.dev.js ├── paths.js ├── eslint.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── template ├── src │ ├── index.css │ ├── favicon.ico │ ├── index.js │ ├── __tests__ │ │ └── App-test.js │ ├── App.css │ ├── App.js │ └── logo.svg ├── gitignore ├── index.html └── README.md ├── .gitignore ├── .travis.yml ├── .eslintrc.js ├── bin └── preact-scripts.js ├── README.md ├── global-cli ├── package.json └── index.js ├── scripts ├── test.js ├── utils │ ├── createJestConfig.js │ ├── WatchMissingNodeModulesPlugin.js │ ├── chrome.applescript │ └── prompt.js ├── init.js ├── eject.js ├── build.js └── start.js ├── LICENSE ├── tasks ├── release.sh └── e2e.sh ├── PATENTS ├── CONTRIBUTING.md ├── package.json └── CHANGELOG.md /config/flow/css.js.flow: -------------------------------------------------------------------------------- 1 | // @flow 2 | -------------------------------------------------------------------------------- /config/flow/file.js.flow: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare export default string; 3 | -------------------------------------------------------------------------------- /template/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /template/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexkuz/create-preact-app/HEAD/template/src/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build 3 | .DS_Store 4 | *.tgz 5 | my-app* 6 | template/src/__tests__/__snapshots__/ 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | - 4 5 | - 6 6 | cache: 7 | directories: 8 | - global-cli/node_modules 9 | - node_modules 10 | script: tasks/e2e.sh 11 | -------------------------------------------------------------------------------- /template/src/index.js: -------------------------------------------------------------------------------- 1 | import { h, render } from 'preact'; 2 | import App from './App'; 3 | import './index.css'; 4 | 5 | render( 6 | , 7 | document.getElementById('root') 8 | ); 9 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const clientESLintConfig = require('./config/eslint'); 2 | 3 | module.exports = Object.assign({}, clientESLintConfig, { 4 | env: Object.assign({}, clientESLintConfig.env, { 5 | node: true, 6 | }) 7 | }); 8 | -------------------------------------------------------------------------------- /template/gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # production 7 | build 8 | 9 | # misc 10 | .DS_Store 11 | npm-debug.log 12 | -------------------------------------------------------------------------------- /config/jest/environment.js: -------------------------------------------------------------------------------- 1 | // Currently, Jest mocks setTimeout() and similar functions by default: 2 | // https://facebook.github.io/jest/docs/timer-mocks.html 3 | // We think this is confusing, so we disable this feature. 4 | // If you see value in it, run `jest.useFakeTimers()` in individual tests. 5 | beforeEach(() => { 6 | jest.useRealTimers(); 7 | }); 8 | -------------------------------------------------------------------------------- /template/src/__tests__/App-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import App from '../App'; 3 | import renderer from 'react-test-renderer'; 4 | 5 | describe('App', () => { 6 | it('renders a welcome view', () => { 7 | const instance = renderer.create(); 8 | const tree = instance.toJSON(); 9 | expect(tree).toMatchSnapshot(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /config/jest/CSSStub.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 3 | * 4 | * This source code is licensed under the BSD-style license found in the 5 | * LICENSE file in the root directory of this source tree. An additional grant 6 | * of patent rights can be found in the PATENTS file in the same directory. 7 | * 8 | * @flow 9 | */ 10 | 11 | module.exports = {}; 12 | -------------------------------------------------------------------------------- /config/jest/FileStub.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 3 | * 4 | * This source code is licensed under the BSD-style license found in the 5 | * LICENSE file in the root directory of this source tree. An additional grant 6 | * of patent rights can be found in the PATENTS file in the same directory. 7 | * 8 | * @flow 9 | */ 10 | 11 | module.exports = "test-file-stub"; 12 | -------------------------------------------------------------------------------- /template/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /config/jest/transform.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 3 | * 4 | * This source code is licensed under the BSD-style license found in the 5 | * LICENSE file in the root directory of this source tree. An additional grant 6 | * of patent rights can be found in the PATENTS file in the same directory. 7 | */ 8 | 9 | const babelDev = require('../babel.dev'); 10 | const babelJest = require('babel-jest'); 11 | 12 | module.exports = babelJest.createTransformer(babelDev); 13 | -------------------------------------------------------------------------------- /template/src/App.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | class App extends Component { 6 | render() { 7 | return ( 8 |
9 |
10 | logo 11 |

Welcome to Preact

12 |
13 |

14 | To get started, edit src/App.js and save to reload. 15 |

16 |
17 | ); 18 | } 19 | } 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /bin/preact-scripts.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var spawn = require('cross-spawn'); 3 | var script = process.argv[2]; 4 | var args = process.argv.slice(3); 5 | 6 | switch (script) { 7 | case 'build': 8 | case 'eject': 9 | case 'start': 10 | case 'test': 11 | var result = spawn.sync( 12 | 'node', 13 | [require.resolve('../scripts/' + script)].concat(args), 14 | {stdio: 'inherit'} 15 | ); 16 | process.exit(result.status); 17 | break; 18 | default: 19 | console.log('Unknown script "' + script + '".'); 20 | console.log('Perhaps you need to update preact-scripts?'); 21 | break; 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Create Preact App 2 | 3 | Create Preact apps with no build configuration. 4 | 5 | This is a fork of [create-react-app](https://github.com/facebookincubator/create-react-app). 6 | 7 | ## tl;dr 8 | 9 | ```sh 10 | npm install -g create-preact-app 11 | 12 | create-preact-app my-app 13 | cd my-app/ 14 | npm start 15 | 16 | ``` 17 | 18 | Then open [http://localhost:3000/](http://localhost:3000/) to see your app.
19 | When you’re ready to deploy to production, create a minified bundle with `npm run build`. 20 | 21 | The rest of it is quite similar to original tool, you can read its docs [here](https://github.com/facebookincubator/create-react-app#getting-started). 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 | -------------------------------------------------------------------------------- /global-cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-preact-app", 3 | "version": "0.2.0", 4 | "keywords": [ 5 | "react", 6 | "preact" 7 | ], 8 | "description": "Create Preact apps with no build configuration.", 9 | "repository": "alexkuz/create-preact-app", 10 | "license": "BSD-3-Clause", 11 | "bugs": { 12 | "url": "https://github.com/alexkuz/create-preact-app/issues" 13 | }, 14 | "files": [ 15 | "index.js" 16 | ], 17 | "bin": { 18 | "create-preact-app": "./index.js" 19 | }, 20 | "dependencies": { 21 | "chalk": "^1.1.1", 22 | "cross-spawn": "^4.0.0", 23 | "minimist": "^1.2.0", 24 | "path-exists": "^3.0.0", 25 | "semver": "^5.0.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React App 8 | 9 | 10 |
11 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /config/env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be 11 | // injected into the application via DefinePlugin in Webpack configuration. 12 | 13 | var REACT_APP = /^REACT_APP_/i; 14 | var NODE_ENV = JSON.stringify(process.env.NODE_ENV || 'development'); 15 | 16 | module.exports = Object 17 | .keys(process.env) 18 | .filter(key => REACT_APP.test(key)) 19 | .reduce((env, key) => { 20 | env['process.env.' + key] = JSON.stringify(process.env[key]); 21 | return env; 22 | }, { 23 | 'process.env.NODE_ENV': NODE_ENV 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | process.env.NODE_ENV = 'test'; 11 | 12 | const createJestConfig = require('./utils/createJestConfig'); 13 | const jest = require('jest'); 14 | const path = require('path'); 15 | const paths = require('../config/paths'); 16 | 17 | const argv = process.argv.slice(2); 18 | 19 | const index = argv.indexOf('--debug-template'); 20 | if (index !== -1) { 21 | argv.splice(index, 1); 22 | } 23 | 24 | argv.push('--config', JSON.stringify(createJestConfig( 25 | relativePath => path.resolve(__dirname, '..', relativePath), 26 | path.resolve(paths.appSrc, '..') 27 | ))); 28 | 29 | jest.run(argv); 30 | -------------------------------------------------------------------------------- /scripts/utils/createJestConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | module.exports = (resolve, rootDir) => { 11 | const config = { 12 | automock: false, 13 | moduleNameMapper: { 14 | '^[./a-zA-Z0-9$_-]+\\.(jpg|png|gif|eot|svg|ttf|woff|woff2|mp4|webm)$': resolve('config/jest/FileStub.js'), 15 | '^[./a-zA-Z0-9$_-]+\\.css$': resolve('config/jest/CSSStub.js') 16 | }, 17 | persistModuleRegistryBetweenSpecs: true, 18 | scriptPreprocessor: resolve('config/jest/transform.js'), 19 | setupFiles: [ 20 | resolve('config/polyfills.js') 21 | ], 22 | setupTestFrameworkScriptFile: resolve('config/jest/environment.js'), 23 | testPathIgnorePatterns: ['/node_modules/', '/build/'], 24 | // Allow three popular conventions: 25 | // **/__tests__/*.js 26 | // **/*.test.js 27 | // **/*.spec.js 28 | testRegex: '(__tests__/.*|\\.(test|spec))\\.js$', 29 | testEnvironment: 'node', 30 | verbose: true 31 | }; 32 | if (rootDir) { 33 | config.rootDir = rootDir; 34 | } 35 | return config; 36 | }; 37 | -------------------------------------------------------------------------------- /scripts/utils/WatchMissingNodeModulesPlugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | // This Webpack plugin ensures `npm install ` forces a project rebuild. 11 | // We’re not sure why this isn't Webpack's default behavior. 12 | // See https://github.com/facebookincubator/create-react-app/issues/186. 13 | 14 | function WatchMissingNodeModulesPlugin(nodeModulesPath) { 15 | this.nodeModulesPath = nodeModulesPath; 16 | } 17 | 18 | WatchMissingNodeModulesPlugin.prototype.apply = function (compiler) { 19 | compiler.plugin('emit', (compilation, callback) => { 20 | var missingDeps = compilation.missingDependencies; 21 | var nodeModulesPath = this.nodeModulesPath; 22 | 23 | // If any missing files are expected to appear in node_modules... 24 | if (missingDeps.some(file => file.indexOf(nodeModulesPath) !== -1)) { 25 | // ...tell webpack to watch node_modules recursively until they appear. 26 | compilation.contextDependencies.push(nodeModulesPath); 27 | } 28 | 29 | callback(); 30 | }); 31 | } 32 | 33 | module.exports = WatchMissingNodeModulesPlugin; 34 | -------------------------------------------------------------------------------- /scripts/utils/chrome.applescript: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2015-present, Facebook, Inc. 2 | -- All rights reserved. 3 | -- 4 | -- This source code is licensed under the BSD-style license found in the 5 | -- LICENSE file in the root directory of this source tree. An additional grant 6 | -- of patent rights can be found in the PATENTS file in the same directory. 7 | on run argv 8 | set theURL to item 1 of argv 9 | 10 | tell application "Chrome" 11 | 12 | if (count every window) = 0 then 13 | make new window 14 | end if 15 | 16 | -- Find a tab currently running the debugger 17 | set found to false 18 | set theTabIndex to -1 19 | repeat with theWindow in every window 20 | set theTabIndex to 0 21 | repeat with theTab in every tab of theWindow 22 | set theTabIndex to theTabIndex + 1 23 | if theTab's URL is theURL then 24 | set found to true 25 | exit repeat 26 | end if 27 | end repeat 28 | 29 | if found then 30 | exit repeat 31 | end if 32 | end repeat 33 | 34 | if found then 35 | tell theTab to reload 36 | set index of theWindow to 1 37 | set theWindow's active tab index to theTabIndex 38 | else 39 | tell window 1 40 | activate 41 | make new tab with properties {URL:theURL} 42 | end tell 43 | end if 44 | end tell 45 | end run 46 | -------------------------------------------------------------------------------- /scripts/utils/prompt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | var rl = require('readline'); 11 | 12 | // Convention: "no" should be the conservative choice. 13 | // If you mistype the answer, we'll always take it as a "no". 14 | // You can control the behavior on with `isYesDefault`. 15 | module.exports = function (question, isYesDefault) { 16 | if (typeof isYesDefault !== 'boolean') { 17 | throw new Error('Provide explicit boolean isYesDefault as second argument.'); 18 | } 19 | return new Promise(resolve => { 20 | var rlInterface = rl.createInterface({ 21 | input: process.stdin, 22 | output: process.stdout, 23 | }); 24 | 25 | var hint = isYesDefault === true ? '[Y/n]' : '[y/N]'; 26 | var message = question + ' ' + hint + '\n'; 27 | 28 | rlInterface.question(message, function(answer) { 29 | rlInterface.close(); 30 | 31 | var useDefault = answer.trim().length === 0; 32 | if (useDefault) { 33 | return resolve(isYesDefault); 34 | } 35 | 36 | var isYes = answer.match(/^(yes|y)$/i); 37 | return resolve(isYes); 38 | }); 39 | }); 40 | }; 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For create-react-app software 4 | 5 | Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /tasks/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2015-present, Facebook, Inc. 3 | # All rights reserved. 4 | # 5 | # This source code is licensed under the BSD-style license found in the 6 | # LICENSE file in the root directory of this source tree. An additional grant 7 | # of patent rights can be found in the PATENTS file in the same directory. 8 | 9 | # Start in tests/ even if run from root directory 10 | cd "$(dirname "$0")" 11 | 12 | # Exit the script on any command with non 0 return code 13 | # We assume that all the commands in the pipeline set their return code 14 | # properly and that we do not need to validate that the output is correct 15 | set -e 16 | 17 | # Echo every command being executed 18 | set -x 19 | 20 | # Go to root 21 | cd .. 22 | 23 | # You can only release with npm >= 3 24 | if [ $(npm -v | head -c 1) -lt 3 ]; then 25 | echo "Releasing requires npm >= 3. Aborting."; 26 | exit 1; 27 | fi; 28 | 29 | if [ -n "$(git status --porcelain)" ]; then 30 | echo "Your git status is not clean. Aborting."; 31 | exit 1; 32 | fi 33 | 34 | # Update deps 35 | rm -rf node_modules 36 | rm -rf ~/.npm 37 | npm cache clear 38 | npm install 39 | 40 | # Force dedupe 41 | npm dedupe 42 | 43 | # Don't bundle fsevents because it is optional and OS X-only 44 | # Since it's in optionalDependencies, it will attempt install outside bundle 45 | rm -rf node_modules/fsevents 46 | 47 | # This modifies package.json to copy all dependencies to bundledDependencies 48 | # We will revert package.json back after release to avoid doing it every time 49 | node ./node_modules/.bin/bundle-deps 50 | 51 | # Go! 52 | npm publish "$@" 53 | 54 | # Discard changes to package.json 55 | git checkout -- . 56 | -------------------------------------------------------------------------------- /config/babel.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | module.exports = { 11 | // Don't try to find .babelrc because we want to force this configuration. 12 | babelrc: false, 13 | presets: [ 14 | // let, const, destructuring, classes, modules 15 | require.resolve('babel-preset-es2015'), 16 | // exponentiation 17 | require.resolve('babel-preset-es2016'), 18 | // JSX, Flow 19 | require.resolve('babel-preset-react') 20 | ], 21 | plugins: [ 22 | // function x(a, b, c,) { } 23 | require.resolve('babel-plugin-syntax-trailing-function-commas'), 24 | // await fetch() 25 | require.resolve('babel-plugin-syntax-async-functions'), 26 | // class { handleClick = () => { } } 27 | require.resolve('babel-plugin-transform-class-properties'), 28 | // { ...todo, completed: true } 29 | require.resolve('babel-plugin-transform-object-rest-spread'), 30 | // function* () { yield 42; yield 43; } 31 | require.resolve('babel-plugin-transform-regenerator'), 32 | // Polyfills the runtime needed for async/await and generators 33 | [require.resolve('babel-plugin-transform-runtime'), { 34 | helpers: false, 35 | polyfill: false, 36 | regenerator: true 37 | }], 38 | // Optimization: hoist JSX that never changes out of render() 39 | require.resolve('babel-plugin-transform-react-constant-elements'), 40 | [require.resolve('babel-plugin-transform-react-jsx'), { 41 | pragma: 'h' 42 | }] 43 | ] 44 | }; 45 | -------------------------------------------------------------------------------- /config/babel.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | module.exports = { 11 | // Don't try to find .babelrc because we want to force this configuration. 12 | babelrc: false, 13 | // This is a feature of `babel-loader` for webpack (not Babel itself). 14 | // It enables caching results in OS temporary directory for faster rebuilds. 15 | cacheDirectory: true, 16 | presets: [ 17 | // let, const, destructuring, classes, modules 18 | require.resolve('babel-preset-es2015'), 19 | // exponentiation 20 | require.resolve('babel-preset-es2016'), 21 | // JSX, Flow 22 | require.resolve('babel-preset-react') 23 | ], 24 | plugins: [ 25 | // function x(a, b, c,) { } 26 | require.resolve('babel-plugin-syntax-trailing-function-commas'), 27 | // await fetch() 28 | require.resolve('babel-plugin-syntax-async-functions'), 29 | // class { handleClick = () => { } } 30 | require.resolve('babel-plugin-transform-class-properties'), 31 | // { ...todo, completed: true } 32 | require.resolve('babel-plugin-transform-object-rest-spread'), 33 | // function* () { yield 42; yield 43; } 34 | require.resolve('babel-plugin-transform-regenerator'), 35 | // Polyfills the runtime needed for async/await and generators 36 | [require.resolve('babel-plugin-transform-runtime'), { 37 | helpers: false, 38 | polyfill: false, 39 | regenerator: true 40 | }], 41 | [require.resolve('babel-plugin-transform-react-jsx'), { 42 | pragma: 'h' 43 | }] 44 | ] 45 | }; 46 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the create-react-app software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software 6 | ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook’s rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. 34 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `create-react-app` 2 | 3 | ♥ `create-react-app` and want to get involved? Thanks! There are plenty of ways you can help! 4 | 5 | Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. 6 | 7 | Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue or assessing patches and features. 8 | 9 | ## Core ideas 10 | 11 | We do not want any flags or configuration, that would defeat the purpose of this tool. We want to find good defaults and actively find ways to improve the developer experience. 12 | 13 | We try not to make any controversial choices. If the community is split between different tools, we won't just pick the least controversial or most popular, the tool itself should be agnostic between them. 14 | 15 | *These ideas are subject to change at any time* 16 | 17 | ## Submitting a Pull Request 18 | 19 | Good pull requests - patches, improvements, new features - are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. 20 | 21 | Please **ask first** if somebody else is already working on this or the core developers think your feature is in-scope for `create-react-app`. Generally always have a related issue with discussions for whatever you are including. 22 | 23 | Please also provide a **test plan**, i.e. specify how you verified what you added works. 24 | 25 | ## Setting up a local copy of the repository 26 | 27 | 1. Clone the repo with `git clone https://github.com/facebookincubator/create-react-app` 28 | 29 | 2. Run `npm install` in the root `create-react-app` folder **and** the `create-react-app/global-cli` folder 30 | 31 | Once it is done, you can modify any file locally and run `npm start` or `npm run build` just like in a generated project. 32 | 33 | If you want to try out the end-to-end flow with the global CLI, you can do this too: 34 | 35 | ``` 36 | npm run create-react-app my-app 37 | cd my-app 38 | ``` 39 | 40 | and then run `npm start` or `npm run build`. 41 | 42 | *Many thanks to [h5bp](https://github.com/h5bp/html5-boilerplate/blob/master/CONTRIBUTING.md) for the inspiration with this contributing guide* 43 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | // TODO: we can split this file into several files (pre-eject, post-eject, test) 11 | // and use those instead. This way we don't need to branch here. 12 | 13 | var path = require('path'); 14 | 15 | // True after ejecting, false when used as a dependency 16 | var isEjected = ( 17 | path.resolve(path.join(__dirname, '..')) === 18 | path.resolve(process.cwd()) 19 | ); 20 | 21 | // Are we developing create-react-app locally? 22 | var isInCreateReactAppSource = ( 23 | process.argv.some(arg => arg.indexOf('--debug-template') > -1) 24 | ); 25 | 26 | function resolveOwn(relativePath) { 27 | return path.resolve(__dirname, relativePath); 28 | } 29 | 30 | function resolveApp(relativePath) { 31 | return path.resolve(relativePath); 32 | } 33 | 34 | if (isInCreateReactAppSource) { 35 | // create-react-app development: we're in ./config/ 36 | module.exports = { 37 | appBuild: resolveOwn('../build'), 38 | appHtml: resolveOwn('../template/index.html'), 39 | appPackageJson: resolveOwn('../package.json'), 40 | appSrc: resolveOwn('../template/src'), 41 | appNodeModules: resolveOwn('../node_modules'), 42 | ownNodeModules: resolveOwn('../node_modules') 43 | }; 44 | } else if (!isEjected) { 45 | // before eject: we're in ./node_modules/react-scripts/config/ 46 | module.exports = { 47 | appBuild: resolveApp('build'), 48 | appHtml: resolveApp('index.html'), 49 | appPackageJson: resolveApp('package.json'), 50 | appSrc: resolveApp('src'), 51 | appNodeModules: resolveApp('node_modules'), 52 | // this is empty with npm3 but node resolution searches higher anyway: 53 | ownNodeModules: resolveOwn('../node_modules') 54 | }; 55 | } else { 56 | // after eject: we're in ./config/ 57 | module.exports = { 58 | appBuild: resolveApp('build'), 59 | appHtml: resolveApp('index.html'), 60 | appPackageJson: resolveApp('package.json'), 61 | appSrc: resolveApp('src'), 62 | appNodeModules: resolveApp('node_modules'), 63 | ownNodeModules: resolveApp('node_modules') 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /template/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preact-scripts", 3 | "version": "0.3.0-alpha", 4 | "description": "Configuration and scripts for Create Preact App.", 5 | "repository": "alexkuz/create-preact-app", 6 | "license": "BSD-3-Clause", 7 | "engines": { 8 | "node": ">=4" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/alexkuz/create-preact-app/issues" 12 | }, 13 | "scripts": { 14 | "build": "node scripts/build.js --debug-template", 15 | "create-preact-app": "node global-cli/index.js --scripts-version \"$PWD/`npm pack`\"", 16 | "e2e": "tasks/e2e.sh", 17 | "start": "node scripts/start.js --debug-template", 18 | "test": "node scripts/test.js --debug-template" 19 | }, 20 | "files": [ 21 | "PATENTS", 22 | "bin", 23 | "config", 24 | "scripts", 25 | "template" 26 | ], 27 | "bin": { 28 | "preact-scripts": "./bin/preact-scripts.js" 29 | }, 30 | "dependencies": { 31 | "autoprefixer": "6.4.0", 32 | "babel-core": "6.11.4", 33 | "babel-eslint": "6.1.2", 34 | "babel-jest": "14.1.0", 35 | "babel-loader": "6.2.4", 36 | "babel-plugin-syntax-async-functions": "6.8.0", 37 | "babel-plugin-syntax-trailing-function-commas": "6.8.0", 38 | "babel-plugin-transform-class-properties": "6.11.5", 39 | "babel-plugin-transform-object-rest-spread": "6.8.0", 40 | "babel-plugin-transform-react-constant-elements": "6.9.1", 41 | "babel-plugin-transform-regenerator": "6.11.4", 42 | "babel-plugin-transform-runtime": "6.12.0", 43 | "babel-preset-es2015": "6.9.0", 44 | "babel-preset-es2016": "6.11.3", 45 | "babel-preset-react": "6.11.1", 46 | "babel-runtime": "6.11.6", 47 | "case-sensitive-paths-webpack-plugin": "1.1.3", 48 | "chalk": "1.1.3", 49 | "connect-history-api-fallback": "1.3.0", 50 | "cross-spawn": "4.0.0", 51 | "css-loader": "0.23.1", 52 | "detect-port": "1.0.0", 53 | "eslint": "3.2.2", 54 | "eslint-loader": "1.4.1", 55 | "eslint-plugin-flowtype": "2.4.0", 56 | "eslint-plugin-import": "1.12.0", 57 | "eslint-plugin-jsx-a11y": "2.0.1", 58 | "eslint-plugin-react": "5.2.2", 59 | "extract-text-webpack-plugin": "1.0.1", 60 | "file-loader": "0.9.0", 61 | "filesize": "3.3.0", 62 | "fs-extra": "0.30.0", 63 | "gzip-size": "3.0.0", 64 | "html-loader": "0.4.3", 65 | "html-webpack-plugin": "2.22.0", 66 | "http-proxy-middleware": "0.17.0", 67 | "jest": "14.1.0", 68 | "json-loader": "0.5.4", 69 | "object-assign": "4.1.0", 70 | "opn": "4.0.2", 71 | "path-exists": "3.0.0", 72 | "postcss-loader": "0.9.1", 73 | "promise": "7.1.1", 74 | "recursive-readdir": "2.0.0", 75 | "rimraf": "2.5.4", 76 | "strip-ansi": "3.0.1", 77 | "style-loader": "0.13.1", 78 | "url-loader": "0.5.7", 79 | "webpack": "1.13.1", 80 | "webpack-dev-server": "1.14.1", 81 | "whatwg-fetch": "1.0.0" 82 | }, 83 | "devDependencies": { 84 | "bundle-deps": "1.0.0", 85 | "preact": "^5.6.0", 86 | "react-test-renderer": "^15.3.0" 87 | }, 88 | "optionalDependencies": { 89 | "fsevents": "1.0.14" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /tasks/e2e.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2015-present, Facebook, Inc. 3 | # All rights reserved. 4 | # 5 | # This source code is licensed under the BSD-style license found in the 6 | # LICENSE file in the root directory of this source tree. An additional grant 7 | # of patent rights can be found in the PATENTS file in the same directory. 8 | 9 | # Start in tests/ even if run from root directory 10 | cd "$(dirname "$0")" 11 | 12 | function cleanup { 13 | echo 'Cleaning up.' 14 | cd $initial_path 15 | rm ../template/src/__tests__/__snapshots__/App-test.js.snap 16 | rm -rf $temp_cli_path $temp_app_path 17 | } 18 | 19 | function handle_error { 20 | echo "$(basename $0): \033[31mERROR!\033[m An error was encountered executing \033[36mline $1\033[m." 21 | cleanup 22 | echo 'Exiting with error.' 23 | exit 1 24 | } 25 | 26 | function handle_exit { 27 | cleanup 28 | echo 'Exiting without error.' 29 | exit 30 | } 31 | 32 | # Exit the script with a helpful error message when any error is encountered 33 | trap 'set +x; handle_error $LINENO $BASH_COMMAND' ERR 34 | 35 | # Cleanup before exit on any termination signal 36 | trap 'set +x; handle_exit' SIGQUIT SIGTERM SIGINT SIGKILL SIGHUP 37 | 38 | # Echo every command being executed 39 | set -x 40 | 41 | # npm pack the two directories to make sure they are valid npm modules 42 | initial_path=$PWD 43 | 44 | cd .. 45 | 46 | # A hacky way to avoid bundling dependencies. 47 | # Packing with them enabled takes too much memory, and Travis crashes. 48 | # End to end script is meant to run on Travis so it's not a big deal. 49 | # If you run it locally, you'll need to `git checkout -- package.json`. 50 | perl -i -p0e 's/bundledDependencies.*?]/bundledDependencies": []/s' package.json 51 | 52 | # Pack react-scripts 53 | npm install 54 | scripts_path=$PWD/`npm pack` 55 | 56 | # lint 57 | ./node_modules/.bin/eslint --ignore-path .gitignore ./ 58 | 59 | # Test local start command 60 | npm start -- --smoke-test 61 | 62 | # Test local build command 63 | npm run build 64 | 65 | # Check for expected output 66 | test -e build/*.html 67 | test -e build/static/js/*.js 68 | test -e build/static/css/*.css 69 | test -e build/static/media/*.svg 70 | test -e build/favicon.ico 71 | 72 | # Run tests 73 | npm run test 74 | test -e template/src/__tests__/__snapshots__/App-test.js.snap 75 | 76 | # Pack CLI 77 | cd global-cli 78 | npm install 79 | cli_path=$PWD/`npm pack` 80 | 81 | # Install the cli in a temporary location ( http://unix.stackexchange.com/a/84980 ) 82 | temp_cli_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_cli_path'` 83 | cd $temp_cli_path 84 | npm install $cli_path 85 | 86 | # Install the app in a temporary location 87 | temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'` 88 | cd $temp_app_path 89 | node "$temp_cli_path"/node_modules/create-preact-app/index.js --scripts-version=$scripts_path test-app 90 | cd test-app 91 | 92 | # Test the build 93 | npm run build 94 | 95 | # Check for expected output 96 | test -e build/*.html 97 | test -e build/static/js/*.js 98 | test -e build/static/css/*.css 99 | test -e build/static/media/*.svg 100 | test -e build/favicon.ico 101 | 102 | # Run tests 103 | npm run test 104 | test -e src/__tests__/__snapshots__/App-test.js.snap 105 | 106 | # Test the server 107 | npm start -- --smoke-test 108 | 109 | # Eject and test the build 110 | echo yes | npm run eject 111 | npm run build 112 | 113 | # Check for expected output 114 | test -e build/*.html 115 | test -e build/static/js/*.js 116 | test -e build/static/css/*.css 117 | test -e build/static/media/*.svg 118 | test -e build/favicon.ico 119 | 120 | # Run tests 121 | npm run test 122 | test -e src/__tests__/__snapshots__/App-test.js.snap 123 | 124 | # Test the server 125 | npm start -- --smoke-test 126 | 127 | # Cleanup 128 | cleanup 129 | -------------------------------------------------------------------------------- /scripts/init.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | var fs = require('fs-extra'); 11 | var path = require('path'); 12 | var spawn = require('cross-spawn'); 13 | var pathExists = require('path-exists'); 14 | var chalk = require('chalk'); 15 | 16 | module.exports = function(appPath, appName, verbose, originalDirectory) { 17 | var ownPath = path.join(appPath, 'node_modules', 'preact-scripts'); 18 | 19 | var appPackage = require(path.join(appPath, 'package.json')); 20 | var ownPackage = require(path.join(ownPath, 'package.json')); 21 | 22 | // Copy over some of the devDependencies 23 | appPackage.dependencies = appPackage.dependencies || {}; 24 | appPackage.devDependencies = appPackage.devDependencies || {}; 25 | ['preact'].forEach(function (key) { 26 | appPackage.dependencies[key] = ownPackage.devDependencies[key]; 27 | }); 28 | ['react-test-renderer'].forEach(function (key) { 29 | appPackage.devDependencies[key] = ownPackage.devDependencies[key]; 30 | }); 31 | 32 | // Setup the script rules 33 | appPackage.scripts = {}; 34 | ['start', 'build', 'eject', 'test'].forEach(function(command) { 35 | appPackage.scripts[command] = 'preact-scripts ' + command; 36 | }); 37 | 38 | // explicitly specify ESLint config path for editor plugins 39 | appPackage.eslintConfig = { 40 | extends: './node_modules/preact-scripts/config/eslint.js', 41 | }; 42 | 43 | fs.writeFileSync( 44 | path.join(appPath, 'package.json'), 45 | JSON.stringify(appPackage, null, 2) 46 | ); 47 | 48 | var readmeExists = pathExists.sync(path.join(appPath, 'README.md')); 49 | if (readmeExists) { 50 | fs.renameSync(path.join(appPath, 'README.md'), path.join(appPath, 'README.old.md')); 51 | } 52 | 53 | // Copy the files for the user 54 | fs.copySync(path.join(ownPath, 'template'), appPath); 55 | 56 | // Rename gitignore after the fact to prevent npm from renaming it to .npmignore 57 | // See: https://github.com/npm/npm/issues/1862 58 | fs.move(path.join(appPath, 'gitignore'), path.join(appPath, '.gitignore'), [], function (err) { 59 | if (err) { 60 | // Append if there's already a `.gitignore` file there 61 | if (err.code === 'EEXIST') { 62 | var data = fs.readFileSync(path.join(appPath, 'gitignore')); 63 | fs.appendFileSync(path.join(appPath, '.gitignore'), data); 64 | fs.unlinkSync(path.join(appPath, 'gitignore')); 65 | } else { 66 | throw err; 67 | } 68 | } 69 | }); 70 | 71 | // Run another npm install for preact 72 | console.log('Installing preact from npm...'); 73 | console.log(); 74 | // TODO: having to do two npm installs is bad, can we avoid it? 75 | var args = [ 76 | 'install', 77 | verbose && '--verbose' 78 | ].filter(function(e) { return e; }); 79 | var proc = spawn('npm', args, {stdio: 'inherit'}); 80 | proc.on('close', function (code) { 81 | if (code !== 0) { 82 | console.error('`npm ' + args.join(' ') + '` failed'); 83 | return; 84 | } 85 | 86 | // Display the most elegant way to cd. 87 | // This needs to handle an undefined originalDirectory for 88 | // backward compatibility with old global-cli's. 89 | var cdpath; 90 | if (originalDirectory && 91 | path.join(originalDirectory, appName) === appPath) { 92 | cdpath = appName; 93 | } else { 94 | cdpath = appPath; 95 | } 96 | 97 | console.log(); 98 | console.log('Success! Created ' + appName + ' at ' + appPath + '.'); 99 | console.log('Inside that directory, you can run several commands:'); 100 | console.log(); 101 | console.log(' * npm start: Starts the development server.'); 102 | console.log(' * npm run build: Bundles the app into static files for production.'); 103 | console.log(' * npm run eject: Removes this tool. If you do this, you can’t go back!'); 104 | console.log(); 105 | console.log('We suggest that you begin by typing:'); 106 | console.log(); 107 | console.log(' cd', cdpath); 108 | console.log(' npm start'); 109 | if (readmeExists) { 110 | console.log(); 111 | console.log(chalk.yellow('You had a `README.md` file, we renamed it to `README.old.md`')); 112 | } 113 | console.log(); 114 | console.log('Happy hacking!'); 115 | }); 116 | }; 117 | -------------------------------------------------------------------------------- /scripts/eject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | var createJestConfig = require('./utils/createJestConfig'); 11 | var fs = require('fs'); 12 | var path = require('path'); 13 | var prompt = require('./utils/prompt'); 14 | var rimrafSync = require('rimraf').sync; 15 | var spawnSync = require('cross-spawn').sync; 16 | 17 | prompt( 18 | 'Are you sure you want to eject? This action is permanent.', 19 | false 20 | ).then(shouldEject => { 21 | if (!shouldEject) { 22 | console.log('Close one! Eject aborted.'); 23 | process.exit(1); 24 | } 25 | 26 | console.log('Ejecting...'); 27 | console.log(); 28 | 29 | var ownPath = path.join(__dirname, '..'); 30 | var appPath = path.join(ownPath, '..', '..'); 31 | var files = [ 32 | path.join('config', 'babel.dev.js'), 33 | path.join('config', 'babel.prod.js'), 34 | path.join('config', 'flow', 'css.js.flow'), 35 | path.join('config', 'flow', 'file.js.flow'), 36 | path.join('config', 'eslint.js'), 37 | path.join('config', 'paths.js'), 38 | path.join('config', 'env.js'), 39 | path.join('config', 'polyfills.js'), 40 | path.join('config', 'webpack.config.dev.js'), 41 | path.join('config', 'webpack.config.prod.js'), 42 | path.join('config', 'jest', 'CSSStub.js'), 43 | path.join('config', 'jest', 'FileStub.js'), 44 | path.join('config', 'jest', 'environment.js'), 45 | path.join('config', 'jest', 'transform.js'), 46 | path.join('scripts', 'build.js'), 47 | path.join('scripts', 'start.js'), 48 | path.join('scripts', 'utils', 'chrome.applescript'), 49 | path.join('scripts', 'utils', 'prompt.js'), 50 | path.join('scripts', 'utils', 'WatchMissingNodeModulesPlugin.js') 51 | ]; 52 | 53 | // Ensure that the app folder is clean and we won't override any files 54 | files.forEach(function(file) { 55 | if (fs.existsSync(path.join(appPath, file))) { 56 | console.error( 57 | '`' + file + '` already exists in your app folder. We cannot ' + 58 | 'continue as you would lose all the changes in that file or directory. ' + 59 | 'Please delete it (maybe make a copy for backup) and run this ' + 60 | 'command again.' 61 | ); 62 | process.exit(1); 63 | } 64 | }); 65 | 66 | // Copy the files over 67 | fs.mkdirSync(path.join(appPath, 'config')); 68 | fs.mkdirSync(path.join(appPath, 'config', 'flow')); 69 | fs.mkdirSync(path.join(appPath, 'config', 'jest')); 70 | fs.mkdirSync(path.join(appPath, 'scripts')); 71 | fs.mkdirSync(path.join(appPath, 'scripts', 'utils')); 72 | 73 | files.forEach(function(file) { 74 | console.log('Copying ' + file + ' to ' + appPath); 75 | var content = fs 76 | .readFileSync(path.join(ownPath, file), 'utf8') 77 | // Remove license header from JS 78 | .replace(/^\/\*\*(\*(?!\/)|[^*])*\*\//, '') 79 | // Remove license header from AppleScript 80 | .replace(/^--.*\n/gm, '') 81 | .trim() + '\n'; 82 | fs.writeFileSync(path.join(appPath, file), content); 83 | }); 84 | console.log(); 85 | 86 | var ownPackage = require(path.join(ownPath, 'package.json')); 87 | var appPackage = require(path.join(appPath, 'package.json')); 88 | 89 | console.log('Removing dependency: preact-scripts'); 90 | delete appPackage.devDependencies['preact-scripts']; 91 | 92 | Object.keys(ownPackage.dependencies).forEach(function (key) { 93 | // For some reason optionalDependencies end up in dependencies after install 94 | if (ownPackage.optionalDependencies[key]) { 95 | return; 96 | } 97 | console.log('Adding dependency: ' + key); 98 | appPackage.devDependencies[key] = ownPackage.dependencies[key]; 99 | }); 100 | 101 | console.log('Updating scripts'); 102 | Object.keys(appPackage.scripts).forEach(function (key) { 103 | appPackage.scripts[key] = 'node ./scripts/' + key + '.js' 104 | }); 105 | delete appPackage.scripts['eject']; 106 | 107 | appPackage.scripts.test = 'jest'; 108 | appPackage.jest = createJestConfig( 109 | filePath => path.join('', filePath) 110 | ); 111 | 112 | // explicitly specify ESLint config path for editor plugins 113 | appPackage.eslintConfig = { 114 | extends: './config/eslint.js', 115 | }; 116 | 117 | console.log('Writing package.json'); 118 | fs.writeFileSync( 119 | path.join(appPath, 'package.json'), 120 | JSON.stringify(appPackage, null, 2) 121 | ); 122 | console.log(); 123 | 124 | console.log('Running npm install...'); 125 | rimrafSync(ownPath); 126 | spawnSync('npm', ['install'], {stdio: 'inherit'}); 127 | console.log('Ejected successfully!'); 128 | console.log(); 129 | 130 | console.log('Please consider sharing why you ejected in this survey:'); 131 | console.log(' http://goo.gl/forms/Bi6CZjk1EqsdelXk1'); 132 | console.log(); 133 | }); 134 | -------------------------------------------------------------------------------- /global-cli/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Copyright (c) 2015-present, Facebook, Inc. 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. An additional grant 9 | * of patent rights can be found in the PATENTS file in the same directory. 10 | */ 11 | 12 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 13 | // /!\ DO NOT MODIFY THIS FILE /!\ 14 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | // 16 | // create-preact-app is installed globally on people's computers. This means 17 | // that it is extremely difficult to have them upgrade the version and 18 | // because there's only one global version installed, it is very prone to 19 | // breaking changes. 20 | // 21 | // The only job of create-preact-app is to init the repository and then 22 | // forward all the commands to the local version of create-preact-app. 23 | // 24 | // If you need to add a new command, please add it to the scripts/ folder. 25 | // 26 | // The only reason to modify this file is to add more warnings and 27 | // troubleshooting information for the `create-preact-app` command. 28 | // 29 | // Do not make breaking changes! We absolutely don't want to have to 30 | // tell people to update their global version of create-preact-app. 31 | // 32 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 33 | // /!\ DO NOT MODIFY THIS FILE /!\ 34 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 35 | 36 | 'use strict'; 37 | 38 | var fs = require('fs'); 39 | var path = require('path'); 40 | var spawn = require('cross-spawn'); 41 | var chalk = require('chalk'); 42 | var semver = require('semver'); 43 | var argv = require('minimist')(process.argv.slice(2)); 44 | var pathExists = require('path-exists'); 45 | 46 | /** 47 | * Arguments: 48 | * --version - to print current version 49 | * --verbose - to print logs while init 50 | * --scripts-version 51 | * Example of valid values: 52 | * - a specific npm version: "0.22.0-rc1" 53 | * - a .tgz archive from any npm repo: "https://registry.npmjs.org/react-scripts/-/react-scripts-0.20.0.tgz" 54 | * - a package prepared with `npm pack`: "/Users/home/vjeux/create-react-app/react-scripts-0.22.0.tgz" 55 | */ 56 | var commands = argv._; 57 | if (commands.length === 0) { 58 | if (argv.version) { 59 | console.log('create-preact-app version: ' + require('./package.json').version); 60 | process.exit(); 61 | } 62 | console.error( 63 | 'Usage: create-preact-app [--verbose]' 64 | ); 65 | process.exit(1); 66 | } 67 | 68 | createApp(commands[0], argv.verbose, argv['scripts-version']); 69 | 70 | function createApp(name, verbose, version) { 71 | var root = path.resolve(name); 72 | if (!pathExists.sync(name)) { 73 | fs.mkdirSync(root); 74 | } else if (!isGitHubBoilerplate(root)) { 75 | console.log('The directory `' + name + '` contains file(s) that could conflict. Aborting.'); 76 | process.exit(1); 77 | } 78 | 79 | var appName = path.basename(root); 80 | console.log( 81 | 'Creating a new Preact app in ' + root + '.' 82 | ); 83 | console.log(); 84 | 85 | var packageJson = { 86 | name: appName, 87 | version: '0.0.1', 88 | private: true, 89 | }; 90 | fs.writeFileSync( 91 | path.join(root, 'package.json'), 92 | JSON.stringify(packageJson, null, 2) 93 | ); 94 | var originalDirectory = process.cwd(); 95 | process.chdir(root); 96 | 97 | console.log('Installing packages. This might take a couple minutes.'); 98 | console.log('Installing preact-scripts from npm...'); 99 | console.log(); 100 | 101 | run(root, appName, version, verbose, originalDirectory); 102 | } 103 | 104 | function run(root, appName, version, verbose, originalDirectory) { 105 | var args = [ 106 | 'install', 107 | verbose && '--verbose', 108 | '--save-dev', 109 | '--save-exact', 110 | getInstallPackage(version), 111 | ].filter(function(e) { return e; }); 112 | var proc = spawn('npm', args, {stdio: 'inherit'}); 113 | proc.on('close', function (code) { 114 | if (code !== 0) { 115 | console.error('`npm ' + args.join(' ') + '` failed'); 116 | return; 117 | } 118 | 119 | checkNodeVersion(); 120 | 121 | var scriptsPath = path.resolve( 122 | process.cwd(), 123 | 'node_modules', 124 | 'preact-scripts', 125 | 'scripts', 126 | 'init.js' 127 | ); 128 | var init = require(scriptsPath); 129 | init(root, appName, verbose, originalDirectory); 130 | }); 131 | } 132 | 133 | function getInstallPackage(version) { 134 | var packageToInstall = 'preact-scripts'; 135 | var validSemver = semver.valid(version); 136 | if (validSemver) { 137 | packageToInstall += '@' + validSemver; 138 | } else if (version) { 139 | // for tar.gz or alternative paths 140 | packageToInstall = version; 141 | } 142 | return packageToInstall; 143 | } 144 | 145 | function checkNodeVersion() { 146 | var packageJsonPath = path.resolve( 147 | process.cwd(), 148 | 'node_modules', 149 | 'preact-scripts', 150 | 'package.json' 151 | ); 152 | var packageJson = require(packageJsonPath); 153 | if (!packageJson.engines || !packageJson.engines.node) { 154 | return; 155 | } 156 | 157 | if (!semver.satisfies(process.version, packageJson.engines.node)) { 158 | console.error( 159 | chalk.red( 160 | 'You are currently running Node %s but create-preact-app requires %s.' + 161 | ' Please use a supported version of Node.\n' 162 | ), 163 | process.version, 164 | packageJson.engines.node 165 | ); 166 | process.exit(1); 167 | } 168 | } 169 | 170 | // Check if GitHub boilerplate compatible 171 | // https://github.com/facebookincubator/create-react-app/pull/368#issuecomment-237875655 172 | function isGitHubBoilerplate(root) { 173 | var validFiles = [ 174 | '.DS_Store', 'Thumbs.db', '.git', '.gitignore', 'README.md', 'LICENSE' 175 | ]; 176 | return fs.readdirSync(root) 177 | .every(function(file) { 178 | return validFiles.indexOf(file) >= 0; 179 | }); 180 | } 181 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.2.1 (August 1, 2016) 2 | 3 | ### Build Dependency (`react-scripts`) 4 | 5 | * Fixes an issue with `npm start` taking a very long time on OS X with Firewall enabled ([@gaearon](https://github.com/gaearon) in [#319](https://github.com/facebookincubator/create-react-app/pull/319)) 6 | * Fixes an issue with Webpack eating a lot of CPU in some cases ([@dceddia](https://github.com/dceddia) in [#294](https://github.com/facebookincubator/create-react-app/pull/294)) 7 | * We now warn if you import a file with mismatched casing because this breaks the watcher ([@alexzherdev](https://github.com/alexzherdev) in [#266](https://github.com/facebookincubator/create-react-app/pull/266)) 8 | * CSS files specifying `?v=` after asset filenames, such as Font Awesome, now works correctly ([@alexzherdev](https://github.com/alexzherdev) in [#298](https://github.com/facebookincubator/create-react-app/pull/298)) 9 | * Issues with `npm link`ing `react-scripts` have been fixed ([@dallonf](https://github.com/dallonf) in [#277](https://github.com/facebookincubator/create-react-app/pull/277)) 10 | * We now use `/static` prefix for assets both in development and production ([@gaearon](https://github.com/gaearon) in [#278](https://github.com/facebookincubator/create-react-app/pull/278)) 11 | 12 | ### Migrating from 0.2.0 to 0.2.1 13 | 14 | Update `react-scripts` to point to `0.2.1` in your `package.json` and run `npm install`. You shouldn’t need to do anything else. If you see a warning about wrong file casing next time you `npm start`, fix your imports to use the correct filename casing. 15 | 16 | Newly created projects will use `0.2.1` automatically. You **don’t** need to update the global `create-react-app` CLI itself. It stays at `0.2.0` for now because it doesn’t have any changes. 17 | 18 | ## 0.2.0 (July 28, 2016) 19 | 20 | ### Build Dependency (`react-scripts`) 21 | 22 | * You can now enable deployment to GitHub Pages by adding `homepage` field to `package.json` ([@dhruska](https://github.com/dhruska) in [#94](https://github.com/facebookincubator/create-react-app/pull/94)) 23 | * Development server now runs on `0.0.0.0` and works with VirtualBox ([@JWo1F](https://github.com/JWo1F) in [#128](https://github.com/facebookincubator/create-react-app/pull/128)) 24 | * Cloud9 and Nitrous online IDEs are now supported ([@gaearon](http://github.com/gaearon) in [2fe84e](https://github.com/facebookincubator/create-react-app/commit/2fe84ecded55f1d5258d91f9c2c07698ae0d2fb4)) 25 | * When `3000` port is taken, we offer to use another port ([@chocnut](https://github.com/chocnut) in [#101](https://github.com/facebookincubator/create-react-app/pull/101), [2edf21](https://github.com/facebookincubator/create-react-app/commit/2edf2180f2aa6bf647807d0b1fcd95f4cfe4a558)) 26 | * You can now `import` CSS files from npm modules ([@glennreyes](https://github.com/glennreyes) in [#105](https://github.com/facebookincubator/create-react-app/pull/105), [@breaddevil](https://github.com/breaddevil) in [#178](https://github.com/facebookincubator/create-react-app/pull/178)) 27 | * `fetch` and `Promise` polyfills are now always included ([@gaearon](https://github.com/gaearon) in [#235](https://github.com/facebookincubator/create-react-app/pull/235)) 28 | * Regenerator runtime is now included if you use ES6 generators ([@gaearon](https://github.com/gaearon) in [#238](https://github.com/facebookincubator/create-react-app/pull/238)) 29 | * Generated project now contains `.gitignore` ([@npverni](https://github.com/npverni) in [#79](https://github.com/facebookincubator/create-react-app/pull/79), [@chibicode](https://github.com/chibicode) in [#112](https://github.com/facebookincubator/create-react-app/pull/112)) 30 | * ESLint config is now more compatible with Flow ([@gaearon](https://github.com/gaearon) in [#261](https://github.com/facebookincubator/create-react-app/pull/261)) 31 | * A stylistic lint rule about method naming has been removed ([@mxstbr](https://github.com/mxstbr) in [#152](https://github.com/facebookincubator/create-react-app/pull/157)) 32 | * A few unobtrusive accessibility lint rules have been added ([@evcohen](https://github.com/evcohen) in [#175](https://github.com/facebookincubator/create-react-app/pull/175)) 33 | * A `.babelrc` in parent directory no longer causes an error ([@alexzherdev](https://github.com/alexzherdev) in [#236](https://github.com/facebookincubator/create-react-app/pull/236)) 34 | * Files with `.json` extension are now discovered ([@gaearon](https://github.com/gaearon) in [a11d6a](https://github.com/facebookincubator/create-react-app/commit/a11d6a398f487f9163880dd34667b1d3e14b147a)) 35 | * Bug fixes from transitive dependencies are included ([#126](https://github.com/facebookincubator/create-react-app/issues/126)) 36 | * Linting now works with IDEs if you follow [these](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md#display-lint-output-in-the-editor) instructions ([@keyanzhang](https://github.com/keyanzhang) in [#149](https://github.com/facebookincubator/create-react-app/pull/149)) 37 | * After building, we now print gzipped bundle size ([@lvwrence](https://github.com/lvwrence) in [#229](https://github.com/facebookincubator/create-react-app/pull/229)) 38 | 39 | ### Global CLI (`create-react-app`) 40 | 41 | * It enforces that you have Node >= 4 ([@conorhastings](https://github.com/conorhastings) in [#88](https://github.com/facebookincubator/create-react-app/pull/88)) 42 | * It handles `--version` flag correctly ([@mxstbr](https://github.com/mxstbr) in [#152](https://github.com/facebookincubator/create-react-app/pull/152)) 43 | 44 | ### Migrating from 0.1.0 to 0.2.0 45 | 46 | You may optionally update the global command (it’s not required): 47 | 48 | ``` 49 | npm install -g create-react-app@0.2.0 50 | ``` 51 | 52 | Inside any created project that has not been ejected, run: 53 | 54 | ``` 55 | npm install --save-dev --save-exact react-scripts@0.2.0 56 | ``` 57 | 58 | You may need to fix a few lint warnings about missing `` tag, but everything else should work out of the box. If you intend to deploy your site to GitHub Pages, you may now [add `homepage` field to `package.json`](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md#deploy-to-github-pages). If you had [issues with integrating editor linter plugins](https://github.com/facebookincubator/create-react-app/issues/124), follow [these new instructions](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md#display-lint-output-in-the-editor). 59 | 60 | ## 0.1.0 (July 22, 2016) 61 | 62 | * Initial public release 63 | -------------------------------------------------------------------------------- /config/eslint.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | // Inspired by https://github.com/airbnb/javascript but less opinionated. 11 | 12 | // We use eslint-loader so even warnings are very visibile. 13 | // This is why we only use "WARNING" level for potential errors, 14 | // and we don't use "ERROR" level at all. 15 | 16 | // In the future, we might create a separate list of rules for production. 17 | // It would probably be more strict. 18 | 19 | module.exports = { 20 | root: true, 21 | 22 | parser: 'babel-eslint', 23 | 24 | // import plugin is termporarily disabled, scroll below to see why 25 | plugins: [/*'import', */'flowtype', 'jsx-a11y', 'react'], 26 | 27 | env: { 28 | browser: true, 29 | commonjs: true, 30 | es6: true, 31 | jest: true, 32 | node: true 33 | }, 34 | 35 | parserOptions: { 36 | ecmaVersion: 6, 37 | sourceType: 'module', 38 | ecmaFeatures: { 39 | jsx: true, 40 | generators: true, 41 | experimentalObjectRestSpread: true 42 | } 43 | }, 44 | 45 | settings: { 46 | 'import/ignore': [ 47 | 'node_modules', 48 | '\\.(json|css|jpg|png|gif|eot|svg|ttf|woff|woff2|mp4|webm)$', 49 | ], 50 | 'import/extensions': ['.js'], 51 | 'import/resolver': { 52 | node: { 53 | extensions: ['.js', '.json'] 54 | } 55 | }, 56 | react: { 57 | pragma: 'h' 58 | } 59 | }, 60 | 61 | rules: { 62 | // http://eslint.org/docs/rules/ 63 | 'array-callback-return': 'warn', 64 | 'default-case': ['warn', { commentPattern: '^no default$' }], 65 | 'dot-location': ['warn', 'property'], 66 | eqeqeq: ['warn', 'allow-null'], 67 | 'guard-for-in': 'warn', 68 | 'new-cap': ['warn', { newIsCap: true }], 69 | 'new-parens': 'warn', 70 | 'no-array-constructor': 'warn', 71 | 'no-caller': 'warn', 72 | 'no-cond-assign': ['warn', 'always'], 73 | 'no-const-assign': 'warn', 74 | 'no-control-regex': 'warn', 75 | 'no-delete-var': 'warn', 76 | 'no-dupe-args': 'warn', 77 | 'no-dupe-class-members': 'warn', 78 | 'no-dupe-keys': 'warn', 79 | 'no-duplicate-case': 'warn', 80 | 'no-empty-character-class': 'warn', 81 | 'no-empty-pattern': 'warn', 82 | 'no-eval': 'warn', 83 | 'no-ex-assign': 'warn', 84 | 'no-extend-native': 'warn', 85 | 'no-extra-bind': 'warn', 86 | 'no-extra-label': 'warn', 87 | 'no-fallthrough': 'warn', 88 | 'no-func-assign': 'warn', 89 | 'no-implied-eval': 'warn', 90 | 'no-invalid-regexp': 'warn', 91 | 'no-iterator': 'warn', 92 | 'no-label-var': 'warn', 93 | 'no-labels': ['warn', { allowLoop: false, allowSwitch: false }], 94 | 'no-lone-blocks': 'warn', 95 | 'no-loop-func': 'warn', 96 | 'no-mixed-operators': ['warn', { 97 | groups: [ 98 | ['&', '|', '^', '~', '<<', '>>', '>>>'], 99 | ['==', '!=', '===', '!==', '>', '>=', '<', '<='], 100 | ['&&', '||'], 101 | ['in', 'instanceof'] 102 | ], 103 | allowSamePrecedence: false 104 | }], 105 | 'no-multi-str': 'warn', 106 | 'no-native-reassign': 'warn', 107 | 'no-negated-in-lhs': 'warn', 108 | 'no-new-func': 'warn', 109 | 'no-new-object': 'warn', 110 | 'no-new-symbol': 'warn', 111 | 'no-new-wrappers': 'warn', 112 | 'no-obj-calls': 'warn', 113 | 'no-octal': 'warn', 114 | 'no-octal-escape': 'warn', 115 | 'no-redeclare': 'warn', 116 | 'no-regex-spaces': 'warn', 117 | 'no-restricted-syntax': [ 118 | 'warn', 119 | 'LabeledStatement', 120 | 'WithStatement', 121 | ], 122 | 'no-return-assign': 'warn', 123 | 'no-script-url': 'warn', 124 | 'no-self-assign': 'warn', 125 | 'no-self-compare': 'warn', 126 | 'no-sequences': 'warn', 127 | 'no-shadow-restricted-names': 'warn', 128 | 'no-sparse-arrays': 'warn', 129 | 'no-this-before-super': 'warn', 130 | 'no-throw-literal': 'warn', 131 | 'no-undef': 'warn', 132 | 'no-unexpected-multiline': 'warn', 133 | 'no-unreachable': 'warn', 134 | 'no-unused-expressions': 'warn', 135 | 'no-unused-labels': 'warn', 136 | 'no-unused-vars': ['warn', { vars: 'local', args: 'none' }], 137 | 'no-use-before-define': ['warn', 'nofunc'], 138 | 'no-useless-computed-key': 'warn', 139 | 'no-useless-concat': 'warn', 140 | 'no-useless-constructor': 'warn', 141 | 'no-useless-escape': 'warn', 142 | 'no-useless-rename': ['warn', { 143 | ignoreDestructuring: false, 144 | ignoreImport: false, 145 | ignoreExport: false, 146 | }], 147 | 'no-with': 'warn', 148 | 'no-whitespace-before-property': 'warn', 149 | 'operator-assignment': ['warn', 'always'], 150 | radix: 'warn', 151 | 'require-yield': 'warn', 152 | 'rest-spread-spacing': ['warn', 'never'], 153 | strict: ['warn', 'never'], 154 | 'unicode-bom': ['warn', 'never'], 155 | 'use-isnan': 'warn', 156 | 'valid-typeof': 'warn', 157 | 158 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/ 159 | 160 | // TODO: import rules are temporarily disabled because they don't play well 161 | // with how eslint-loader only checks the file you change. So if module A 162 | // imports module B, and B is missing a default export, the linter will 163 | // record this as an issue in module A. Now if you fix module B, the linter 164 | // will not be aware that it needs to re-lint A as well, so the error 165 | // will stay until the next restart, which is really confusing. 166 | 167 | // This is probably fixable with a patch to eslint-loader. 168 | // When file A is saved, we want to invalidate all files that import it 169 | // *and* that currently have lint errors. This should fix the problem. 170 | 171 | // 'import/default': 'warn', 172 | // 'import/export': 'warn', 173 | // 'import/named': 'warn', 174 | // 'import/namespace': 'warn', 175 | // 'import/no-amd': 'warn', 176 | // 'import/no-duplicates': 'warn', 177 | // 'import/no-extraneous-dependencies': 'warn', 178 | // 'import/no-named-as-default': 'warn', 179 | // 'import/no-named-as-default-member': 'warn', 180 | // 'import/no-unresolved': ['warn', { commonjs: true }], 181 | 182 | // https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules 183 | 'react/jsx-equals-spacing': ['warn', 'never'], 184 | 'react/jsx-no-duplicate-props': ['warn', { ignoreCase: true }], 185 | 'react/jsx-no-undef': 'warn', 186 | 'react/jsx-pascal-case': ['warn', { 187 | allowAllCaps: true, 188 | ignore: [], 189 | }], 190 | 'react/jsx-uses-react': 'warn', 191 | 'react/jsx-uses-vars': 'warn', 192 | 'react/no-deprecated': 'warn', 193 | 'react/no-direct-mutation-state': 'warn', 194 | 'react/no-is-mounted': 'warn', 195 | 'react/react-in-jsx-scope': 'warn', 196 | 'react/require-render-return': 'warn', 197 | 198 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/tree/master/docs/rules 199 | 'jsx-a11y/aria-role': 'warn', 200 | 'jsx-a11y/img-has-alt': 'warn', 201 | 'jsx-a11y/img-redundant-alt': 'warn', 202 | 'jsx-a11y/no-access-key': 'warn', 203 | 204 | // https://github.com/gajus/eslint-plugin-flowtype 205 | 'flowtype/define-flow-type': 'warn', 206 | 'flowtype/require-valid-file-annotation': 'warn', 207 | 'flowtype/use-flow-type': 'warn' 208 | } 209 | }; 210 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | // Do this as the first thing so that any code reading it knows the right env. 11 | process.env.NODE_ENV = 'production'; 12 | 13 | var chalk = require('chalk'); 14 | var fs = require('fs'); 15 | var path = require('path'); 16 | var filesize = require('filesize'); 17 | var gzipSize = require('gzip-size').sync; 18 | var rimrafSync = require('rimraf').sync; 19 | var webpack = require('webpack'); 20 | var config = require('../config/webpack.config.prod'); 21 | var paths = require('../config/paths'); 22 | var recursive = require('recursive-readdir'); 23 | var stripAnsi = require('strip-ansi'); 24 | 25 | // Input: /User/dan/app/build/static/js/main.82be8.js 26 | // Output: /static/js/main.js 27 | function removeFileNameHash(fileName) { 28 | return fileName 29 | .replace(paths.appBuild, '') 30 | .replace(/\/?(.*)(\.\w+)(\.js|\.css)/, (match, p1, p2, p3) => p1 + p3); 31 | } 32 | 33 | // Input: 1024, 2048 34 | // Output: "(+1 KB)" 35 | function getDifferenceLabel(currentSize, previousSize) { 36 | var FIFTY_KILOBYTES = 1024 * 50; 37 | var difference = currentSize - previousSize; 38 | var fileSize = !Number.isNaN(difference) ? filesize(difference) : 0; 39 | if (difference >= FIFTY_KILOBYTES) { 40 | return chalk.red('+' + fileSize); 41 | } else if (difference < FIFTY_KILOBYTES && difference > 0) { 42 | return chalk.yellow('+' + fileSize); 43 | } else if (difference < 0) { 44 | return chalk.green(fileSize); 45 | } else { 46 | return ''; 47 | } 48 | } 49 | 50 | // First, read the current file sizes in build directory. 51 | // This lets us display how much they changed later. 52 | recursive(paths.appBuild, (err, fileNames) => { 53 | var previousSizeMap = (fileNames || []) 54 | .filter(fileName => /\.(js|css)$/.test(fileName)) 55 | .reduce((memo, fileName) => { 56 | var contents = fs.readFileSync(fileName); 57 | var key = removeFileNameHash(fileName); 58 | memo[key] = gzipSize(contents); 59 | return memo; 60 | }, {}); 61 | 62 | // Remove all content but keep the directory so that 63 | // if you're in it, you don't end up in Trash 64 | rimrafSync(paths.appBuild + '/*'); 65 | 66 | // Start the webpack build 67 | build(previousSizeMap); 68 | }); 69 | 70 | // Print a detailed summary of build files. 71 | function printFileSizes(stats, previousSizeMap) { 72 | var assets = stats.toJson().assets 73 | .filter(asset => /\.(js|css)$/.test(asset.name)) 74 | .map(asset => { 75 | var fileContents = fs.readFileSync(paths.appBuild + '/' + asset.name); 76 | var size = gzipSize(fileContents); 77 | var previousSize = previousSizeMap[removeFileNameHash(asset.name)]; 78 | var difference = getDifferenceLabel(size, previousSize); 79 | return { 80 | folder: path.join('build', path.dirname(asset.name)), 81 | name: path.basename(asset.name), 82 | size: size, 83 | sizeLabel: filesize(size) + (difference ? ' (' + difference + ')' : '') 84 | }; 85 | }); 86 | assets.sort((a, b) => b.size - a.size); 87 | var longestSizeLabelLength = Math.max.apply(null, 88 | assets.map(a => stripAnsi(a.sizeLabel).length) 89 | ); 90 | assets.forEach(asset => { 91 | var sizeLabel = asset.sizeLabel; 92 | var sizeLength = stripAnsi(sizeLabel).length; 93 | if (sizeLength < longestSizeLabelLength) { 94 | var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength); 95 | sizeLabel += rightPadding; 96 | } 97 | console.log( 98 | ' ' + sizeLabel + 99 | ' ' + chalk.dim(asset.folder + path.sep) + chalk.cyan(asset.name) 100 | ); 101 | }); 102 | } 103 | 104 | // Create the production build and print the deployment instructions. 105 | function build(previousSizeMap) { 106 | console.log('Creating an optimized production build...'); 107 | webpack(config).run((err, stats) => { 108 | if (err) { 109 | console.error('Failed to create a production build. Reason:'); 110 | console.error(err.message || err); 111 | process.exit(1); 112 | } 113 | 114 | console.log(chalk.green('Compiled successfully.')); 115 | console.log(); 116 | 117 | console.log('File sizes after gzip:'); 118 | console.log(); 119 | printFileSizes(stats, previousSizeMap); 120 | console.log(); 121 | 122 | var openCommand = process.platform === 'win32' ? 'start' : 'open'; 123 | var homepagePath = require(paths.appPackageJson).homepage; 124 | var publicPath = config.output.publicPath; 125 | if (homepagePath && homepagePath.indexOf('.github.io/') !== -1) { 126 | // "homepage": "http://user.github.io/project" 127 | console.log('The project was built assuming it is hosted at ' + chalk.green(publicPath) + '.'); 128 | console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.'); 129 | console.log(); 130 | console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); 131 | console.log('To publish it at ' + chalk.green(homepagePath) + ', run:'); 132 | console.log(); 133 | console.log(' ' + chalk.cyan('git') + ' commit -am ' + chalk.yellow('"Save local changes"')); 134 | console.log(' ' + chalk.cyan('git') + ' checkout -B gh-pages'); 135 | console.log(' ' + chalk.cyan('git') + ' add -f build'); 136 | console.log(' ' + chalk.cyan('git') + ' commit -am ' + chalk.yellow('"Rebuild website"')); 137 | console.log(' ' + chalk.cyan('git') + ' filter-branch -f --prune-empty --subdirectory-filter build'); 138 | console.log(' ' + chalk.cyan('git') + ' push -f origin gh-pages'); 139 | console.log(' ' + chalk.cyan('git') + ' checkout -'); 140 | console.log(); 141 | } else if (publicPath !== '/') { 142 | // "homepage": "http://mywebsite.com/project" 143 | console.log('The project was built assuming it is hosted at ' + chalk.green(publicPath) + '.'); 144 | console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.'); 145 | console.log(); 146 | console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); 147 | console.log(); 148 | } else { 149 | // no homepage or "homepage": "http://mywebsite.com" 150 | console.log('The project was built assuming it is hosted at the server root.'); 151 | if (homepagePath) { 152 | // "homepage": "http://mywebsite.com" 153 | console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.'); 154 | console.log(); 155 | } else { 156 | // no homepage 157 | console.log('To override this, specify the ' + chalk.green('homepage') + ' in your ' + chalk.cyan('package.json') + '.'); 158 | console.log('For example, add this to build it for GitHub Pages:') 159 | console.log(); 160 | console.log(' ' + chalk.green('"homepage"') + chalk.cyan(': ') + chalk.green('"http://myname.github.io/myapp"') + chalk.cyan(',')); 161 | console.log(); 162 | } 163 | console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); 164 | console.log('You may also serve it locally with a static server:') 165 | console.log(); 166 | console.log(' ' + chalk.cyan('npm') + ' install -g pushstate-server'); 167 | console.log(' ' + chalk.cyan('pushstate-server') + ' build'); 168 | console.log(' ' + chalk.cyan(openCommand) + ' http://localhost:9000'); 169 | console.log(); 170 | } 171 | }); 172 | } 173 | -------------------------------------------------------------------------------- /config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | var path = require('path'); 11 | var autoprefixer = require('autoprefixer'); 12 | var webpack = require('webpack'); 13 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 14 | var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); 15 | var WatchMissingNodeModulesPlugin = require('../scripts/utils/WatchMissingNodeModulesPlugin'); 16 | var paths = require('./paths'); 17 | var env = require('./env'); 18 | 19 | // This is the development configuration. 20 | // It is focused on developer experience and fast rebuilds. 21 | // The production configuration is different and lives in a separate file. 22 | module.exports = { 23 | // This makes the bundle appear split into separate modules in the devtools. 24 | // We don't use source maps here because they can be confusing: 25 | // https://github.com/facebookincubator/create-react-app/issues/343#issuecomment-237241875 26 | // You may want 'cheap-module-source-map' instead if you prefer source maps. 27 | devtool: 'eval', 28 | // These are the "entry points" to our application. 29 | // This means they will be the "root" imports that are included in JS bundle. 30 | // The first two entry points enable "hot" CSS and auto-refreshes for JS. 31 | entry: [ 32 | // Include WebpackDevServer client. It connects to WebpackDevServer via 33 | // sockets and waits for recompile notifications. When WebpackDevServer 34 | // recompiles, it sends a message to the client by socket. If only CSS 35 | // was changed, the app reload just the CSS. Otherwise, it will refresh. 36 | // The "?/" bit at the end tells the client to look for the socket at 37 | // the root path, i.e. /sockjs-node/. Otherwise visiting a client-side 38 | // route like /todos/42 would make it wrongly request /todos/42/sockjs-node. 39 | // The socket server is a part of WebpackDevServer which we are using. 40 | // The /sockjs-node/ path I'm referring to is hardcoded in WebpackDevServer. 41 | require.resolve('webpack-dev-server/client') + '?/', 42 | // Include Webpack hot module replacement runtime. Webpack is pretty 43 | // low-level so we need to put all the pieces together. The runtime listens 44 | // to the events received by the client above, and applies updates (such as 45 | // new CSS) to the running application. 46 | require.resolve('webpack/hot/dev-server'), 47 | // We ship a few polyfills by default. 48 | require.resolve('./polyfills'), 49 | // Finally, this is your app's code: 50 | path.join(paths.appSrc, 'index') 51 | // We include the app code last so that if there is a runtime error during 52 | // initialization, it doesn't blow up the WebpackDevServer client, and 53 | // changing JS code would still trigger a refresh. 54 | ], 55 | output: { 56 | // Next line is not used in dev but WebpackDevServer crashes without it: 57 | path: paths.appBuild, 58 | // Add /* filename */ comments to generated require()s in the output. 59 | pathinfo: true, 60 | // This does not produce a real file. It's just the virtual path that is 61 | // served by WebpackDevServer in development. This is the JS bundle 62 | // containing code from all our entry points, and the Webpack runtime. 63 | filename: 'static/js/bundle.js', 64 | // In development, we always serve from the root. This makes config easier. 65 | publicPath: '/' 66 | }, 67 | resolve: { 68 | // These are the reasonable defaults supported by the Node ecosystem. 69 | extensions: ['.js', '.json', ''], 70 | alias: { 71 | // This `alias` section can be safely removed after ejection. 72 | // We do this because `babel-runtime` may be inside `react-scripts`, 73 | // so when `babel-plugin-transform-runtime` imports it, it will not be 74 | // available to the app directly. This is a temporary solution that lets 75 | // us ship support for generators. However it is far from ideal, and 76 | // if we don't have a good solution, we should just make `babel-runtime` 77 | // a dependency in generated projects. 78 | // See https://github.com/facebookincubator/create-react-app/issues/255 79 | 'babel-runtime/regenerator': require.resolve('babel-runtime/regenerator'), 80 | 'react-native': 'react-native-web' 81 | } 82 | }, 83 | // Resolve loaders (webpack plugins for CSS, images, transpilation) from the 84 | // directory of `react-scripts` itself rather than the project directory. 85 | // You can remove this after ejecting. 86 | resolveLoader: { 87 | root: paths.ownNodeModules, 88 | moduleTemplates: ['*-loader'] 89 | }, 90 | module: { 91 | // First, run the linter. 92 | // It's important to do this before Babel processes the JS. 93 | preLoaders: [ 94 | { 95 | test: /\.js$/, 96 | loader: 'eslint', 97 | include: paths.appSrc, 98 | } 99 | ], 100 | loaders: [ 101 | // Process JS with Babel. 102 | { 103 | test: /\.js$/, 104 | include: paths.appSrc, 105 | loader: 'babel', 106 | query: require('./babel.dev') 107 | }, 108 | // "postcss" loader applies autoprefixer to our CSS. 109 | // "css" loader resolves paths in CSS and adds assets as dependencies. 110 | // "style" loader turns CSS into JS modules that inject