diff --git a/CHANGELOG.md b/CHANGELOG.md index 04129633274..bbd05b0bc7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,150 @@ +## 0.4.1 (September 3, 2016) + +### Build Dependency (`react-scripts`) + +* We now support (but [don’t recommend](https://github.com/facebookincubator/create-react-app/issues/87#issuecomment-234627904)) `.jsx` file extension. ([@tizmagik](https://github.com/tizmagik) in [#563](https://github.com/facebookincubator/create-react-app/pull/563)) +* Proxy request errors are now printed to the console. ([@cloudmu](https://github.com/cloudmu) in [#502](https://github.com/facebookincubator/create-react-app/pull/502)) + +### Migrating from 0.4.0 to 0.4.1 + +Inside any created project that has not been ejected, run: + +``` +npm install --save-dev --save-exact react-scripts@0.4.1 +``` + +## 0.4.0 (September 2, 2016) + +### Build Dependency (`react-scripts`) + +* **Breaking Change:** Disabled implicit serving of source files in development. ([@gaearon](https://github.com/gaearon) in [#551](https://github.com/facebookincubator/create-react-app/pull/551)) +* You can use `NODE_PATH` environment variable for absolute `import` paths. ([@jimmyhmiller](https://github.com/jimmyhmiller) in [#476](https://github.com/facebookincubator/create-react-app/pull/476)) +* If `src/setupTests.js` exists, it will be used to setup the test environment. ([@gaelduplessix](https://github.com/gaelduplessix) in [#548](https://github.com/facebookincubator/create-react-app/pull/548)) +* If `HTTPS` environment variable is set to `true`, development server will run in HTTPS mode. ([@dceddia](https://github.com/dceddia) in [#552](https://github.com/facebookincubator/create-react-app/pull/552)) + +### Migrating from 0.3.1 to 0.4.0 + +Inside any created project that has not been ejected, run: + +``` +npm install --save-dev --save-exact react-scripts@0.4.0 +``` + +### Breaking Change in 0.4.0 + +Paths like `/src/somefile.png` used to be served in development, but only by accident. They never worked in production builds. Since 0.4.0, we [don’t serve static files by default in development anymore either](https://github.com/facebookincubator/create-react-app/pull/551). This removes a dangerous inconsistency that we never intentionally supported. + +If you need a static file to be part for the build, [import it from JavaScript and you will get its filename](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md#adding-images-and-fonts). This ensures it gets included into the production build as well, and its filename contains the content hash. + +If you used static files with ``, [read this new guide](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md#referring-to-static-assets-from-link-href) on how to make sure these files get included into the builds. For example, you can replace `` with ``, and then Webpack will recognize it and include it into the build. + +If you referenced some other files from `index.html`, please file an issue to discuss your use case. In the meantime, you can serve them from a separate static server until your use case is supported. + +## 0.3.1 (September 2, 2016) + +### Build Dependency (`react-scripts`) + +* Bumps Jest dependency to fix a few issues discovered yesterday. ([@cpojer](https://github.com/cpojer) in [facebook/jest#1580](https://github.com/facebook/jest/pull/1580), [@insin](https://github.com/insin) in [facebook/jest#1574](https://github.com/facebook/jest/pull/1574)) + +### Migrating from 0.3.0 to 0.3.1 + +Inside any created project that has not been ejected, run: + +``` +npm install --save-dev --save-exact react-scripts@0.3.1 +``` + +## 0.3.0 (September 1, 2016) + +### Build Dependency (`react-scripts`) + +* Testing is [now supported](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md#running-tests)! ([Jest project contributors](https://github.com/facebook/jest/pulls?q=is%3Apr+is%3Aclosed), [@cpojer](https://github.com/cpojer) in [#250](https://github.com/facebookincubator/create-react-app/pull/250), [@gaearon](https://github.com/gaearon) in [#378](https://github.com/facebookincubator/create-react-app/pull/378), [#530](https://github.com/facebookincubator/create-react-app/pull/530), [#533](https://github.com/facebookincubator/create-react-app/pull/533)) +* Static files such as CSS, images, and fonts, can now exist outside `src` directory. ([@fson](https://github.com/fson) in [#504](https://github.com/facebookincubator/create-react-app/pull/504)) +* **Breaking Change:** Local paths in `` in `index.html` will now be correctly resolved, so deleting `favicon.ico` is not an error anymore. ([@andreypopp](https://github.com/andreypopp) in [#428](https://github.com/facebookincubator/create-react-app/pull/428)) +* Removed an annoying lint rule that warned for `
this.node = node}>`. ([@mrscobbler](https://github.com/mrscobbler) in [#529](https://github.com/facebookincubator/create-react-app/pull/529)) +* Temporarily disabled `react-constant-elements` Babel transform because of its bugs. ([@gaearon](https://github.com/gaearon) in [#534](https://github.com/facebookincubator/create-react-app/pull/534)) +* Fixed a permission issue with Docker. ([@gaearon](https://github.com/gaearon) in [73c940](https://github.com/facebookincubator/create-react-app/commit/73c940a73205d761230f8d6bf81ecfd460ba28a9)) +* Fixed an issue with generator syntax in Jest that occurred in an alpha release. ([@gaearon](https://github.com/gaearon) in [#535](https://github.com/facebookincubator/create-react-app/pull/535)) + +### Global CLI (`create-react-app`) + +* You can now create a project in a folder that already contains an `.idea` folder, which is necessary for future WebStorm integration. ([@denofevil](https://github.com/denofevil) in [#522](https://github.com/facebookincubator/create-react-app/pull/522)) + +### Migrating from 0.2.3 to 0.3.0 + +You may optionally update the global command (it’s not required): + +``` +npm install -g create-react-app@0.3.0 +``` + +Inside any created project that has not been ejected, run: + +``` +npm install --save-dev --save-exact react-scripts@0.3.0 +``` + +#### Breaking Change + +Now `favicon.ico` is not treated specially anymore. +If you use it, move it to `src` and add the following line to `` in your HTML: + +```html + +``` + +#### New Feature + +Since 0.3.0 added a test runner, we recommend that you add it to the `scripts` section of your `package.json` like this: + +```js + // ... + "scripts": { + // ... + "test": "react-scripts test --env=jsdom" + } +``` + +[Then read the testing guide to learn more about using it!](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md#running-tests) + +## 0.2.3 (August 25, 2016) + +### Build Dependency (`react-scripts`) + +* You can now [proxy requests to an API server](https://github.com/facebookincubator/create-react-app/blob/ef94b0561d5afb9b50b905fa5cd3f94e965c69c0/template/README.md#proxying-api-requests-in-development) without worrying about CORS. ([@gaearon](https://github.com/gaearon) in [#282](https://github.com/facebookincubator/create-react-app/pull/282)) +* You can now [pass custom environment variables](https://github.com/facebookincubator/create-react-app/blob/ef94b0561d5afb9b50b905fa5cd3f94e965c69c0/template/README.md#adding-custom-environment-variables) to your application. ([@eliperelman](https://github.com/eliperelman) in [#342](https://github.com/facebookincubator/create-react-app/pull/342)) +* You can now [use `async` and `await`](https://ponyfoo.com/articles/understanding-javascript-async-await) syntax. ([@gaearon](https://github.com/gaearon) in [#327](https://github.com/facebookincubator/create-react-app/pull/327), [@fson](https://github.com/fson) in [#332](https://github.com/facebookincubator/create-react-app/pull/332)) +* Paths with period in them now load successfully on the development server. ([@mxstbr](https://github.com/mxstbr) in [#422](https://github.com/facebookincubator/create-react-app/pull/422)) +* Images with `.webp` extension are now supported. ([@gafemoyano](https://github.com/gafemoyano) in [#458](https://github.com/facebookincubator/create-react-app/pull/458)) +* The most recent version of React is now added to `package.json`. ([@wdhorton](https://github.com/wdhorton) in [#477](https://github.com/facebookincubator/create-react-app/pull/477)) +* Babel configuration is simplified. ([@kripod](https://github.com/kripod) in [#490](https://github.com/facebookincubator/create-react-app/pull/490)) + +### Migrating from 0.2.2 to 0.2.3 + +Update `react-scripts` to point to `0.2.3` in your `package.json` and run `npm install`. You shouldn’t need to do anything else. + +Newly created projects will use `0.2.3` 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. + +## 0.2.2 (August 22, 2016) + +### Build Dependency (`react-scripts`) + +* When the bundle size changes, we now display the difference after build. ([@elijahmanor](https://github.com/elijahmanor) in [#340](https://github.com/facebookincubator/create-react-app/pull/340)) +* `npm install`ing a missing dependency now forces a rebuild. ([@gaearon](https://github.com/gaearon) in [#349](https://github.com/facebookincubator/create-react-app/pull/349)) +* Autoprefixer config now includes more commonly supported browsers. ([@kripod](https://github.com/kripod) in [#345](https://github.com/facebookincubator/create-react-app/pull/345)) +* All the configuration is now documented inline so ejecting doesn’t leave you in the dark. ([@gaearon](https://github.com/gaearon) in [#362](https://github.com/facebookincubator/create-react-app/pull/362)) +* `Object.assign()` polyfill is now bundled by default. ([@gaearon](https://github.com/gaearon) in [#399](https://github.com/facebookincubator/create-react-app/pull/399)) +* [React Native Web](https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/) now works out of the box. ([@grigio](https://github.com/grigio) in [#407](https://github.com/facebookincubator/create-react-app/pull/407)) +* Same asset filenames in different folders don’t confuse the server now. ([@arunoda](https://github.com/arunoda) in [#446](https://github.com/facebookincubator/create-react-app/pull/446)) +* The `otf` font format is now supported. ([@A-gambit](https://github.com/A-gambit) in [#434](https://github.com/facebookincubator/create-react-app/pull/434)) +* The `new-cap` linting rule has been disabled thanks to feedback from Immutable.js users. ([@rricard](https://github.com/rricard) in [#470](https://github.com/facebookincubator/create-react-app/pull/470)) + +### Migrating from 0.2.1 to 0.2.2 + +Update `react-scripts` to point to `0.2.2` in your `package.json` and run `npm install`. You shouldn’t need to do anything else. + +Newly created projects will use `0.2.2` 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. + ## 0.2.1 (August 1, 2016) ### Build Dependency (`react-scripts`) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 74d2eb8e97e..7eab19b19df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,34 +1,53 @@ -# Contributing to `create-react-app` +# Contributing to Create React App -♥ `create-react-app` and want to get involved? Thanks! There are plenty of ways you can help! +Loving Create React App and want to get involved? Thanks! There are plenty of ways you can help. Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. 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. -## Core ideas +## Core Ideas -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. +As much as possible, we try to avoid adding configuration and flags. The purpose of this tool is to provide the best experience for people getting started with React, and this will always be our first priority. This means that sometimes we [sacrifice additional functionality](https://gettingreal.37signals.com/ch05_Half_Not_Half_Assed.php) (such as server rendering) because it is too hard to solve it in a way that wouldn’t require any configuration. -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. +We prefer **convention, heuristics, or interactivity** over configuration. +Here’s a few examples of them in action. -*These ideas are subject to change at any time* +### Convention + +Instead of letting the user specify the entry filename, we always assume it to be `src/index.js`. Rather than letting the user specify the output bundle name, we generate it, but make sure to include the content hash in it. Whenever possible, we want to leverage convention to make good choices for the user, especially in cases where it’s easy to misconfigure something. + +### Heuristics + +Normally, `npm start` runs on port `3000`, and this is not explicitly configurable. However some environments like cloud IDEs want the programs to run on a specific port to serve their output. We want to play well with different environments, so Create React App reads `PORT` environment variable and prefers it when it is specified. The trick is that we know cloud IDEs already specify it automatically so there is no need for the user to do anything. Create React App relies on heuristics to do the right thing depending on environment. + +Another example of this is how `npm test` normally launches the watcher, but if the `CI` environment variable is set, it will run tests once. We know that popular CI environments set this variable so the user doesn’t need to do anything. It just works. + +### Interactivity + +We prefer to add interactivity to the command line interface rather than add configuration flags. For example, `npm start` will attempt to run with port `3000` by default but it may be busy. Many other tools just fail in this case and ask that you pass a different port, but Create React App will display a prompt asking if you’d like to run the app on the next available port. + +Another example of interactivity is `npm test` watcher interface. Instead of asking people to pass command line flags for switching between test runner modes or search patterns, we print a hint with keys that you can press during the test session to instruct watcher what to do. Jest supports both flags and interactive CLI but Create React App prefers long-running sessions to keep user immersed in the flow over short-running sessions with different flags. + +### Breaking the Rules + +No rules are perfect. Sometimes we may introduce flags or configuration if we believe the value is high enough to justify the mental cost. For example, we know that apps may be hosted paths different from the root, and we need to support this use case. However we still try to fall back to heuristics when possible. In this example, we ask that you specify `homepage` in `package.json`, and infer the correct path based on it. We also nudge the user to fill out the `homepage` after the build so the user becomes aware that the feature exists. ## Submitting a Pull Request -Good pull requests - patches, improvements, new features - are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. +Good pull requests, such as patches, improvements, and new features, are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. -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. +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. -Please also provide a **test plan**, i.e. specify how you verified what you added works. +Please also provide a **test plan**, i.e. specify how you verified that your addition works. -## Setting up a local copy of the repository +## Setting Up a Local Copy 1. Clone the repo with `git clone https://github.com/facebookincubator/create-react-app` 2. Run `npm install` in the root `create-react-app` folder **and** the `create-react-app/global-cli` folder -Once it is done, you can modify any file locally and run `npm start` or `npm run build` just like in a generated project. +Once it is done, you can modify any file locally and run `npm start`, `npm test` or `npm run build` just like in a generated project. If you want to try out the end-to-end flow with the global CLI, you can do this too: @@ -39,4 +58,21 @@ cd my-app and then run `npm start` or `npm run build`. +## Cutting a Release + +1. Tag all merged PRs that go into the release with the relevant milestone. +2. Close the milestone. +3. In most releases, only `react-scripts` needs to be released. If you don’t have any changes to the `global-cli` folder, you don’t need to bump its version or publish it. +4. Note that files in `global-cli` should be modified with extreme caution. Since it’s a global CLI, any version of `create-react-app` (global CLI) including very old ones should work with the latest version of `react-scripts`. +5. Add an entry to `CHANGELOG.md` detailing what has changed with links to PRs and their authors. Use previous entries for inspiration. Group changes to `react-scripts` and `create-react-app` separately in the notes, for example like in `0.2.0` release notes. +6. Make sure to include “Migrating from ...” instructions for the previous release. Often you can copy and paste them. +7. After merging the changelog update, create a GitHub Release with the same text. See previous Releases for inspiration. +8. If you are releasing updates to the `create-react-app` CLI (likely not), go to `global-cli`, bump the version in `package.json` and run `npm publish` in that folder. +9. If you are releasing updates to `react-scripts` (most likely!), bump the version in `package.json`. **Do not run `npm publish`. Instead, run `sh tasks/release.sh`.** +10. Wait for a long time, and it will get published. Don’t worry that it’s stuck. It will bundle dependencies into a single tarball before publishing for faster installs. + +Make sure to test the released version! If you want to be extra careful, you can publish a prerelease by running `sh tasks/release.sh --tag next` instead of `sh tasks/release.sh`. + +------------ + *Many thanks to [h5bp](https://github.com/h5bp/html5-boilerplate/blob/master/CONTRIBUTING.md) for the inspiration with this contributing guide* diff --git a/README.md b/README.md index aac5d0b0f18..0541db4b8d5 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ Create React apps with no build configuration. +* [Getting Started](#getting-started) – How to create a new app. +* [User Guide](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md) – How to develop apps bootstrapped with Create React App. + ## tl;dr ```sh @@ -55,6 +58,7 @@ my-app/ src/ App.css App.js + App.test.js index.css index.js logo.svg @@ -73,6 +77,13 @@ You will see the build errors and lint warnings in the console. Build errors +### `npm test` + +Runs the test watcher in an interactive mode. +By default, runs tests related to files changes since the last commit. + +[Read more about testing.](template/README.md#running-tests) + ### `npm run build` Builds the app for production to the `build` folder.
@@ -81,7 +92,7 @@ It correctly bundles React in production mode and optimizes the build for the be The build is minified and the filenames include the hashes.
Your app is ready to be deployed! -## How Do I…? +## User Guide The generated project will include a guide in its README.
You can also read its latest version [here](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md). @@ -105,7 +116,7 @@ You can also read its latest version [here](https://github.com/facebookincubator * Autoprefixed CSS, so you don’t need `-webkit` or other prefixes. * A `build` script to bundle JS, CSS, and images for production, with sourcemaps. -**The feature set is intentionally limited**. It doesn’t support advanced features such as server rendering or CSS modules. Currently, it doesn’t support testing either. The tool is also **non-configurable** because it is hard to provide a cohesive experience and easy updates across a set of tools when the user can tweak anything. +**The feature set is intentionally limited**. It doesn’t support advanced features such as server rendering or CSS modules. The tool is also **non-configurable** because it is hard to provide a cohesive experience and easy updates across a set of tools when the user can tweak anything. **You don’t have to use this.** Historically it has been easy to [gradually adopt](https://www.youtube.com/watch?v=BF58ZJ1ZQxY) React. However many people create new single-page React apps from scratch every day. We’ve heard [loud](https://medium.com/@ericclemmons/javascript-fatigue-48d4011b6fc4) and [clear](https://twitter.com/thomasfuchs/status/708675139253174273) that this process can be error-prone and tedious, especially if this is your first JavaScript build stack. This project is an attempt to figure out a good way to start developing React apps. @@ -124,7 +135,6 @@ You don’t have to ever use `eject`. The curated feature set is suitable for sm Some features are currently **not supported**: * Server rendering. -* Testing. * Some experimental syntax extensions (e.g. decorators). * CSS Modules. * LESS or Sass. @@ -141,7 +151,8 @@ Currently it is a thin layer on top of many amazing community projects, such as: * [Babel](http://babeljs.io/) with ES6 and extensions used by Facebook (JSX, [object spread](https://github.com/sebmarkbage/ecmascript-rest-spread/commits/master), [class properties](https://github.com/jeffmo/es-class-public-fields)) * [Autoprefixer](https://github.com/postcss/autoprefixer) * [ESLint](http://eslint.org/) -* and more. +* [Jest](http://facebook.github.io/jest) +* and others. All of them are transitive dependencies of the provided npm package. @@ -174,6 +185,7 @@ If you don’t agree with the choices made in this project, you might want to ex * [react-app](https://github.com/kriasoft/react-app) * [dev-toolkit](https://github.com/stoikerty/dev-toolkit) * [mozilla-neo](https://github.com/mozilla/neo) +* [tarec](https://github.com/geowarin/tarec) You can also use module bundlers like [webpack](http://webpack.github.io) and [Browserify](http://browserify.org/) directly.
React documentation includes [a walkthrough](https://facebook.github.io/react/docs/package-management.html) on this topic. diff --git a/bin/react-scripts.js b/bin/react-scripts.js old mode 100644 new mode 100755 diff --git a/config/babel.dev.js b/config/babel.dev.js index 89096734713..ee7d4fdf6db 100644 --- a/config/babel.dev.js +++ b/config/babel.dev.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,37 +7,42 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end + +var path = require('path'); +var findCacheDir = require('find-cache-dir'); module.exports = { // Don't try to find .babelrc because we want to force this configuration. babelrc: false, // This is a feature of `babel-loader` for webpack (not Babel itself). - // It enables caching results in OS temporary directory for faster rebuilds. - cacheDirectory: true, + // It enables caching results in ./node_modules/.cache/react-scripts/ + // directory for faster rebuilds. + cacheDirectory: findCacheDir({ name: 'react-scripts' }), presets: [ - // let, const, destructuring, classes, modules - require.resolve('babel-preset-es2015'), - // exponentiation - require.resolve('babel-preset-es2016'), + // Latest stable ECMAScript features + require.resolve('babel-preset-latest'), // JSX, Flow require.resolve('babel-preset-react') ], plugins: [ - // function x(a, b, c,) { } - require.resolve('babel-plugin-syntax-trailing-function-commas'), - // await fetch() - require.resolve('babel-plugin-syntax-async-functions'), // class { handleClick = () => { } } require.resolve('babel-plugin-transform-class-properties'), // { ...todo, completed: true } require.resolve('babel-plugin-transform-object-rest-spread'), // function* () { yield 42; yield 43; } - require.resolve('babel-plugin-transform-regenerator'), + [require.resolve('babel-plugin-transform-regenerator'), { + // Async functions are converted to generators by babel-preset-latest + async: false + }], // Polyfills the runtime needed for async/await and generators [require.resolve('babel-plugin-transform-runtime'), { helpers: false, polyfill: false, - regenerator: true + regenerator: true, + // Resolve the Babel runtime relative to the config. + // You can safely remove this after ejecting: + moduleName: path.dirname(require.resolve('babel-runtime/package')) }] ] }; diff --git a/config/babel.prod.js b/config/babel.prod.js index 92491bfcacb..f53094ababd 100644 --- a/config/babel.prod.js +++ b/config/babel.prod.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,36 +7,43 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end + +var path = require('path'); module.exports = { // Don't try to find .babelrc because we want to force this configuration. babelrc: false, presets: [ - // let, const, destructuring, classes, modules - require.resolve('babel-preset-es2015'), - // exponentiation - require.resolve('babel-preset-es2016'), + // Latest stable ECMAScript features + require.resolve('babel-preset-latest'), // JSX, Flow require.resolve('babel-preset-react') ], plugins: [ - // function x(a, b, c,) { } - require.resolve('babel-plugin-syntax-trailing-function-commas'), - // await fetch() - require.resolve('babel-plugin-syntax-async-functions'), // class { handleClick = () => { } } require.resolve('babel-plugin-transform-class-properties'), // { ...todo, completed: true } require.resolve('babel-plugin-transform-object-rest-spread'), // function* () { yield 42; yield 43; } - require.resolve('babel-plugin-transform-regenerator'), + [require.resolve('babel-plugin-transform-regenerator'), { + // Async functions are converted to generators by babel-preset-latest + async: false + }], // Polyfills the runtime needed for async/await and generators [require.resolve('babel-plugin-transform-runtime'), { helpers: false, polyfill: false, - regenerator: true + regenerator: true, + // Resolve the Babel runtime relative to the config. + // You can safely remove this after ejecting: + moduleName: path.dirname(require.resolve('babel-runtime/package')) }], // Optimization: hoist JSX that never changes out of render() - require.resolve('babel-plugin-transform-react-constant-elements') + // Disabled because of issues: + // * https://github.com/facebookincubator/create-react-app/issues/525 + // * https://phabricator.babeljs.io/search/query/pCNlnC2xzwzx/ + // TODO: Enable again when these issues are resolved. + // require.resolve('babel-plugin-transform-react-constant-elements') ] }; diff --git a/config/env.js b/config/env.js index cfa10c75b44..66acf119b84 100644 --- a/config/env.js +++ b/config/env.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,6 +7,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be // injected into the application via DefinePlugin in Webpack configuration. diff --git a/config/eslint.js b/config/eslint.js index 513ad2de02f..9c77d1f7b39 100644 --- a/config/eslint.js +++ b/config/eslint.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,6 +7,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end // Inspired by https://github.com/airbnb/javascript but less opinionated. @@ -21,7 +23,7 @@ module.exports = { parser: 'babel-eslint', - // import plugin is termporarily disabled, scroll below to see why + // import plugin is temporarily disabled, scroll below to see why plugins: [/*'import', */'flowtype', 'jsx-a11y', 'react'], env: { @@ -45,7 +47,7 @@ module.exports = { settings: { 'import/ignore': [ 'node_modules', - '\\.(json|css|jpg|png|gif|eot|svg|ttf|woff|woff2|mp4|webm)$', + '\\.(json|css|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm)$', ], 'import/extensions': ['.js'], 'import/resolver': { @@ -62,7 +64,6 @@ module.exports = { 'dot-location': ['warn', 'property'], eqeqeq: ['warn', 'allow-null'], 'guard-for-in': 'warn', - 'new-cap': ['warn', { newIsCap: true }], 'new-parens': 'warn', 'no-array-constructor': 'warn', 'no-caller': 'warn', @@ -116,13 +117,13 @@ module.exports = { 'LabeledStatement', 'WithStatement', ], - 'no-return-assign': 'warn', 'no-script-url': 'warn', 'no-self-assign': 'warn', 'no-self-compare': 'warn', 'no-sequences': 'warn', 'no-shadow-restricted-names': 'warn', 'no-sparse-arrays': 'warn', + 'no-template-curly-in-string': 'warn', 'no-this-before-super': 'warn', 'no-throw-literal': 'warn', 'no-undef': 'warn', diff --git a/config/jest/CSSStub.js b/config/jest/CSSStub.js index 05fb9d0d70f..05810269ac6 100644 --- a/config/jest/CSSStub.js +++ b/config/jest/CSSStub.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * @@ -7,5 +8,6 @@ * * @flow */ +// @remove-on-eject-end module.exports = {}; diff --git a/config/jest/FileStub.js b/config/jest/FileStub.js index 96d28629fe6..c95c3e790a1 100644 --- a/config/jest/FileStub.js +++ b/config/jest/FileStub.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * @@ -7,5 +8,6 @@ * * @flow */ +// @remove-on-eject-end module.exports = "test-file-stub"; diff --git a/config/jest/transform.js b/config/jest/transform.js index 9f51b1a8558..3a085e93e65 100644 --- a/config/jest/transform.js +++ b/config/jest/transform.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * @@ -5,6 +6,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end const babelDev = require('../babel.dev'); const babelJest = require('babel-jest'); diff --git a/config/paths.js b/config/paths.js index 7645917fbc9..9fbb4ecbc56 100644 --- a/config/paths.js +++ b/config/paths.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,63 +7,70 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ - -// TODO: we can split this file into several files (pre-eject, post-eject, test) -// and use those instead. This way we don't need to branch here. +// @remove-on-eject-end var path = require('path'); -// True after ejecting, false when used as a dependency -var isEjected = ( - path.resolve(path.join(__dirname, '..')) === - path.resolve(process.cwd()) -); +// We support resolving modules according to `NODE_PATH`. +// This lets you use absolute paths in imports inside large monorepos: +// https://github.com/facebookincubator/create-react-app/issues/253. -// Are we developing create-react-app locally? -var isInCreateReactAppSource = ( - process.argv.some(arg => arg.indexOf('--debug-template') > -1) -); +// It works similar to `NODE_PATH` in Node itself: +// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders -function resolveOwn(relativePath) { - return path.resolve(__dirname, relativePath); -} +// We will export `nodePaths` as an array of absolute paths. +// It will then be used by Webpack configs. +// Jest doesn’t need this because it already handles `NODE_PATH` out of the box. + +var nodePaths = (process.env.NODE_PATH || '') + .split(process.platform === 'win32' ? ';' : ':') + .filter(Boolean) + .map(p => path.resolve(p)); function resolveApp(relativePath) { return path.resolve(relativePath); } -if (isInCreateReactAppSource) { - // create-react-app development: we're in ./config/ - module.exports = { - appBuild: resolveOwn('../build'), - appHtml: resolveOwn('../template/index.html'), - appFavicon: resolveOwn('../template/favicon.ico'), - appPackageJson: resolveOwn('../package.json'), - appSrc: resolveOwn('../template/src'), - appNodeModules: resolveOwn('../node_modules'), - ownNodeModules: resolveOwn('../node_modules') - }; -} else if (!isEjected) { - // before eject: we're in ./node_modules/react-scripts/config/ - module.exports = { - appBuild: resolveApp('build'), - appHtml: resolveApp('index.html'), - appFavicon: resolveApp('favicon.ico'), - appPackageJson: resolveApp('package.json'), - appSrc: resolveApp('src'), - appNodeModules: resolveApp('node_modules'), - // this is empty with npm3 but node resolution searches higher anyway: - ownNodeModules: resolveOwn('../node_modules') - }; -} else { - // after eject: we're in ./config/ - module.exports = { - appBuild: resolveApp('build'), - appHtml: resolveApp('index.html'), - appFavicon: resolveApp('favicon.ico'), - appPackageJson: resolveApp('package.json'), - appSrc: resolveApp('src'), - appNodeModules: resolveApp('node_modules'), - ownNodeModules: resolveApp('node_modules') - }; +// config after eject: we're in ./config/ +module.exports = { + appBuild: resolveApp('build'), + appHtml: resolveApp('index.html'), + appPackageJson: resolveApp('package.json'), + appSrc: resolveApp('src'), + testsSetup: resolveApp('src/setupTests.js'), + appNodeModules: resolveApp('node_modules'), + ownNodeModules: resolveApp('node_modules'), + nodePaths: nodePaths +}; + +// @remove-on-eject-begin +function resolveOwn(relativePath) { + return path.resolve(__dirname, relativePath); } + +// config before eject: we're in ./node_modules/react-scripts/config/ +module.exports = { + appBuild: resolveApp('build'), + appHtml: resolveApp('index.html'), + appPackageJson: resolveApp('package.json'), + appSrc: resolveApp('src'), + testsSetup: resolveApp('src/setupTests.js'), + appNodeModules: resolveApp('node_modules'), + // this is empty with npm3 but node resolution searches higher anyway: + ownNodeModules: resolveOwn('../node_modules'), + nodePaths: nodePaths +}; +// @remove-on-eject-end + +// @remove-on-publish-begin +module.exports = { + appBuild: resolveOwn('../build'), + appHtml: resolveOwn('../template/index.html'), + appPackageJson: resolveOwn('../package.json'), + appSrc: resolveOwn('../template/src'), + testsSetup: resolveOwn('../template/src/setupTests.js'), + appNodeModules: resolveOwn('../node_modules'), + ownNodeModules: resolveOwn('../node_modules'), + nodePaths: nodePaths +}; +// @remove-on-publish-end diff --git a/config/polyfills.js b/config/polyfills.js index 1f71e4ac4f2..a1353ca3d2d 100644 --- a/config/polyfills.js +++ b/config/polyfills.js @@ -1,3 +1,14 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +// @remove-on-eject-end + if (typeof Promise === 'undefined') { // Rejection tracking prevents a common issue where React gets into an // inconsistent state due to an error, but it gets swallowed by a Promise, @@ -8,3 +19,7 @@ if (typeof Promise === 'undefined') { // fetch() polyfill for making API calls. require('whatwg-fetch'); + +// Object.assign() is commonly used with React. +// It will use the native implementation if it's present and isn't buggy. +Object.assign = require('object-assign'); diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index a3db11f8ec7..34bda5590a3 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,6 +7,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end var path = require('path'); var autoprefixer = require('autoprefixer'); @@ -65,18 +67,21 @@ module.exports = { publicPath: '/' }, resolve: { + // This allows you to set a fallback for where Webpack should look for modules. + // We read `NODE_PATH` environment variable in `paths.js` and pass paths here. + // We use `fallback` instead of `root` because we want `node_modules` to "win" + // if there any conflicts. This matches Node resolution mechanism. + // https://github.com/facebookincubator/create-react-app/issues/253 + fallback: paths.nodePaths, // These are the reasonable defaults supported by the Node ecosystem. - extensions: ['.js', '.json', ''], + // We also include JSX as a common component filename extension to support + // some tools, although we do not recommend using it, see: + // https://github.com/facebookincubator/create-react-app/issues/290 + extensions: ['.js', '.json', '.jsx', ''], alias: { - // This `alias` section can be safely removed after ejection. - // We do this because `babel-runtime` may be inside `react-scripts`, - // so when `babel-plugin-transform-runtime` imports it, it will not be - // available to the app directly. This is a temporary solution that lets - // us ship support for generators. However it is far from ideal, and - // if we don't have a good solution, we should just make `babel-runtime` - // a dependency in generated projects. - // See https://github.com/facebookincubator/create-react-app/issues/255 - 'babel-runtime/regenerator': require.resolve('babel-runtime/regenerator') + // Support React Native Web + // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ + 'react-native': 'react-native-web' } }, // Resolve loaders (webpack plugins for CSS, images, transpilation) from the @@ -91,7 +96,7 @@ module.exports = { // It's important to do this before Babel processes the JS. preLoaders: [ { - test: /\.js$/, + test: /\.(js|jsx)$/, loader: 'eslint', include: paths.appSrc, } @@ -99,7 +104,7 @@ module.exports = { loaders: [ // Process JS with Babel. { - test: /\.js$/, + test: /\.(js|jsx)$/, include: paths.appSrc, loader: 'babel', query: require('./babel.dev') @@ -111,36 +116,51 @@ module.exports = { // in development "style" loader enables hot editing of CSS. { test: /\.css$/, - include: [paths.appSrc, paths.appNodeModules], loader: 'style!css!postcss' }, // JSON is not enabled by default in Webpack but both Node and Browserify // allow it implicitly so we also enable it. { test: /\.json$/, - include: [paths.appSrc, paths.appNodeModules], loader: 'json' }, // "file" loader makes sure those assets get served by WebpackDevServer. // When you `import` an asset, you get its (virtual) filename. // In production, they would get copied to the `build` folder. { - test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, - include: [paths.appSrc, paths.appNodeModules], + test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/, + exclude: /\/favicon.ico$/, loader: 'file', query: { - name: 'static/media/[name].[ext]' + name: 'static/media/[name].[hash:8].[ext]' + } + }, + // A special case for favicon.ico to place it into build root directory. + { + test: /\/favicon.ico$/, + include: [paths.appSrc], + loader: 'file', + query: { + name: 'favicon.ico?[hash:8]' } }, // "url" loader works just like "file" loader but it also embeds // assets smaller than specified size as data URLs to avoid requests. { test: /\.(mp4|webm)(\?.*)?$/, - include: [paths.appSrc, paths.appNodeModules], loader: 'url', query: { limit: 10000, - name: 'static/media/[name].[ext]' + name: 'static/media/[name].[hash:8].[ext]' + } + }, + // "html" loader is used to process template page (index.html) to resolve + // resources linked with HTML tags. + { + test: /\.html$/, + loader: 'html', + query: { + attrs: ['link:href'], } } ] @@ -168,7 +188,6 @@ module.exports = { new HtmlWebpackPlugin({ inject: true, template: paths.appHtml, - favicon: paths.appFavicon, }), // Makes some environment variables available to the JS code, for example: // if (process.env.NODE_ENV === 'development') { ... }. See `env.js`. diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index dbac03f1aaf..c03b6ef272f 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,6 +7,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end var path = require('path'); var autoprefixer = require('autoprefixer'); @@ -60,18 +62,21 @@ module.exports = { publicPath: publicPath }, resolve: { + // This allows you to set a fallback for where Webpack should look for modules. + // We read `NODE_PATH` environment variable in `paths.js` and pass paths here. + // We use `fallback` instead of `root` because we want `node_modules` to "win" + // if there any conflicts. This matches Node resolution mechanism. + // https://github.com/facebookincubator/create-react-app/issues/253 + fallback: paths.nodePaths, // These are the reasonable defaults supported by the Node ecosystem. - extensions: ['.js', '.json', ''], + // We also include JSX as a common component filename extension to support + // some tools, although we do not recommend using it, see: + // https://github.com/facebookincubator/create-react-app/issues/290 + extensions: ['.js', '.json', '.jsx', ''], alias: { - // This `alias` section can be safely removed after ejection. - // We do this because `babel-runtime` may be inside `react-scripts`, - // so when `babel-plugin-transform-runtime` imports it, it will not be - // available to the app directly. This is a temporary solution that lets - // us ship support for generators. However it is far from ideal, and - // if we don't have a good solution, we should just make `babel-runtime` - // a dependency in generated projects. - // See https://github.com/facebookincubator/create-react-app/issues/255 - 'babel-runtime/regenerator': require.resolve('babel-runtime/regenerator') + // Support React Native Web + // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ + 'react-native': 'react-native-web' } }, // Resolve loaders (webpack plugins for CSS, images, transpilation) from the @@ -86,7 +91,7 @@ module.exports = { // It's important to do this before Babel processes the JS. preLoaders: [ { - test: /\.js$/, + test: /\.(js|jsx)$/, loader: 'eslint', include: paths.appSrc } @@ -94,7 +99,7 @@ module.exports = { loaders: [ // Process JS with Babel. { - test: /\.js$/, + test: /\.(js|jsx)$/, include: paths.appSrc, loader: 'babel', query: require('./babel.prod') @@ -113,40 +118,60 @@ module.exports = { // in the main CSS file. { test: /\.css$/, - include: [paths.appSrc, paths.appNodeModules], // "?-autoprefixer" disables autoprefixer in css-loader itself: // https://github.com/webpack/css-loader/issues/281 - // We already have it thanks to postcss. + // We already have it thanks to postcss. We only pass this flag in + // production because "css" loader only enables autoprefixer-powered + // removal of unnecessary prefixes when Uglify plugin is enabled. + // Webpack 1.x uses Uglify plugin as a signal to minify *all* the assets + // including CSS. This is confusing and will be removed in Webpack 2: + // https://github.com/webpack/webpack/issues/283 loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss') // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, + // JSON is not enabled by default in Webpack but both Node and Browserify + // allow it implicitly so we also enable it. { - // JSON is not enabled by default in Webpack but both Node and Browserify - // allow it implicitly so we also enable it. test: /\.json$/, - include: [paths.appSrc, paths.appNodeModules], loader: 'json' }, + // "file" loader makes sure those assets end up in the `build` folder. + // When you `import` an asset, you get its filename. { - // "file" loader makes sure those assets end up in the `build` folder. - // When you `import` an asset, you get its filename. - test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, - include: [paths.appSrc, paths.appNodeModules], + test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/, + exclude: /\/favicon.ico$/, loader: 'file', query: { name: 'static/media/[name].[hash:8].[ext]' } }, + // A special case for favicon.ico to place it into build root directory. + { + test: /\/favicon.ico$/, + include: [paths.appSrc], + loader: 'file', + query: { + name: 'favicon.ico?[hash:8]' + } + }, // "url" loader works just like "file" loader but it also embeds // assets smaller than specified size as data URLs to avoid requests. { test: /\.(mp4|webm)(\?.*)?$/, - include: [paths.appSrc, paths.appNodeModules], loader: 'url', query: { limit: 10000, name: 'static/media/[name].[hash:8].[ext]' } + }, + // "html" loader is used to process template page (index.html) to resolve + // resources linked with HTML tags. + { + test: /\.html$/, + loader: 'html', + query: { + attrs: ['link:href'], + } } ] }, @@ -175,7 +200,6 @@ module.exports = { new HtmlWebpackPlugin({ inject: true, template: paths.appHtml, - favicon: paths.appFavicon, minify: { removeComments: true, collapseWhitespace: true, diff --git a/global-cli/index.js b/global-cli/index.js index d1319aba06f..3c646e37e31 100644 --- a/global-cli/index.js +++ b/global-cli/index.js @@ -41,6 +41,7 @@ var spawn = require('cross-spawn'); var chalk = require('chalk'); var semver = require('semver'); var argv = require('minimist')(process.argv.slice(2)); +var pathExists = require('path-exists'); /** * Arguments: @@ -50,7 +51,7 @@ var argv = require('minimist')(process.argv.slice(2)); * Example of valid values: * - a specific npm version: "0.22.0-rc1" * - a .tgz archive from any npm repo: "https://registry.npmjs.org/react-scripts/-/react-scripts-0.20.0.tgz" - * - a package prepared with `npm pack`: "/Users/home/vjeux/create-react-app/react-scripts-0.22.0.tgz" + * - a package prepared with `tasks/clean_pack.sh`: "/Users/home/vjeux/create-react-app/react-scripts-0.22.0.tgz" */ var commands = argv._; if (commands.length === 0) { @@ -67,24 +68,23 @@ if (commands.length === 0) { createApp(commands[0], argv.verbose, argv['scripts-version']); function createApp(name, verbose, version) { - if (fs.existsSync(name)) { - console.log('The directory `' + name + '` already exists. Aborting.'); + var root = path.resolve(name); + if (!pathExists.sync(name)) { + fs.mkdirSync(root); + } else if (!isSafeToCreateProjectIn(root)) { + console.log('The directory `' + name + '` contains file(s) that could conflict. Aborting.'); process.exit(1); } - var root = path.resolve(name); var appName = path.basename(root); - console.log( 'Creating a new React app in ' + root + '.' ); console.log(); - fs.mkdirSync(root); - var packageJson = { name: appName, - version: '0.0.1', + version: '0.1.0', private: true, }; fs.writeFileSync( @@ -166,3 +166,16 @@ function checkNodeVersion() { process.exit(1); } } + +// If project only contains files generated by GH, it’s safe. +// We also special case IJ-based products .idea because it integrates with CRA: +// https://github.com/facebookincubator/create-react-app/pull/368#issuecomment-243446094 +function isSafeToCreateProjectIn(root) { + var validFiles = [ + '.DS_Store', 'Thumbs.db', '.git', '.gitignore', '.idea', 'README.md', 'LICENSE' + ]; + return fs.readdirSync(root) + .every(function(file) { + return validFiles.indexOf(file) >= 0; + }); +} diff --git a/global-cli/package.json b/global-cli/package.json index 3e98c4c939a..cd4008feff9 100644 --- a/global-cli/package.json +++ b/global-cli/package.json @@ -1,12 +1,15 @@ { "name": "create-react-app", - "version": "0.2.0", + "version": "0.3.0", "keywords": [ "react" ], "description": "Create React apps with no build configuration.", "repository": "facebookincubator/create-react-app", "license": "BSD-3-Clause", + "engines": { + "node": ">=4" + }, "bugs": { "url": "https://github.com/facebookincubator/create-react-app/issues" }, @@ -20,6 +23,7 @@ "chalk": "^1.1.1", "cross-spawn": "^4.0.0", "minimist": "^1.2.0", + "path-exists": "^3.0.0", "semver": "^5.0.3" } } diff --git a/npm-debug.log b/npm-debug.log new file mode 100644 index 00000000000..8a04fe28be2 --- /dev/null +++ b/npm-debug.log @@ -0,0 +1,45 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'start' ] +2 info using npm@3.10.3 +3 info using node@v6.3.1 +4 verbose run-script [ 'prestart', 'start', 'poststart' ] +5 info lifecycle react-scripts@0.3.0-alpha~prestart: react-scripts@0.3.0-alpha +6 silly lifecycle react-scripts@0.3.0-alpha~prestart: no script for prestart, continuing +7 info lifecycle react-scripts@0.3.0-alpha~start: react-scripts@0.3.0-alpha +8 verbose lifecycle react-scripts@0.3.0-alpha~start: unsafe-perm in lifecycle true +9 verbose lifecycle react-scripts@0.3.0-alpha~start: PATH: /usr/local/lib/node_modules/npm/bin/node-gyp-bin:/Users/newton/Science/create-react-app/node_modules/.bin:/usr/local/bin:.git/safe/../../bin:/Users/newton/.rbenv/shims:/Users/newton/.bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin +10 verbose lifecycle react-scripts@0.3.0-alpha~start: CWD: /Users/newton/Science/create-react-app +11 silly lifecycle react-scripts@0.3.0-alpha~start: Args: [ '-c', 'node scripts/start.js --debug-template' ] +12 silly lifecycle react-scripts@0.3.0-alpha~start: Returned: code: 1 signal: null +13 info lifecycle react-scripts@0.3.0-alpha~start: Failed to exec start script +14 verbose stack Error: react-scripts@0.3.0-alpha start: `node scripts/start.js --debug-template` +14 verbose stack Exit status 1 +14 verbose stack at EventEmitter. (/usr/local/lib/node_modules/npm/lib/utils/lifecycle.js:242:16) +14 verbose stack at emitTwo (events.js:106:13) +14 verbose stack at EventEmitter.emit (events.js:191:7) +14 verbose stack at ChildProcess. (/usr/local/lib/node_modules/npm/lib/utils/spawn.js:40:14) +14 verbose stack at emitTwo (events.js:106:13) +14 verbose stack at ChildProcess.emit (events.js:191:7) +14 verbose stack at maybeClose (internal/child_process.js:852:16) +14 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:215:5) +15 verbose pkgid react-scripts@0.3.0-alpha +16 verbose cwd /Users/newton/Science/create-react-app +17 error Darwin 15.6.0 +18 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "start" +19 error node v6.3.1 +20 error npm v3.10.3 +21 error code ELIFECYCLE +22 error react-scripts@0.3.0-alpha start: `node scripts/start.js --debug-template` +22 error Exit status 1 +23 error Failed at the react-scripts@0.3.0-alpha start script 'node scripts/start.js --debug-template'. +23 error Make sure you have the latest version of node.js and npm installed. +23 error If you do, this is most likely a problem with the react-scripts package, +23 error not with npm itself. +23 error Tell the author that this fails on your system: +23 error node scripts/start.js --debug-template +23 error You can get information on how to open an issue for this project with: +23 error npm bugs react-scripts +23 error Or if that isn't available, you can get their info via: +23 error npm owner ls react-scripts +23 error There is likely additional logging output above. +24 verbose exit [ 1, true ] diff --git a/package.json b/package.json index bf3d853af2a..631b9618de8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-scripts", - "version": "0.3.0-alpha", + "version": "0.4.1", "description": "Configuration and scripts for Create React App.", "repository": "facebookincubator/create-react-app", "license": "BSD-3-Clause", @@ -11,11 +11,11 @@ "url": "https://github.com/facebookincubator/create-react-app/issues" }, "scripts": { - "build": "node scripts/build.js --debug-template", - "create-react-app": "node global-cli/index.js --scripts-version \"$PWD/`npm pack`\"", + "build": "node scripts/build.js", + "create-react-app": "tasks/cra.sh", "e2e": "tasks/e2e.sh", - "start": "node scripts/start.js --debug-template", - "test": "node scripts/test.js --debug-template" + "start": "node scripts/start.js", + "test": "node scripts/test.js --env=jsdom" }, "files": [ "PATENTS", @@ -29,59 +29,59 @@ }, "dependencies": { "autoprefixer": "6.4.0", - "babel-core": "6.11.4", + "babel-core": "6.14.0", "babel-eslint": "6.1.2", - "babel-jest": "14.1.0", - "babel-loader": "6.2.4", - "babel-plugin-syntax-async-functions": "6.8.0", - "babel-plugin-syntax-trailing-function-commas": "6.8.0", + "babel-jest": "15.0.0", + "babel-loader": "6.2.5", "babel-plugin-transform-class-properties": "6.11.5", "babel-plugin-transform-object-rest-spread": "6.8.0", "babel-plugin-transform-react-constant-elements": "6.9.1", - "babel-plugin-transform-regenerator": "6.11.4", - "babel-plugin-transform-runtime": "6.12.0", - "babel-preset-es2015": "6.9.0", - "babel-preset-es2016": "6.11.3", + "babel-plugin-transform-regenerator": "6.14.0", + "babel-plugin-transform-runtime": "6.15.0", + "babel-preset-latest": "6.14.0", "babel-preset-react": "6.11.1", "babel-runtime": "6.11.6", - "case-sensitive-paths-webpack-plugin": "1.1.2", + "case-sensitive-paths-webpack-plugin": "1.1.4", "chalk": "1.1.3", - "connect-history-api-fallback": "1.2.0", + "connect-history-api-fallback": "1.3.0", "cross-spawn": "4.0.0", - "css-loader": "0.23.1", + "css-loader": "0.24.0", "detect-port": "1.0.0", - "eslint": "3.2.2", - "eslint-loader": "1.4.1", - "eslint-plugin-flowtype": "2.4.0", + "eslint": "3.4.0", + "eslint-loader": "1.5.0", + "eslint-plugin-flowtype": "2.11.4", "eslint-plugin-import": "1.12.0", - "eslint-plugin-jsx-a11y": "2.0.1", + "eslint-plugin-jsx-a11y": "2.2.1", "eslint-plugin-react": "5.2.2", "extract-text-webpack-plugin": "1.0.1", "file-loader": "0.9.0", "filesize": "3.3.0", + "find-cache-dir": "^0.1.1", "fs-extra": "0.30.0", "gzip-size": "3.0.0", + "html-loader": "0.4.3", "html-webpack-plugin": "2.22.0", - "http-proxy-middleware": "0.17.0", - "jest": "14.1.0", + "http-proxy-middleware": "0.17.1", + "jest": "15.1.1", "json-loader": "0.5.4", + "object-assign": "4.1.0", "opn": "4.0.2", - "postcss-loader": "0.9.1", + "path-exists": "3.0.0", + "postcss-loader": "0.11.1", "promise": "7.1.1", "recursive-readdir": "2.0.0", "rimraf": "2.5.4", "strip-ansi": "3.0.1", "style-loader": "0.13.1", "url-loader": "0.5.7", - "webpack": "1.13.1", - "webpack-dev-server": "1.14.1", + "webpack": "1.13.2", + "webpack-dev-server": "1.15.1", "whatwg-fetch": "1.0.0" }, "devDependencies": { "bundle-deps": "1.0.0", "react": "^15.3.0", - "react-dom": "^15.3.0", - "react-test-renderer": "^15.3.0" + "react-dom": "^15.3.0" }, "optionalDependencies": { "fsevents": "1.0.14" diff --git a/scripts/build.js b/scripts/build.js index 1f3079f2594..e60b554466f 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,6 +7,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end // Do this as the first thing so that any code reading it knows the right env. process.env.NODE_ENV = 'production'; @@ -130,13 +132,13 @@ function build(previousSizeMap) { console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); console.log('To publish it at ' + chalk.green(homepagePath) + ', run:'); console.log(); - console.log(' ' + chalk.blue('git') + chalk.cyan(' commit -am ') + chalk.yellow('"Save local changes"')); - console.log(' ' + chalk.blue('git') + chalk.cyan(' checkout -B gh-pages')); - console.log(' ' + chalk.blue('git') + chalk.cyan(' add -f build')); - console.log(' ' + chalk.blue('git') + chalk.cyan(' commit -am ' + chalk.yellow('"Rebuild website"'))); - console.log(' ' + chalk.blue('git') + chalk.cyan(' filter-branch -f --prune-empty --subdirectory-filter build')); - console.log(' ' + chalk.blue('git') + chalk.cyan(' push -f origin gh-pages')); - console.log(' ' + chalk.blue('git') + chalk.cyan(' checkout -')); + console.log(' ' + chalk.cyan('git') + ' commit -am ' + chalk.yellow('"Save local changes"')); + console.log(' ' + chalk.cyan('git') + ' checkout -B gh-pages'); + console.log(' ' + chalk.cyan('git') + ' add -f build'); + console.log(' ' + chalk.cyan('git') + ' commit -am ' + chalk.yellow('"Rebuild website"')); + console.log(' ' + chalk.cyan('git') + ' filter-branch -f --prune-empty --subdirectory-filter build'); + console.log(' ' + chalk.cyan('git') + ' push -f origin gh-pages'); + console.log(' ' + chalk.cyan('git') + ' checkout -'); console.log(); } else if (publicPath !== '/') { // "homepage": "http://mywebsite.com/project" @@ -163,9 +165,9 @@ function build(previousSizeMap) { console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.'); console.log('You may also serve it locally with a static server:') console.log(); - console.log(' ' + chalk.blue('npm') + chalk.cyan(' install -g pushstate-server')); - console.log(' ' + chalk.blue('pushstate-server') + chalk.cyan(' build')); - console.log(' ' + chalk.blue(openCommand) + chalk.cyan(' http://localhost:9000')); + console.log(' ' + chalk.cyan('npm') + ' install -g pushstate-server'); + console.log(' ' + chalk.cyan('pushstate-server') + ' build'); + console.log(' ' + chalk.cyan(openCommand) + ' http://localhost:9000'); console.log(); } }); diff --git a/scripts/eject.js b/scripts/eject.js index 82202d6eed9..3e5e18af387 100644 --- a/scripts/eject.js +++ b/scripts/eject.js @@ -73,10 +73,10 @@ prompt( console.log('Copying ' + file + ' to ' + appPath); var content = fs .readFileSync(path.join(ownPath, file), 'utf8') - // Remove license header from JS - .replace(/^\/\*\*(\*(?!\/)|[^*])*\*\//, '') - // Remove license header from AppleScript - .replace(/^--.*\n/gm, '') + // Remove dead code from .js files on eject + .replace(/\/\/ @remove-on-eject-begin([\s\S]*?)\/\/ @remove-on-eject-end/mg, '') + // Remove dead code from .applescript files on eject + .replace(/-- @remove-on-eject-begin([\s\S]*?)-- @remove-on-eject-end/mg, '') .trim() + '\n'; fs.writeFileSync(path.join(appPath, file), content); }); @@ -98,17 +98,19 @@ prompt( }); console.log('Updating scripts'); + delete appPackage.scripts['eject']; Object.keys(appPackage.scripts).forEach(function (key) { - appPackage.scripts[key] = 'node ./scripts/' + key + '.js' + appPackage.scripts[key] = appPackage.scripts[key] + .replace(/react-scripts test/g, 'jest --watch') + .replace(/react-scripts (\w+)/g, 'node scripts/$1.js'); }); - delete appPackage.scripts['eject']; - appPackage.scripts.test = 'jest'; + // Add Jest config appPackage.jest = createJestConfig( filePath => path.join('', filePath) ); - // explicitly specify ESLint config path for editor plugins + // Explicitly specify ESLint config path for editor plugins appPackage.eslintConfig = { extends: './config/eslint.js', }; diff --git a/scripts/init.js b/scripts/init.js index 50cc9d25ba7..117a040b7d8 100644 --- a/scripts/init.js +++ b/scripts/init.js @@ -7,31 +7,29 @@ * of patent rights can be found in the PATENTS file in the same directory. */ +var chalk = require('chalk'); var fs = require('fs-extra'); var path = require('path'); var spawn = require('cross-spawn'); +var pathExists = require('path-exists'); +var chalk = require('chalk'); module.exports = function(appPath, appName, verbose, originalDirectory) { var ownPath = path.join(appPath, 'node_modules', 'react-scripts'); var appPackage = require(path.join(appPath, 'package.json')); - var ownPackage = require(path.join(ownPath, 'package.json')); // Copy over some of the devDependencies appPackage.dependencies = appPackage.dependencies || {}; appPackage.devDependencies = appPackage.devDependencies || {}; - ['react', 'react-dom'].forEach(function (key) { - appPackage.dependencies[key] = ownPackage.devDependencies[key]; - }); - ['react-test-renderer'].forEach(function (key) { - appPackage.devDependencies[key] = ownPackage.devDependencies[key]; - }); // Setup the script rules - appPackage.scripts = {}; - ['start', 'build', 'eject', 'test'].forEach(function(command) { - appPackage.scripts[command] = 'react-scripts ' + command; - }); + appPackage.scripts = { + 'start': 'react-scripts start', + 'build': 'react-scripts build', + 'test': 'react-scripts test --env=jsdom', + 'eject': 'react-scripts eject' + }; // explicitly specify ESLint config path for editor plugins appPackage.eslintConfig = { @@ -43,12 +41,28 @@ module.exports = function(appPath, appName, verbose, originalDirectory) { JSON.stringify(appPackage, null, 2) ); + var readmeExists = pathExists.sync(path.join(appPath, 'README.md')); + if (readmeExists) { + fs.renameSync(path.join(appPath, 'README.md'), path.join(appPath, 'README.old.md')); + } + // Copy the files for the user fs.copySync(path.join(ownPath, 'template'), appPath); // Rename gitignore after the fact to prevent npm from renaming it to .npmignore // See: https://github.com/npm/npm/issues/1862 - fs.move(path.join(appPath, 'gitignore'), path.join(appPath, '.gitignore'), []); + fs.move(path.join(appPath, 'gitignore'), path.join(appPath, '.gitignore'), [], function (err) { + if (err) { + // Append if there's already a `.gitignore` file there + if (err.code === 'EEXIST') { + var data = fs.readFileSync(path.join(appPath, 'gitignore')); + fs.appendFileSync(path.join(appPath, '.gitignore'), data); + fs.unlinkSync(path.join(appPath, 'gitignore')); + } else { + throw err; + } + } + }); // Run another npm install for react and react-dom console.log('Installing react and react-dom from npm...'); @@ -56,6 +70,9 @@ module.exports = function(appPath, appName, verbose, originalDirectory) { // TODO: having to do two npm installs is bad, can we avoid it? var args = [ 'install', + 'react', + 'react-dom', + '--save', verbose && '--verbose' ].filter(function(e) { return e; }); var proc = spawn('npm', args, {stdio: 'inherit'}); @@ -80,14 +97,28 @@ module.exports = function(appPath, appName, verbose, originalDirectory) { console.log('Success! Created ' + appName + ' at ' + appPath + '.'); console.log('Inside that directory, you can run several commands:'); console.log(); - console.log(' * npm start: Starts the development server.'); - console.log(' * npm run build: Bundles the app into static files for production.'); - console.log(' * npm run eject: Removes this tool. If you do this, you can’t go back!'); + console.log(chalk.cyan('npm start')); + console.log(' Starts the development server.'); + console.log(); + console.log(chalk.cyan('npm test')); + console.log(' Starts the test runner.'); + console.log(); + console.log(chalk.cyan('npm run build')); + console.log(' Bundles the app into static files for production.'); + console.log(); + console.log(chalk.cyan('npm run eject')); + console.log(' Removes this tool and copies build dependencies, configs,') + console.log(' and scripts into the app directory.') + console.log(' If you do this, you can’t go back!'); console.log(); console.log('We suggest that you begin by typing:'); console.log(); console.log(' cd', cdpath); - console.log(' npm start'); + console.log(' ' + chalk.cyan('npm start')); + if (readmeExists) { + console.log(); + console.log(chalk.yellow('You had a `README.md` file, we renamed it to `README.old.md`')); + } console.log(); console.log('Happy hacking!'); }); diff --git a/scripts/start.js b/scripts/start.js index d76390084b6..a1d984017f8 100644 --- a/scripts/start.js +++ b/scripts/start.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,6 +7,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end process.env.NODE_ENV = 'development'; @@ -25,10 +27,10 @@ var paths = require('../config/paths'); // Tools like Cloud9 rely on this. var DEFAULT_PORT = process.env.PORT || 3000; var compiler; - -// TODO: hide this behind a flag and eliminate dead code on eject. -// This shouldn't be exposed to the user. var handleCompile; + +// You can safely remove this after ejecting. +// We only use this block for testing of Create React App itself: var isSmokeTest = process.argv.some(arg => arg.indexOf('--smoke-test') > -1); if (isSmokeTest) { handleCompile = function (err, stats) { @@ -72,7 +74,7 @@ function clearConsole() { process.stdout.write('\x1bc'); } -function setupCompiler(port) { +function setupCompiler(port, protocol) { // "Compiler" is a low-level interface to Webpack. // It lets us listen to some events and provide our own custom messages. compiler = webpack(config, handleCompile); @@ -97,7 +99,7 @@ function setupCompiler(port) { console.log(); console.log('The app is running at:'); console.log(); - console.log(' ' + chalk.cyan('http://localhost:' + port + '/')); + console.log(' ' + chalk.cyan(protocol + '://localhost:' + port + '/')); console.log(); console.log('Note that the development build is not optimized.'); console.log('To create a production build, use ' + chalk.cyan('npm run build') + '.'); @@ -108,7 +110,9 @@ function setupCompiler(port) { // We have switched off the default Webpack output in WebpackDevServer // options so we are going to "massage" the warnings and errors and present // them in a readable focused way. - var json = stats.toJson(); + // We use stats.toJson({}, true) to make output more compact and readable: + // https://github.com/facebookincubator/create-react-app/issues/401#issuecomment-238291901 + var json = stats.toJson({}, true); var formattedErrors = json.errors.map(message => 'Error in ' + formatMessage(message) ); @@ -146,14 +150,14 @@ function setupCompiler(port) { }); } -function openBrowser(port) { +function openBrowser(port, protocol) { if (process.platform === 'darwin') { try { // Try our best to reuse existing tab // on OS X Google Chrome with AppleScript execSync('ps cax | grep "Google Chrome"'); execSync( - 'osascript chrome.applescript http://localhost:' + port + '/', + 'osascript chrome.applescript ' + protocol + '://localhost:' + port + '/', {cwd: path.join(__dirname, 'utils'), stdio: 'ignore'} ); return; @@ -163,7 +167,33 @@ function openBrowser(port) { } // Fallback to opn // (It will always open new tab) - opn('http://localhost:' + port + '/'); + opn(protocol + '://localhost:' + port + '/'); +} + +// We need to provide a custom onError function for httpProxyMiddleware. +// It allows us to log custom error messages on the console. +function onProxyError(proxy) { + return function(err, req, res){ + var host = req.headers && req.headers.host; + console.log( + chalk.red('Proxy error:') + ' Could not proxy request ' + chalk.cyan(req.url) + + ' from ' + chalk.cyan(host) + ' to ' + chalk.cyan(proxy) + '.' + ); + console.log( + 'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' + + chalk.cyan(err.code) + ').' + ); + console.log(); + + // And immediately send the proper error response to the client. + // Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side. + if (res.writeHead && !res.headersSent) { + res.writeHead(500); + } + res.end('Proxy error: Could not proxy request ' + req.url + ' from ' + + host + ' to ' + proxy + ' (' + err.code + ').' + ); + } } function addMiddleware(devServer) { @@ -171,6 +201,8 @@ function addMiddleware(devServer) { // Every unrecognized request will be forwarded to it. var proxy = require(paths.appPackageJson).proxy; devServer.use(historyApiFallback({ + // Allow paths with dots in them to be loaded, reference issue #387 + disableDotRule: true, // For single page apps, we generally want to fallback to /index.html. // However we also want to respect `proxy` for API calls. // So if `proxy` is specified, we need to decide which fallback to use. @@ -203,6 +235,7 @@ function addMiddleware(devServer) { httpProxyMiddleware(pathname => mayProxy.test(pathname), { target: proxy, logLevel: 'silent', + onError: onProxyError(proxy), secure: false, changeOrigin: true }) @@ -213,8 +246,25 @@ function addMiddleware(devServer) { devServer.use(devServer.middleware); } -function runDevServer(port) { +function runDevServer(port, protocol) { var devServer = new WebpackDevServer(compiler, { + // By default WebpackDevServer also serves files from the current directory. + // This might be useful in legacy apps. However we already encourage people + // to use Webpack for importing assets in the code, so we don't need to + // additionally serve files by their filenames. Otherwise, even if it + // works in development, those files will be missing in production, unless + // we explicitly copy them. But even if we copy the all the files into + // the build output (which doesn't seem to be wise because it may contain + // private information such as files with API keys, for example), we would + // still have a problem. Since the filenames would be the same every time, + // browsers would cache their content, and updating file content would not + // work correctly. This is easily solved by importing assets through Webpack + // because if it can then append content hashes to filenames in production, + // just like it does for JS and CSS. And because we configured "html" loader + // to be used for HTML files, even would + // get resolved correctly by Webpack and handled both in development and + // in production without actually serving it by that path. + contentBase: [], // Enable hot reloading server. It will provide /sockjs-node/ endpoint // for the WebpackDevServer client so it can learn when the files were // updated. The WebpackDevServer client is included as an entry point @@ -231,7 +281,9 @@ function runDevServer(port) { // https://github.com/facebookincubator/create-react-app/issues/293 watchOptions: { ignored: /node_modules/ - } + }, + // Enable HTTPS if the HTTPS environment variable is set to 'true' + https: protocol === "https" ? true : false }); // Our custom middleware proxies requests to /index.html or a remote API. @@ -246,13 +298,14 @@ function runDevServer(port) { clearConsole(); console.log(chalk.cyan('Starting the development server...')); console.log(); - openBrowser(port); + openBrowser(port, protocol); }); } function run(port) { - setupCompiler(port); - runDevServer(port); + var protocol = process.env.HTTPS === 'true' ? "https" : "http"; + setupCompiler(port, protocol); + runDevServer(port, protocol); } // We attempt to use the default port but if it is busy, we offer the user to @@ -265,8 +318,8 @@ detect(DEFAULT_PORT).then(port => { clearConsole(); var question = - chalk.yellow('Something is already running at port ' + DEFAULT_PORT + '.') + - '\n\nWould you like to run the app at another port instead?'; + chalk.yellow('Something is already running on port ' + DEFAULT_PORT + '.') + + '\n\nWould you like to run the app on another port instead?'; prompt(question, true).then(shouldChangePort => { if (shouldChangePort) { diff --git a/scripts/test.js b/scripts/test.js index f11cda5a428..d13aff38017 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -16,9 +16,9 @@ const paths = require('../config/paths'); const argv = process.argv.slice(2); -const index = argv.indexOf('--debug-template'); -if (index !== -1) { - argv.splice(index, 1); +// Watch unless on CI +if (!process.env.CI) { + argv.push('--watch'); } argv.push('--config', JSON.stringify(createJestConfig( diff --git a/scripts/utils/WatchMissingNodeModulesPlugin.js b/scripts/utils/WatchMissingNodeModulesPlugin.js index ee99c218806..45c3616d2e1 100644 --- a/scripts/utils/WatchMissingNodeModulesPlugin.js +++ b/scripts/utils/WatchMissingNodeModulesPlugin.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,6 +7,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end // This Webpack plugin ensures `npm install ` forces a project rebuild. // We’re not sure why this isn't Webpack's default behavior. diff --git a/scripts/utils/chrome.applescript b/scripts/utils/chrome.applescript index 0035dcad5e6..07d229652d8 100644 --- a/scripts/utils/chrome.applescript +++ b/scripts/utils/chrome.applescript @@ -1,9 +1,14 @@ --- Copyright (c) 2015-present, Facebook, Inc. --- All rights reserved. --- --- This source code is licensed under the BSD-style license found in the +-- @remove-on-eject-begin +(* +Copyright (c) 2015-present, Facebook, Inc. +All rights reserved. + +This source code is licensed under the BSD-style license found in the -- LICENSE file in the root directory of this source tree. An additional grant --- of patent rights can be found in the PATENTS file in the same directory. +of patent rights can be found in the PATENTS file in the same directory. +*) +-- @remove-on-eject-end + on run argv set theURL to item 1 of argv diff --git a/scripts/utils/createJestConfig.js b/scripts/utils/createJestConfig.js index 282705f0dd3..8d3b60f8614 100644 --- a/scripts/utils/createJestConfig.js +++ b/scripts/utils/createJestConfig.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,20 +7,28 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end + +const pathExists = require('path-exists'); +const paths = require('../../config/paths'); module.exports = (resolve, rootDir) => { + const setupFiles = [resolve('config/polyfills.js')]; + if (pathExists.sync(paths.testsSetup)) { + setupFiles.push(paths.testsSetup); + } + const config = { - automock: false, + moduleFileExtensions: ['jsx', 'js', 'json'], moduleNameMapper: { - '^[./a-zA-Z0-9$_-]+\\.(jpg|png|gif|eot|svg|ttf|woff|woff2|mp4|webm)$': resolve('config/jest/FileStub.js'), - '^[./a-zA-Z0-9$_-]+\\.css$': resolve('config/jest/CSSStub.js') + '^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm)$': resolve('config/jest/FileStub.js'), + '^.+\\.css$': resolve('config/jest/CSSStub.js') }, - persistModuleRegistryBetweenSpecs: true, scriptPreprocessor: resolve('config/jest/transform.js'), - setupFiles: [ - resolve('config/polyfills.js') - ], - testEnvironment: 'node' + setupFiles: setupFiles, + testPathIgnorePatterns: ['/(build|docs|node_modules)/'], + testEnvironment: 'node', + testRegex: '(/__tests__/.*|\\.(test|spec))\\.(js|jsx)$', }; if (rootDir) { config.rootDir = rootDir; diff --git a/scripts/utils/prompt.js b/scripts/utils/prompt.js index b1a806b676b..ed32c750612 100644 --- a/scripts/utils/prompt.js +++ b/scripts/utils/prompt.js @@ -1,3 +1,4 @@ +// @remove-on-eject-begin /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -6,6 +7,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +// @remove-on-eject-end var rl = require('readline'); diff --git a/tasks/cra.sh b/tasks/cra.sh new file mode 100755 index 00000000000..726c6de8499 --- /dev/null +++ b/tasks/cra.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# Copyright (c) 2015-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. + +# ****************************************************************************** +# This creates an app with the global CLI and `react-scripts` from the source. +# It is useful for testing the end-to-end flow locally. +# ****************************************************************************** + +# Start in tasks/ even if run from root directory +cd "$(dirname "$0")" + +function cleanup { + echo 'Cleaning up.' + cd $root_path + # Uncomment when snapshot testing is enabled by default: + # rm ./template/src/__snapshots__/App.test.js.snap + rm -rf $clean_path +} + +# Error messages are redirected to stderr +function handle_error { + echo "$(basename $0): ERROR! An error was encountered executing line $1." 1>&2; + cleanup + echo 'Exiting with error.' 1>&2; + exit 1 +} + +function handle_exit { + cleanup + echo 'Exiting without error.' 1>&2; + exit +} + +# Exit the script with a helpful error message when any error is encountered +trap 'set +x; handle_error $LINENO $BASH_COMMAND' ERR + +# Cleanup before exit on any termination signal +trap 'set +x; handle_exit' SIGQUIT SIGTERM SIGINT SIGKILL SIGHUP + +# Echo every command being executed +set -x + +# Go to root +cd .. +root_path=$PWD + +# ****************************************************************************** +# Pack react-scripts so we can verify they work. +# ****************************************************************************** + +# Packing react-scripts takes some work because we want to clean it up first. +# Create a temporary clean folder that contains production only code. +# Do not overwrite any files in the current folder. +clean_path=`mktemp -d 2>/dev/null || mktemp -d -t 'clean_path'` + +# Copy some of the project files to the temporary folder. +# Exclude folders that definitely won’t be part of the package from processing. +# We will strip the dev-only code there, `npm pack`, and copy the package back. +cd $root_path +rsync -av --exclude='.git' --exclude=$clean_path\ + --exclude='node_modules' --exclude='build'\ + './' $clean_path >/dev/null + +# Open the clean folder +cd $clean_path +# Now remove all the code relevant to development of Create React App. +files="$(find -L . -name "*.js" -type f)" +for file in $files; do + sed -i.bak '/\/\/ @remove-on-publish-begin/,/\/\/ @remove-on-publish-end/d' $file + rm $file.bak +done + +# Finally, pack react-scripts +cp -rf $root_path/node_modules $clean_path +scripts_path=$clean_path/`npm pack` + +# ****************************************************************************** +# Now that we have packed them, call the global CLI. +# ****************************************************************************** + +# Go back to the root directory and run the command from here +cd $root_path +node global-cli/index.js --scripts-version=$scripts_path "$@" + +# Cleanup +cleanup diff --git a/tasks/e2e.sh b/tasks/e2e.sh index 8189847f7f7..0cd92b0d25e 100755 --- a/tasks/e2e.sh +++ b/tasks/e2e.sh @@ -1,3 +1,4 @@ +#!/bin/bash # Copyright (c) 2015-present, Facebook, Inc. # All rights reserved. # @@ -5,26 +6,33 @@ # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. -# Start in tests/ even if run from root directory +# ****************************************************************************** +# This is an end-to-end test intended to run on CI. +# You can also run it locally but it's slow. +# ****************************************************************************** + +# Start in tasks/ even if run from root directory cd "$(dirname "$0")" function cleanup { echo 'Cleaning up.' - cd $initial_path - rm ../template/src/__tests__/__snapshots__/App-test.js.snap - rm -rf $temp_cli_path $temp_app_path + cd $root_path + # Uncomment when snapshot testing is enabled by default: + # rm ./template/src/__snapshots__/App.test.js.snap + rm -rf $temp_cli_path $temp_app_path $clean_path } +# Error messages are redirected to stderr function handle_error { - echo "$(basename $0): \033[31mERROR!\033[m An error was encountered executing \033[36mline $1\033[m." + echo "$(basename $0): ERROR! An error was encountered executing line $1." 1>&2; cleanup - echo 'Exiting with error.' + echo 'Exiting with error.' 1>&2; exit 1 } function handle_exit { cleanup - echo 'Exiting without error.' + echo 'Exiting without error.' 1>&2; exit } @@ -37,46 +45,78 @@ trap 'set +x; handle_exit' SIGQUIT SIGTERM SIGINT SIGKILL SIGHUP # Echo every command being executed set -x -# npm pack the two directories to make sure they are valid npm modules -initial_path=$PWD - +# Go to root cd .. +root_path=$PWD -# A hacky way to avoid bundling dependencies. -# Packing with them enabled takes too much memory, and Travis crashes. -# End to end script is meant to run on Travis so it's not a big deal. -# If you run it locally, you'll need to `git checkout -- package.json`. -perl -i -p0e 's/bundledDependencies.*?]/bundledDependencies": []/s' package.json - -# Pack react-scripts -npm install -scripts_path=$PWD/`npm pack` - -# lint +# Lint ./node_modules/.bin/eslint --ignore-path .gitignore ./ -# Test local start command -npm start -- --smoke-test +# ****************************************************************************** +# First, test the create-react-app development environment. +# This does not affect our users but makes sure we can develop it. +# ****************************************************************************** + +npm install # Test local build command npm run build - # Check for expected output test -e build/*.html test -e build/static/js/*.js test -e build/static/css/*.css test -e build/static/media/*.svg +test -e build/favicon.ico -# Run tests -npm run test -test -e template/src/__tests__/__snapshots__/App-test.js.snap +# Run tests with CI flag +CI=true npm test +# Uncomment when snapshot testing is enabled by default: +# test -e template/src/__snapshots__/App.test.js.snap + +# Test local start command +npm start -- --smoke-test -# Pack CLI +# ****************************************************************************** +# Next, pack react-scripts and create-react-app so we can verify they work. +# ****************************************************************************** + +# Pack CLI (it doesn't need cleaning) cd global-cli npm install cli_path=$PWD/`npm pack` -# Install the cli in a temporary location ( http://unix.stackexchange.com/a/84980 ) +# Packing react-scripts takes more work because we want to clean it up first. +# Create a temporary clean folder that contains production only code. +# Do not overwrite any files in the current folder. +clean_path=`mktemp -d 2>/dev/null || mktemp -d -t 'clean_path'` + +# Copy some of the project files to the temporary folder. +# Exclude folders that definitely won’t be part of the package from processing. +# We will strip the dev-only code there, `npm pack`, and copy the package back. +cd $root_path +rsync -av --exclude='.git' --exclude=$clean_path\ + --exclude='node_modules' --exclude='build'\ + './' $clean_path >/dev/null + +# Open the clean folder +cd $clean_path +# Now remove all the code relevant to development of Create React App. +files="$(find -L . -name "*.js" -type f)" +for file in $files; do + sed -i.bak '/\/\/ @remove-on-publish-begin/,/\/\/ @remove-on-publish-end/d' $file + rm $file.bak +done + +# Finally, pack react-scripts +npm install +scripts_path=$clean_path/`npm pack` + +# ****************************************************************************** +# Now that we have packed them, create a clean app folder and install them. +# ****************************************************************************** + +# Install the CLI in a temporary location +# http://unix.stackexchange.com/a/84980 temp_cli_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_cli_path'` cd $temp_cli_path npm install $cli_path @@ -85,37 +125,55 @@ npm install $cli_path temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'` cd $temp_app_path node "$temp_cli_path"/node_modules/create-react-app/index.js --scripts-version=$scripts_path test-app + +# ****************************************************************************** +# Now that we used create-react-app to create an app depending on react-scripts, +# let's make sure all npm scripts are in the working state. +# ****************************************************************************** + +# Enter the app directory cd test-app # Test the build npm run build - # Check for expected output test -e build/*.html test -e build/static/js/*.js test -e build/static/css/*.css test -e build/static/media/*.svg +test -e build/favicon.ico -# Run tests -npm run test -test -e src/__tests__/__snapshots__/App-test.js.snap +# Run tests with CI flag +CI=true npm test +# Uncomment when snapshot testing is enabled by default: +# test -e src/__snapshots__/App.test.js.snap # Test the server npm start -- --smoke-test -# Eject and test the build +# ****************************************************************************** +# Finally, let's check that everything still works after ejecting. +# ****************************************************************************** + +# Eject echo yes | npm run eject -npm run build +# Test the build +npm run build # Check for expected output test -e build/*.html test -e build/static/js/*.js test -e build/static/css/*.css test -e build/static/media/*.svg - -# Run tests -npm run test -test -e src/__tests__/__snapshots__/App-test.js.snap +test -e build/favicon.ico + +# Run tests, overring the watch option to disable it. +# `CI=true npm test` won't work here because `npm test` becomes just `jest`. +# We should either teach Jest to respect CI env variable, or make +# `scripts/test.js` survive ejection (right now it doesn't). +npm test -- --watch=no +# Uncomment when snapshot testing is enabled by default: +# test -e src/__snapshots__/App.test.js.snap # Test the server npm start -- --smoke-test diff --git a/tasks/release.sh b/tasks/release.sh index b30ab86abd5..83c9fefada0 100755 --- a/tasks/release.sh +++ b/tasks/release.sh @@ -1,3 +1,4 @@ +#!/bin/bash # Copyright (c) 2015-present, Facebook, Inc. # All rights reserved. # @@ -5,7 +6,14 @@ # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. -# Start in tests/ even if run from root directory +# ****************************************************************************** +# This releases an update to the `react-scripts` package. +# Don't use `npm publish` for it. +# Read the release instructions: +# https://github.com/facebookincubator/create-react-app/blob/master/CONTRIBUTING.md#cutting-a-release +# ****************************************************************************** + +# Start in tasks/ even if run from root directory cd "$(dirname "$0")" # Exit the script on any command with non 0 return code @@ -18,6 +26,7 @@ set -x # Go to root cd .. +root_path=$PWD # You can only release with npm >= 3 if [ $(npm -v | head -c 1) -lt 3 ]; then @@ -30,6 +39,25 @@ if [ -n "$(git status --porcelain)" ]; then exit 1; fi +# Create a temporary clean folder that contains production only code. +# Do not overwrite any files in the current folder. +clean_path=`mktemp -d 2>/dev/null || mktemp -d -t 'clean_path'` + +# Copy some of the project files to the temporary folder. +# Exclude folders that definitely won’t be part of the package from processing. +# We will strip the dev-only code there, and publish from it. +rsync -av --exclude='.git' --exclude=$clean_path\ + --exclude='node_modules' --exclude='build'\ + './' $clean_path >/dev/null +cd $clean_path + +# Now remove all the code relevant to development of Create React App. +files="$(find -L . -name "*.js" -type f)" +for file in $files; do + sed -i.bak '/\/\/ @remove-on-publish-begin/,/\/\/ @remove-on-publish-end/d' $file + rm $file.bak +done + # Update deps rm -rf node_modules rm -rf ~/.npm @@ -43,12 +71,12 @@ npm dedupe # Since it's in optionalDependencies, it will attempt install outside bundle rm -rf node_modules/fsevents -# This modifies package.json to copy all dependencies to bundledDependencies -# We will revert package.json back after release to avoid doing it every time -node ./node_modules/.bin/bundle-deps +# This modifies $clean_path/package.json to copy all dependencies to bundledDependencies +node $root_path/node_modules/.bin/bundle-deps # Go! npm publish "$@" -# Discard changes to package.json -git checkout -- . +# cleanup +cd .. +rm -rf $clean_path diff --git a/template/README.md b/template/README.md index 441953eef69..05ef2b43aa9 100644 --- a/template/README.md +++ b/template/README.md @@ -1,3 +1,5 @@ +This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app). + Below you will find some information on how to perform common tasks. You can find the most recent version of this guide [here](https://github.com/facebookincubator/create-react-app/blob/master/template/README.md). @@ -8,6 +10,7 @@ You can find the most recent version of this guide [here](https://github.com/fac - [Folder Structure](#folder-structure) - [Available Scripts](#available-scripts) - [npm start](#npm-start) + - [npm test](#npm-test) - [npm run build](#npm-run-build) - [npm run eject](#npm-run-eject) - [Displaying Lint Output in the Editor](#displaying-lint-output-in-the-editor) @@ -19,12 +22,33 @@ You can find the most recent version of this guide [here](https://github.com/fac - [Adding Bootstrap](#adding-bootstrap) - [Adding Flow](#adding-flow) - [Adding Custom Environment Variables](#adding-custom-environment-variables) +- [Can I Use Decorators?](#can-i-use-decorators) - [Integrating with a Node Backend](#integrating-with-a-node-backend) - [Proxying API Requests in Development](#proxying-api-requests-in-development) +- [Using HTTPS in Development](#using-https-in-development) +- [Adding `` and `` Tags](#adding-link-and-meta-tags) + - [Referring to Static Assets from ``](#referring-to-static-assets-from-link-href) + - [Generating Dynamic `` Tags on the Server](#generating-dynamic-meta-tags-on-the-server) +- [Running Tests](#running-tests) + - [Filename Conventions](#filename-conventions) + - [Command Line Interface](#command-line-interface) + - [Version Control Integration](#version-control-integration) + - [Writing Tests](#writing-tests) + - [Testing Components](#testing-components) + - [Using Third Party Assertion Libraries](#using-third-party-assertion-libraries) + - [Initializing Test Environment](#initializing-test-environment) + - [Focusing and Excluding Tests](#focusing-and-excluding-tests) + - [Coverage Reporting](#coverage-reporting) + - [Continuous Integration](#continuous-integration) + - [Disabling jsdom](#disabling-jsdom) + - [Experimental Snapshot Testing](#experimental-snapshot-testing) - [Deployment](#deployment) - - [Now](#now) - - [Heroku](#heroku) + - [Building for Relative Paths](#building-for-relative-paths) - [GitHub Pages](#github-pages) + - [Heroku](#heroku) + - [Modulus](#modulus) + - [Now](#now) + - [Surge](#surge) - [Something Missing?](#something-missing) ## Updating to New Releases @@ -62,6 +86,7 @@ my-app/ src/ App.css App.js + App.test.js index.css index.js logo.svg @@ -93,6 +118,11 @@ Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits.
You will also see any lint errors in the console. +### `npm test` + +Launches the test runner in the interactive watch mode. +See the section about [running tests](#running-tests) for more information. + ### `npm run build` Builds the app for production to the `build` folder.
@@ -347,51 +377,20 @@ node_modules/fbjs/lib/Deferred.js.flow:60 node_modules/fbjs/lib/shallowEqual.js.flow:29 29: return x !== 0 || 1 / (x: $FlowIssue) === 1 / (y: $FlowIssue); ^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name - -src/App.js:3 - 3: import logo from './logo.svg'; - ^^^^^^^^^^^^ ./logo.svg. Required module not found - -src/App.js:4 - 4: import './App.css'; - ^^^^^^^^^^^ ./App.css. Required module not found - -src/index.js:5 - 5: import './index.css'; - ^^^^^^^^^^^^^ ./index.css. Required module not found ``` To fix this, change your `.flowconfig` to look like this: ```ini -[libs] -./node_modules/fbjs/flow/lib - -[options] -esproposal.class_static_fields=enable -esproposal.class_instance_fields=enable - -module.name_mapper='^\(.*\)\.css$' -> 'react-scripts/config/flow/css' -module.name_mapper='^\(.*\)\.\(jpg\|png\|gif\|eot\|svg\|ttf\|woff\|woff2\|mp4\|webm\)$' -> 'react-scripts/config/flow/file' - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe +[ignore] +/node_modules/fbjs/.* ``` Re-run flow, and you shouldn’t get any extra issues. -If you later `eject`, you’ll need to replace `react-scripts` references with the `` placeholder, for example: - -```ini -module.name_mapper='^\(.*\)\.css$' -> '/config/flow/css' -module.name_mapper='^\(.*\)\.\(jpg\|png\|gif\|eot\|svg\|ttf\|woff\|woff2\|mp4\|webm\)$' -> '/config/flow/file' -``` - -We will consider integrating more tightly with Flow in the future so that you don’t have to do this. - ## Adding Custom Environment Variables -> Note: this feature is available with `react-scripts@0.3.0` and higher. +>Note: this feature is available with `react-scripts@0.2.3` and higher. Your project can consume variables declared in your environment as if they were declared locally in your JS files. By default you will have `NODE_ENV` defined for you, and any other environment variables starting with @@ -421,7 +420,7 @@ render() { The above form is looking for a variable called `REACT_APP_SECRET_CODE` from the environment. In order to consume this value, we need to have it defined in the environment: -### Windows (cmd.exe) +#### Windows (cmd.exe) ```cmd set REACT_APP_SECRET_CODE=abcdef&&npm start @@ -429,7 +428,7 @@ set REACT_APP_SECRET_CODE=abcdef&&npm start (Note: the lack of whitespace is intentional.) -### Linux, OS X (Bash) +#### Linux, OS X (Bash) ```bash REACT_APP_SECRET_CODE=abcdef npm start @@ -459,13 +458,30 @@ if (process.env.NODE_ENV !== 'production') { } ``` +## Can I Use Decorators? + +Many popular libraries use [decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) in their documentation. +Create React App doesn’t support decorator syntax at the moment because: + +* It is an experimental proposal and is subject to change. +* The current specification version is not officially supported by Babel. +* If the specification changes, we won’t be able to write a codemod because we don’t use them internally at Facebook. + +However in many cases you can rewrite decorator-based code without decorators just as fine. +Please refer to these two threads for reference: + +* [#214](https://github.com/facebookincubator/create-react-app/issues/214) +* [#411](https://github.com/facebookincubator/create-react-app/issues/411) + +Create React App will add decorator support when the specification advances to a stable stage. + ## Integrating with a Node Backend Check out [this tutorial](https://www.fullstackreact.com/articles/using-create-react-app-with-a-server/) for instructions on integrating an app with a Node backend running on another port, and using `fetch()` to access it. You can find the companion GitHub repository [here](https://github.com/fullstackreact/food-lookup-demo). ## Proxying API Requests in Development ->Note: this feature is available with `react-scripts@0.3.0` and higher. +>Note: this feature is available with `react-scripts@0.2.3` and higher. People often serve the front-end React app from the same host and port as their backend implementation. For example, a production setup might look like this after the app is deployed: @@ -484,15 +500,15 @@ To tell the development server to proxy any unknown requests to your API server "proxy": "http://localhost:4000", ``` -This way, when you `fetch('/api/todos')` in development, the development server will recognize that it’s not a static asset, and will proxy your request to `http://localhost:4000/api/todos` as a fallback. +This way, when you `fetch('/api/todos')` in development, the development server will recognize that it’s not a static asset, and will proxy your request to `http://localhost:4000/api/todos` as a fallback. The development server will only attempt to send requests without a `text/html` accept header to the proxy. Conveniently, this avoids [CORS issues](http://stackoverflow.com/questions/21854516/understanding-ajax-cors-and-security-considerations) and error messages like this in development: ``` -Fetch API cannot load http://localhost:400/api/todos. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. +Fetch API cannot load http://localhost:4000/api/todos. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. ``` -Keep in mind that `proxy` only has effect in development (with `npm start`), and it is up to you to ensure that URLs like `/api/todos` point to the right thing in production. You don’t have to use the `/api` prefix. Any unrecognized request will be redirected to the specified `proxy`. +Keep in mind that `proxy` only has effect in development (with `npm start`), and it is up to you to ensure that URLs like `/api/todos` point to the right thing in production. You don’t have to use the `/api` prefix. Any unrecognized request without a `text/html` accept header will be redirected to the specified `proxy`. Currently the `proxy` option only handles HTTP requests, and it won’t proxy WebSocket connections. If the `proxy` option is **not** flexible enough for you, alternatively you can: @@ -500,8 +516,318 @@ If the `proxy` option is **not** flexible enough for you, alternatively you can: * Enable CORS on your server ([here’s how to do it for Express](http://enable-cors.org/server_expressjs.html)). * Use [environment variables](#adding-custom-environment-variables) to inject the right server host and port into your app. +## Using HTTPS in Development + +>Note: this feature is available with `react-scripts@0.4.0` and higher. + +You may require the dev server to serve pages over HTTPS. One particular case where this could be useful is when using [the "proxy" feature](#proxying-api-requests-in-development) to proxy requests to an API server when that API server is itself serving HTTPS. + +To do this, set the `HTTPS` environment variable to `true`, then start the dev server as usual with `npm start`: + +#### Windows (cmd.exe) + +```cmd +set HTTPS=true&&npm start +``` + +(Note: the lack of whitespace is intentional.) + +#### Linux, OS X (Bash) + +```bash +HTTPS=true npm start +``` + +Note that the server will use a self-signed certificate, so your web browser will almost definitely display a warning upon accessing the page. + +## Adding `` and `` Tags + +You can edit the generated `index.html` and add any tags you’d like to it. + +### Referring to Static Assets from `` + +>Note: this feature is available with `react-scripts@0.3.0` and higher. + +Sometimes, you might want to refer to static assets from `index.html`. Create React App intentionally does not support serving static assets from a folder because it is too easy to forget to arrange cache invalidation for their filenames. Instead, we recommend that all assets are [handled as part of build process with `import`s](#adding-images-and-fonts). + +However, you can’t `import` anything from an HTML file. This is why Create React App automatically treats any `` attributes that start with `./` as a hint that this file needs to be included in the build process. For example, you can use paths like this in `index.html`: + +```html + + + + +``` + +Webpack will parse those `` attributes and replace them with real paths. +In production, they will become: + +```html + + + + +``` + +For this to work, **make sure to specify paths relatively** so don’t forget the `./`: + +```html + + + + + + + + +``` + +Files starting with `./` in `` attribute will be copied to the `static` folder inside your `build` output, and HTML will reference them instead. Webpack will throw a compilation error if any of these files was accidentally deleted or misspelled. + +Their names will also contain the content hashes to make sure the browser cache is busted when the file changes. The only file that is handled specially is `favicon.ico` which, if present and referenced from HTML, will be always placed at the root so that browsers can find it even when requesting files from the server (such as PDF documents). + +Currently, only `` attributes are treated this way. If you need similar support for other HTML tags and attributes, please file an issue describing your use case. + +If you need to use an asset from code rather than from HTML, please read [Adding Images and Fonts](#adding-images-and-fonts). For example, to integrate a library like [`react-mdl`](https://github.com/tleunen/react-mdl) that depends on global scripts and styles, [`import` them from JavaScript](https://github.com/tleunen/react-mdl/pull/388). + +### Generating Dynamic `` Tags on the Server + +Since Create React App doesn’t support server rendering, you might be wondering how to make `` tags dynamic and reflect the current URL. To solve this, we recommend to add placeholders into the HTML, like this: + +```html + + + + + +``` + +Then, on the server, regardless of the backend you use, you can read `index.html` into memory and replace `$OG_TITLE`, `$OG_DESCRIPTION`, and any other placeholders with values depending on the current URL. Just make sure to sanitize and escape the interpolated values so that they are safe to embed into HTML! + +If you use a Node server, you can even share the route matching logic between the client and the server. However duplicating it also works fine in simple cases. + +## Running Tests + +>Note: this feature is available with `react-scripts@0.3.0` and higher. +>[Read the migration guide to learn how to enable it in older projects!](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md#migrating-from-023-to-030) + +Create React App uses [Jest](https://facebook.github.io/jest/) as its test runner. To prepare for this integration, we did a [major revamp](https://facebook.github.io/jest/blog/2016/09/01/jest-15.html) of Jest so if you heard bad things about it years ago, give it another try. + +Jest is a Node-based runner. This means that the tests always run in a Node environment and not in a real browser. This lets us enable fast iteration speed and prevent flakiness. + +While Jest provides browser globals such as `window` thanks to [jsdom](https://github.com/tmpvar/jsdom), they are only approximations of the real browser behavior. Jest is intended to be used for unit tests of your logic and your components rather than the DOM quirks. + +We recommend that you use a separate tool for browser end-to-end tests if you need them. They are beyond the scope of Create React App. + +### Filename Conventions + +Jest will look for test files with any of the following popular naming conventions: + +* Files with `.js` suffix in `__tests__` folders. +* Files with `.test.js` suffix. +* Files with `.spec.js` suffix. + +The `.test.js` / `.spec.js` files (or the `__tests__` folders) can be located at any depth under the `src` top level folder. + +We recommend to put the test files (or `__tests__` folders) next to the code they are testing so that relative imports appear shorter. For example, if `App.test.js` and `App.js` are in the same folder, the test just needs to `import App from './App'` instead of a long relative path. Colocation also helps find tests more quickly in larger projects. + +### Command Line Interface + +When you run `npm test`, Jest will launch in the watch mode. Every time you save a file, it will re-run the tests, just like `npm start` recompiles the code. + +The watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you can keep it open and enjoy fast re-runs. You can learn the commands from the “Watch Usage” note that the watcher prints after every run: + +![Jest watch mode](http://facebook.github.io/jest/img/blog/15-watch.gif) + +### Version Control Integration + +By default, when you run `npm test`, Jest will only run the tests related to files changed since the last commit. This is an optimization designed to make your tests runs fast regardless of how many tests you have. However it assumes that you don’t often commit the code that doesn’t pass the tests. + +Jest will always explicitly mention that it only ran tests related to the files changed since the last commit. You can also press `a` in the watch mode to force Jest to run all tests. + +Jest will always run all tests on a [continuous integration](#continuous-integration) server or if the project is not inside a Git or Mercurial repository. + +### Writing Tests + +To create tests, add `it()` (or `test()`) blocks with the name of the test and its code. You may optionally wrap them in `describe()` blocks for logical grouping but this is neither required nor recommended. + +Jest provides a built-in `expect()` global function for making assertions. A basic test could look like this: + +```js +import sum from './sum'; + +it('sums numbers', () => { + expect(sum(1, 2)).toEqual(3); + expect(sum(2, 2)).toEqual(4); +}); +``` + +All `expect()` matchers supported by Jest are [extensively documented here](http://facebook.github.io/jest/docs/api.html#expect-value). +You can also use [`jest.fn()` and `expect(fn).toBeCalled()`](http://facebook.github.io/jest/docs/api.html#tobecalled) to create “spies” or mock functions. + +### Testing Components + +There is a broad spectrum of component testing techniques. They range from a “smoke test” verifying that a component renders without throwing, to shallow rendering and testing some of the output, to full rendering and testing component lifecycle and state changes. + +Different projects choose different testing tradeoffs based on how often components change, and how much logic they contain. If you haven’t decided on a testing strategy yet, we recommend that you start with creating simple smoke tests for your components: + +```js +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); +}); +``` + +This test mounts a component and makes sure that it didn’t throw during rendering. Tests like this provide a lot value with very little effort so they are great as a starting point, and this is the test you will find in `src/App.test.js`. + +When you encounter bugs caused by changing components, you will gain a deeper insight into which parts of them are worth testing in your application. This might be a good time to introduce more specific tests asserting specific expected output or behavior. + +If you’d like to test components in isolation from the child components they render, we recommend using [`shallow()` rendering API](http://airbnb.io/enzyme/docs/api/shallow.html) from [Enzyme](http://airbnb.io/enzyme/). You can write a smoke test with it too: + +```sh +npm install --save-dev enzyme react-addons-test-utils +``` + +```js +import React from 'react'; +import { shallow } from 'enzyme'; +import App from './App'; + +it('renders without crashing', () => { + shallow(); +}); +``` + +Unlike the previous smoke test using `ReactDOM.render()`, this test only renders `` and doesn’t go deeper. For example, even if `` itself renders a `