Skip to content

Update from upstream repo facebookincubator/create-react-app@master #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,4 @@ Notable alternatives also include:
* [gluestick](https://github.com/TrueCar/gluestick)

You can also use module bundlers like [webpack](http://webpack.js.org) and [Browserify](http://browserify.org/) directly.<br>
React documentation includes [a walkthrough](https://facebook.github.io/react/docs/package-management.html) on this topic.
React documentation includes [a walkthrough](https://reactjs.org/docs/installation.html#development-and-production-versions) on this topic.
10 changes: 7 additions & 3 deletions packages/react-dev-utils/getProcessForPort.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function getProcessCommand(processId, processDirectory) {
execOptions
);

command = command.replace(/\n$/, '')
command = command.replace(/\n$/, '');

if (isProcessAReactApp(command)) {
const packageName = getPackageNameInDirectory(processDirectory);
Expand All @@ -68,8 +68,12 @@ function getProcessForPort(port) {
var processId = getProcessIdOnPort(port);
var directory = getDirectoryOfProcessById(processId);
var command = getProcessCommand(processId, directory);
return chalk.cyan(command) + chalk.grey(' (pid ' + processId + ')\n') +
chalk.blue(' in ') + chalk.cyan(directory);
return (
chalk.cyan(command) +
chalk.grey(' (pid ' + processId + ')\n') +
chalk.blue(' in ') +
chalk.cyan(directory)
);
} catch (e) {
return null;
}
Expand Down
95 changes: 95 additions & 0 deletions packages/react-error-overlay/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const webpack = require('webpack');
const chalk = require('chalk');
const webpackConfig = require('./webpack.config.js');
const iframeWebpackConfig = require('./webpack.config.iframe.js');
const rimraf = require('rimraf');
const chokidar = require('chokidar');

const args = process.argv.slice(2);
const watchMode = args[0] === '--watch' || args[0] === '-w';

const isCI =
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false');

function build(config, name, callback) {
console.log(chalk.cyan('Compiling ' + name));
webpack(config).run((error, stats) => {
if (error) {
console.log(chalk.red('Failed to compile.'));
console.log(error.message || error);
console.log();
}

if (stats.compilation.errors.length) {
console.log(chalk.red('Failed to compile.'));
console.log(stats.toString({ all: false, errors: true }));
}

if (stats.compilation.warnings.length) {
console.log(chalk.yellow('Compiled with warnings.'));
console.log(stats.toString({ all: false, warnings: true }));
}

// Fail the build if running in a CI server
if (
error ||
stats.compilation.errors.length ||
stats.compilation.warnings.length
) {
isCI && process.exit(1);
return;
}

console.log(
stats.toString({ colors: true, modules: false, version: false })
);
console.log();

callback(stats);
});
}

function runBuildSteps() {
build(iframeWebpackConfig, 'iframeScript.js', () => {
build(webpackConfig, 'index.js', () => {
console.log(chalk.bold.green('Compiled successfully!\n\n'));
});
});
}

function setupWatch() {
const watcher = chokidar.watch('./src', {
ignoreInitial: true,
});

watcher.on('change', runBuildSteps);
watcher.on('add', runBuildSteps);

watcher.on('ready', () => {
runBuildSteps();
});

process.on('SIGINT', function() {
watcher.close();
process.exit(0);
});

watcher.on('error', error => {
console.error('Watcher failure', error);
process.exit(1);
});
}

// Clean up lib folder
rimraf('lib/', () => {
console.log('Cleaned up the lib folder.\n');
watchMode ? setupWatch() : runBuildSteps();
});
18 changes: 12 additions & 6 deletions packages/react-error-overlay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"main": "lib/index.js",
"scripts": {
"prepublishOnly": "npm run build:prod && npm test",
"start": "rimraf lib/ && cross-env NODE_ENV=development npm run build -- --watch",
"test": "flow && jest",
"build": "rimraf lib/ && babel src/ -d lib/",
"build:prod": "rimraf lib/ && cross-env NODE_ENV=production babel src/ -d lib/"
"start": "cross-env NODE_ENV=development node build.js --watch",
"test": "flow && cross-env NODE_ENV=test jest",
"build": "cross-env NODE_ENV=development node build.js",
"build:prod": "cross-env NODE_ENV=production node build.js"
},
"repository": "facebookincubator/create-react-app",
"license": "MIT",
Expand All @@ -35,15 +35,19 @@
"babel-code-frame": "6.22.0",
"babel-runtime": "6.26.0",
"html-entities": "1.2.1",
"object-assign": "4.1.1",
"promise": "8.0.1",
"react": "^15 || ^16",
"react-dom": "^15 || ^16",
"settle-promise": "1.0.0",
"source-map": "0.5.6"
},
"devDependencies": {
"babel-cli": "6.24.1",
"babel-eslint": "7.2.3",
"babel-preset-react-app": "^3.0.3",
"babel-loader": "^7.1.2",
"chalk": "^2.1.0",
"chokidar": "^1.7.0",
"cross-env": "5.0.5",
"eslint": "4.4.1",
"eslint-config-react-app": "^2.0.1",
Expand All @@ -54,7 +58,9 @@
"flow-bin": "^0.54.0",
"jest": "20.0.4",
"jest-fetch-mock": "1.2.1",
"rimraf": "^2.6.1"
"raw-loader": "^0.5.1",
"rimraf": "^2.6.1",
"webpack": "^3.6.0"
},
"jest": {
"setupFiles": [
Expand Down
57 changes: 57 additions & 0 deletions packages/react-error-overlay/src/iframeScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import './utils/pollyfills.js';
import React from 'react';
import ReactDOM from 'react-dom';
import CompileErrorContainer from './containers/CompileErrorContainer';
import RuntimeErrorContainer from './containers/RuntimeErrorContainer';
import { overlayStyle } from './styles';
import { applyStyles } from './utils/dom/css';

let iframeRoot = null;

function render({
currentBuildError,
currentRuntimeErrorRecords,
dismissRuntimeErrors,
launchEditorEndpoint,
}) {
if (currentBuildError) {
return <CompileErrorContainer error={currentBuildError} />;
}
if (currentRuntimeErrorRecords.length > 0) {
return (
<RuntimeErrorContainer
errorRecords={currentRuntimeErrorRecords}
close={dismissRuntimeErrors}
launchEditorEndpoint={launchEditorEndpoint}
/>
);
}
return null;
}

window.updateContent = function updateContent(errorOverlayProps) {
let renderedElement = render(errorOverlayProps);

if (renderedElement === null) {
ReactDOM.unmountComponentAtNode(iframeRoot);
return false;
}
// Update the overlay
ReactDOM.render(renderedElement, iframeRoot);
return true;
};

document.body.style.margin = '0';
// Keep popup within body boundaries for iOS Safari
document.body.style['max-width'] = '100vw';
iframeRoot = document.createElement('div');
applyStyles(iframeRoot, overlayStyle);
document.body.appendChild(iframeRoot);
window.parent.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__.iframeReady();
87 changes: 37 additions & 50 deletions packages/react-error-overlay/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
*/

/* @flow */
import React from 'react';
import type { Element } from 'react';
import ReactDOM from 'react-dom';
import CompileErrorContainer from './containers/CompileErrorContainer';
import RuntimeErrorContainer from './containers/RuntimeErrorContainer';
import { listenToRuntimeErrors } from './listenToRuntimeErrors';
import { iframeStyle, overlayStyle } from './styles';
import { iframeStyle } from './styles';
import { applyStyles } from './utils/dom/css';

// Importing iframe-bundle generated in the pre build step as
// a text using webpack raw-loader. See webpack.config.js file.
// $FlowFixMe
import iframeScript from 'iframeScript';

import type { ErrorRecord } from './listenToRuntimeErrors';

type RuntimeReportingOptions = {|
Expand All @@ -25,8 +25,8 @@ type RuntimeReportingOptions = {|

let iframe: null | HTMLIFrameElement = null;
let isLoadingIframe: boolean = false;
var isIframeReady: boolean = false;

let renderedElement: null | Element<any> = null;
let currentBuildError: null | string = null;
let currentRuntimeErrorRecords: Array<ErrorRecord> = [];
let currentRuntimeErrorOptions: null | RuntimeReportingOptions = null;
Expand Down Expand Up @@ -88,15 +88,14 @@ export function stopReportingRuntimeErrors() {
}

function update() {
renderedElement = render();
// Loading iframe can be either sync or async depending on the browser.
if (isLoadingIframe) {
// Iframe is loading.
// First render will happen soon--don't need to do anything.
return;
}
if (iframe) {
// Iframe has already loaded.
if (isIframeReady) {
// Iframe is ready.
// Just update it.
updateIframeContent();
return;
Expand All @@ -108,58 +107,46 @@ function update() {
loadingIframe.onload = function() {
const iframeDocument = loadingIframe.contentDocument;
if (iframeDocument != null && iframeDocument.body != null) {
iframeDocument.body.style.margin = '0';
// Keep popup within body boundaries for iOS Safari
iframeDocument.body.style['max-width'] = '100vw';
const iframeRoot = iframeDocument.createElement('div');
applyStyles(iframeRoot, overlayStyle);
iframeDocument.body.appendChild(iframeRoot);

// Ready! Now we can update the UI.
iframe = loadingIframe;
isLoadingIframe = false;
updateIframeContent();
const script = loadingIframe.contentWindow.document.createElement(
'script'
);
script.type = 'text/javascript';
script.innerHTML = iframeScript;
iframeDocument.body.appendChild(script);
}
};
const appDocument = window.document;
appDocument.body.appendChild(loadingIframe);
}

function render() {
if (currentBuildError) {
return <CompileErrorContainer error={currentBuildError} />;
}
if (currentRuntimeErrorRecords.length > 0) {
if (!currentRuntimeErrorOptions) {
throw new Error('Expected options to be injected.');
}
return (
<RuntimeErrorContainer
errorRecords={currentRuntimeErrorRecords}
close={dismissRuntimeErrors}
launchEditorEndpoint={currentRuntimeErrorOptions.launchEditorEndpoint}
/>
);
function updateIframeContent() {
if (!currentRuntimeErrorOptions) {
throw new Error('Expected options to be injected.');
}
return null;
}

function updateIframeContent() {
if (iframe === null) {
if (!iframe) {
throw new Error('Iframe has not been created yet.');
}
const iframeBody = iframe.contentDocument.body;
if (!iframeBody) {
throw new Error('Expected iframe to have a body.');
}
const iframeRoot = iframeBody.firstChild;
if (renderedElement === null) {
// Destroy iframe and force it to be recreated on next error

const isRendered = iframe.contentWindow.updateContent({
currentBuildError,
currentRuntimeErrorRecords,
dismissRuntimeErrors,
launchEditorEndpoint: currentRuntimeErrorOptions.launchEditorEndpoint,
});

if (!isRendered) {
window.document.body.removeChild(iframe);
ReactDOM.unmountComponentAtNode(iframeRoot);
iframe = null;
return;
isIframeReady = false;
}
// Update the overlay
ReactDOM.render(renderedElement, iframeRoot);
}

window.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ =
window.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ || {};
window.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__.iframeReady = function iframeReady() {
isIframeReady = true;
isLoadingIframe = false;
updateIframeContent();
};
18 changes: 18 additions & 0 deletions packages/react-error-overlay/src/utils/pollyfills.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

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,
// and the user has no idea what causes React's erratic future behavior.
require('promise/lib/rejection-tracking').enable();
window.Promise = require('promise/lib/es6-extensions.js');
}

// 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');
Loading