Skip to content

Commit eeaa27f

Browse files
authored
Merge pull request #1 from facebookincubator/master
Sync
2 parents e280254 + c82c4f0 commit eeaa27f

28 files changed

+759
-277
lines changed

.travis.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@ matrix:
2424
include:
2525
- node_js: 0.10
2626
env: TEST_SUITE=simple
27-
- node_js: 6
28-
env: USE_YARN=yes TEST_SUITE=simple
27+
# There's a weird Yarn/Lerna bug related to prerelease versions.
28+
# TODO: reenable after we ship 1.0.
29+
# - node_js: 6
30+
# env: USE_YARN=yes TEST_SUITE=simple

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ It correctly bundles React in production mode and optimizes the build for the be
101101

102102
The build is minified and the filenames include the hashes.<br>
103103
Your app is ready to be deployed!
104+
<!--TODO: uncoment and maybe revise
105+
A [service worker](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers) using an [offline-first caching strategy](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network) is automatically generated.<br>
106+
Your ([progressive web](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#making-a-progressive-web-app)) app is ready to be deployed!-->
104107

105108
## User Guide
106109

@@ -162,6 +165,9 @@ Please refer to the [User Guide](https://github.com/facebookincubator/create-rea
162165
* Import CSS and image files directly from JavaScript.
163166
* Autoprefixed CSS, so you don’t need `-webkit` or other prefixes.
164167
* A `build` script to bundle JS, CSS, and images for production, with sourcemaps.
168+
<!--TODO: uncomment
169+
* An offline-first [service worker](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers) and a [web app manifest](https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/), meeting all the [Progressive Web App](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#making-a-progressive-web-app) criteria.
170+
-->
165171

166172
**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.
167173

packages/eslint-config-react-app/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ module.exports = {
235235
],
236236

237237
// https://github.com/benmosher/eslint-plugin-import/tree/master/docs/rules
238+
'import/first': 'error',
239+
'import/no-amd': 'error',
238240
'import/no-webpack-loader-syntax': 'error',
239241

240242
// https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
'use strict';
11+
12+
const chalk = require('chalk');
13+
const path = require('path');
14+
15+
class ModuleScopePlugin {
16+
constructor(appSrc) {
17+
this.appSrc = appSrc;
18+
}
19+
20+
apply(resolver) {
21+
const { appSrc } = this;
22+
resolver.plugin('file', (request, callback) => {
23+
// Unknown issuer, probably webpack internals
24+
if (!request.context.issuer) {
25+
return callback();
26+
}
27+
if (
28+
// If this resolves to a node_module, we don't care what happens next
29+
request.descriptionFileRoot.indexOf('/node_modules/') !== -1 ||
30+
request.descriptionFileRoot.indexOf('\\node_modules\\') !== -1 ||
31+
// Make sure this request was manual
32+
!request.__innerRequest_request
33+
) {
34+
return callback();
35+
}
36+
// Resolve the issuer from our appSrc and make sure it's one of our files
37+
// Maybe an indexOf === 0 would be better?
38+
const relative = path.relative(appSrc, request.context.issuer);
39+
// If it's not in src/ or a subdirectory, not our request!
40+
if (relative[0] === '.') {
41+
return callback();
42+
}
43+
// Find path from src to the requested file
44+
const requestRelative = path.relative(
45+
appSrc,
46+
path.resolve(
47+
path.dirname(request.context.issuer),
48+
request.__innerRequest_request
49+
)
50+
);
51+
// Error if in a parent directory of src/
52+
if (requestRelative[0] === '.') {
53+
callback(
54+
new Error(
55+
`You attempted to import ${chalk.cyan(request.__innerRequest_request)} which falls outside of the project ${chalk.cyan('src/')} directory. ` +
56+
`Relative imports outside of ${chalk.cyan('src/')} are not supported. ` +
57+
`You can either move it inside ${chalk.cyan('src/')}, or add a symlink to it from project's ${chalk.cyan('node_modules/')}.`
58+
),
59+
request
60+
);
61+
} else {
62+
callback();
63+
}
64+
});
65+
}
66+
}
67+
68+
module.exports = ModuleScopePlugin;

packages/react-dev-utils/README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var publicUrl = '/my-custom-url';
3434
module.exports = {
3535
output: {
3636
// ...
37-
publicPath: publicUrl + '/'
37+
publicPath: publicUrl + '/'
3838
},
3939
// ...
4040
plugins: [
@@ -56,6 +56,30 @@ module.exports = {
5656
}
5757
```
5858

59+
60+
#### `new ModuleScopePlugin(appSrc: string)`
61+
62+
This Webpack plugin ensures that relative imports from app's source directory don't reach outside of it.
63+
64+
```js
65+
var path = require('path');
66+
var ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
67+
68+
69+
module.exports = {
70+
// ...
71+
resolve: {
72+
// ...
73+
plugins: [
74+
new ModuleScopePlugin(paths.appSrc),
75+
// ...
76+
],
77+
// ...
78+
},
79+
// ...
80+
}
81+
```
82+
5983
#### `new WatchMissingNodeModulesPlugin(nodeModulesPath: string)`
6084

6185
This Webpack plugin ensures `npm install <library>` forces a project rebuild.<br>
@@ -112,7 +136,7 @@ console.log('Just cleared the screen!');
112136

113137
#### `eslintFormatter(results: Object): string`
114138

115-
This is our custom ESLint formatter that integrates well with Create React App console output.
139+
This is our custom ESLint formatter that integrates well with Create React App console output.<br>
116140
You can use the default one instead if you prefer so.
117141

118142
```js
@@ -228,6 +252,19 @@ if (openBrowser('http://localhost:3000')) {
228252
}
229253
```
230254

255+
#### `printHostingInstructions(appPackage: Object, publicUrl: string, publicPath: string, buildFolder: string, useYarn: boolean): void`
256+
257+
Prints hosting instructions after the project is built.
258+
259+
Pass your parsed `package.json` object as `appPackage`, your the URL where you plan to host the app as `publicUrl`, `output.publicPath` from your Webpack configuration as `publicPath`, the `buildFolder` name, and whether to `useYarn` in instructions.
260+
261+
```js
262+
const appPackage = require(paths.appPackageJson);
263+
const publicUrl = paths.publicUrl;
264+
const publicPath = config.output.publicPath;
265+
printHostingInstructions(appPackage, publicUrl, publicPath, 'build', true);
266+
```
267+
231268
#### `webpackHotDevClient.js`
232269

233270
This is an alternative client for [WebpackDevServer](https://github.com/webpack/webpack-dev-server) that shows a syntax error overlay.

packages/react-dev-utils/ansiHTML.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ var Anser = require('anser');
1515
// var base00 = 'ffffff'; // Default Background
1616
var base01 = 'f5f5f5'; // Lighter Background (Used for status bars)
1717
// var base02 = 'c8c8fa'; // Selection Background
18-
var base03 = '969896'; // Comments, Invisibles, Line Highlighting
18+
var base03 = '6e6e6e'; // Comments, Invisibles, Line Highlighting
1919
// var base04 = 'e8e8e8'; // Dark Foreground (Used for status bars)
2020
var base05 = '333333'; // Default Foreground, Caret, Delimiters, Operators
2121
// var base06 = 'ffffff'; // Light Foreground (Not often used)
2222
// var base07 = 'ffffff'; // Light Background (Not often used)
23-
var base08 = 'ed6a43'; // Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
23+
var base08 = '881280'; // Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
2424
// var base09 = '0086b3'; // Integers, Boolean, Constants, XML Attributes, Markup Link Url
2525
// var base0A = '795da3'; // Classes, Markup Bold, Search Text Background
26-
var base0B = '183691'; // Strings, Inherited Class, Markup Code, Diff Inserted
27-
var base0C = '183691'; // Support, Regular Expressions, Escape Characters, Markup Quotes
26+
var base0B = '1155cc'; // Strings, Inherited Class, Markup Code, Diff Inserted
27+
var base0C = '994500'; // Support, Regular Expressions, Escape Characters, Markup Quotes
2828
// var base0D = '795da3'; // Functions, Methods, Attribute IDs, Headings
29-
var base0E = 'a71d5d'; // Keywords, Storage, Selector, Markup Italic, Diff Changed
29+
var base0E = 'c80000'; // Keywords, Storage, Selector, Markup Italic, Diff Changed
3030
// var base0F = '333333'; // Deprecated, Opening/Closing Embedded Language Tags e.g. <?php ?>
3131

3232
// Map ANSI colors from what babel-code-frame uses to base16-github

packages/react-dev-utils/eslintFormatter.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,23 @@ function isError(message) {
1212

1313
function formatter(results) {
1414
let output = '\n';
15+
let hasErrors = false;
16+
let reportContainsErrorRuleIDs = false;
1517

1618
results.forEach(result => {
1719
let messages = result.messages;
1820
if (messages.length === 0) {
1921
return;
2022
}
2123

22-
let hasErrors = false;
2324
messages = messages.map(message => {
2425
let messageType;
2526
if (isError(message)) {
2627
messageType = 'error';
2728
hasErrors = true;
29+
if (message.ruleId) {
30+
reportContainsErrorRuleIDs = true;
31+
}
2832
} else {
2933
messageType = 'warn';
3034
}
@@ -61,6 +65,19 @@ function formatter(results) {
6165
output += `${outputTable}\n\n`;
6266
});
6367

68+
if (reportContainsErrorRuleIDs) {
69+
// Unlike with warnings, we have to do it here.
70+
// We have similar code in react-scripts for warnings,
71+
// but warnings can appear in multiple files so we only
72+
// print it once at the end. For errors, however, we print
73+
// it here because we always show at most one error, and
74+
// we can only be sure it's an ESLint error before exiting
75+
// this function.
76+
output += 'Search for the ' +
77+
chalk.underline(chalk.red('rule keywords')) +
78+
' to learn more about each error.';
79+
}
80+
6481
return output;
6582
}
6683

packages/react-dev-utils/formatWebpackMessages.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ function formatMessage(message, isError) {
6565
lines[1]
6666
.replace("Cannot resolve 'file' or 'directory' ", '')
6767
.replace('Cannot resolve module ', '')
68-
.replace('Error: ', ''),
68+
.replace('Error: ', '')
69+
.replace('[CaseSensitivePathsPlugin] ', ''),
6970
];
7071
}
7172

packages/react-dev-utils/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
"getProcessForPort.js",
2222
"InterpolateHtmlPlugin.js",
2323
"launchEditor.js",
24+
"ModuleScopePlugin.js",
2425
"openBrowser.js",
2526
"openChrome.applescript",
2627
"prepareProxy.js",
28+
"printHostingInstructions.js",
2729
"WatchMissingNodeModulesPlugin.js",
2830
"webpackHotDevClient.js"
2931
],
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
'use strict';
11+
12+
const chalk = require('chalk');
13+
const url = require('url');
14+
15+
function printHostingInstructions(
16+
appPackage,
17+
publicUrl,
18+
publicPath,
19+
buildFolder,
20+
useYarn
21+
) {
22+
const publicPathname = url.parse(publicPath).pathname;
23+
if (publicUrl && publicUrl.indexOf('.github.io/') !== -1) {
24+
// "homepage": "http://user.github.io/project"
25+
console.log(
26+
`The project was built assuming it is hosted at ${chalk.green(publicPathname)}.`
27+
);
28+
console.log(
29+
`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
30+
);
31+
console.log();
32+
console.log(`The ${chalk.cyan('build')} folder is ready to be deployed.`);
33+
console.log(`To publish it at ${chalk.green(publicUrl)}, run:`);
34+
// If script deploy has been added to package.json, skip the instructions
35+
if (typeof appPackage.scripts.deploy === 'undefined') {
36+
console.log();
37+
if (useYarn) {
38+
console.log(` ${chalk.cyan('yarn')} add --dev gh-pages`);
39+
} else {
40+
console.log(` ${chalk.cyan('npm')} install --save-dev gh-pages`);
41+
}
42+
console.log();
43+
console.log(
44+
`Add the following script in your ${chalk.cyan('package.json')}.`
45+
);
46+
console.log();
47+
console.log(` ${chalk.dim('// ...')}`);
48+
console.log(` ${chalk.yellow('"scripts"')}: {`);
49+
console.log(` ${chalk.dim('// ...')}`);
50+
console.log(
51+
` ${chalk.yellow('"predeploy"')}: ${chalk.yellow('"npm run build",')}`
52+
);
53+
console.log(
54+
` ${chalk.yellow('"deploy"')}: ${chalk.yellow('"gh-pages -d build"')}`
55+
);
56+
console.log(' }');
57+
console.log();
58+
console.log('Then run:');
59+
}
60+
console.log();
61+
console.log(` ${chalk.cyan(useYarn ? 'yarn' : 'npm')} run deploy`);
62+
console.log();
63+
} else if (publicPath !== '/') {
64+
// "homepage": "http://mywebsite.com/project"
65+
console.log(
66+
`The project was built assuming it is hosted at ${chalk.green(publicPath)}.`
67+
);
68+
console.log(
69+
`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
70+
);
71+
console.log();
72+
console.log(`The ${chalk.cyan('build')} folder is ready to be deployed.`);
73+
console.log();
74+
} else {
75+
if (publicUrl) {
76+
// "homepage": "http://mywebsite.com"
77+
console.log(
78+
`The project was built assuming it is hosted at ${chalk.green(publicUrl)}.`
79+
);
80+
console.log(
81+
`You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
82+
);
83+
console.log();
84+
} else {
85+
// no homepage
86+
console.log(
87+
'The project was built assuming it is hosted at the server root.'
88+
);
89+
console.log(
90+
`To override this, specify the ${chalk.green('homepage')} in your ${chalk.cyan('package.json')}.`
91+
);
92+
console.log('For example, add this to build it for GitHub Pages:');
93+
console.log();
94+
console.log(
95+
` ${chalk.green('"homepage"')} ${chalk.cyan(':')} ${chalk.green('"http://myname.github.io/myapp"')}${chalk.cyan(',')}`
96+
);
97+
console.log();
98+
}
99+
console.log(
100+
`The ${chalk.cyan(buildFolder)} folder is ready to be deployed.`
101+
);
102+
console.log('You may serve it with a static server:');
103+
console.log();
104+
if (useYarn) {
105+
console.log(` ${chalk.cyan('yarn')} global add serve`);
106+
} else {
107+
console.log(` ${chalk.cyan('npm')} install -g serve`);
108+
}
109+
console.log(` ${chalk.cyan('serve')} -s build`);
110+
console.log();
111+
}
112+
}
113+
114+
module.exports = printHostingInstructions;

0 commit comments

Comments
 (0)