Skip to content

Commit fdb0e77

Browse files
authoredFeb 6, 2018
Merge pull request #3 from facebook/next
Update upstream #2
2 parents 032ceba + 03604a4 commit fdb0e77

File tree

19 files changed

+269
-53
lines changed

19 files changed

+269
-53
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use strict';
2+
3+
const { extname } = require('path');
4+
5+
function namedAssetImportPlugin({ types: t }) {
6+
const visited = new WeakSet();
7+
8+
return {
9+
visitor: {
10+
ImportDeclaration(path, { opts: { loaderMap } }) {
11+
const sourcePath = path.node.source.value;
12+
const ext = extname(sourcePath).substr(1);
13+
14+
if (visited.has(path.node) || sourcePath.indexOf('!') !== -1) {
15+
return;
16+
}
17+
18+
if (loaderMap[ext]) {
19+
path.replaceWithMultiple(
20+
path.node.specifiers.map(specifier => {
21+
if (t.isImportDefaultSpecifier(specifier)) {
22+
const newDefaultImport = t.importDeclaration(
23+
[
24+
t.importDefaultSpecifier(
25+
t.identifier(specifier.local.name)
26+
),
27+
],
28+
t.stringLiteral(sourcePath)
29+
);
30+
31+
visited.add(newDefaultImport);
32+
return newDefaultImport;
33+
}
34+
35+
const newImport = t.importDeclaration(
36+
[
37+
t.importSpecifier(
38+
t.identifier(specifier.local.name),
39+
t.identifier(specifier.imported.name)
40+
),
41+
],
42+
t.stringLiteral(
43+
loaderMap[ext][specifier.imported.name]
44+
? loaderMap[ext][specifier.imported.name].replace(
45+
/\[path\]/,
46+
sourcePath
47+
)
48+
: sourcePath
49+
)
50+
);
51+
52+
visited.add(newImport);
53+
return newImport;
54+
})
55+
);
56+
}
57+
},
58+
},
59+
};
60+
}
61+
62+
module.exports = namedAssetImportPlugin;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "babel-plugin-named-asset-import",
3+
"version": "0.1.0",
4+
"description": "Babel plugin for named asset imports in Create React App",
5+
"repository": "facebookincubator/create-react-app",
6+
"license": "MIT",
7+
"bugs": {
8+
"url": "https://github.com/facebookincubator/create-react-app/issues"
9+
},
10+
"main": "index.js",
11+
"files": [
12+
"index.js"
13+
],
14+
"peerDependencies": {
15+
"@babel/core": "7.0.0-beta.38"
16+
}
17+
}

‎packages/react-dev-utils/launchEditor.js

+7
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ const COMMON_EDITORS_OSX = {
5757
'/Applications/WebStorm.app/Contents/MacOS/webstorm':
5858
'/Applications/WebStorm.app/Contents/MacOS/webstorm',
5959
'/Applications/MacVim.app/Contents/MacOS/MacVim': 'mvim',
60+
'/Applications/GoLand.app/Contents/MacOS/goland':
61+
'/Applications/GoLand.app/Contents/MacOS/goland',
6062
};
6163

6264
const COMMON_EDITORS_LINUX = {
@@ -72,6 +74,7 @@ const COMMON_EDITORS_LINUX = {
7274
sublime_text: 'sublime_text',
7375
vim: 'vim',
7476
'webstorm.sh': 'webstorm',
77+
'goland.sh': 'goland',
7578
};
7679

7780
const COMMON_EDITORS_WIN = [
@@ -93,6 +96,8 @@ const COMMON_EDITORS_WIN = [
9396
'rubymine64.exe',
9497
'webstorm.exe',
9598
'webstorm64.exe',
99+
'goland.exe',
100+
'goland64.exe',
96101
];
97102

98103
function addWorkspaceToArgumentsIfExists(args, workspace) {
@@ -155,6 +160,8 @@ function getArgumentsForLineNumber(
155160
case 'rubymine64':
156161
case 'webstorm':
157162
case 'webstorm64':
163+
case 'goland':
164+
case 'goland64':
158165
return addWorkspaceToArgumentsIfExists(
159166
['--line', lineNumber, fileName],
160167
workspace
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @remove-on-eject-begin
2+
/**
3+
* Copyright (c) 2018-present, Facebook, Inc.
4+
* Copyright (c) 2016 Remind
5+
*
6+
* This source code is licensed under the MIT license found in the
7+
* LICENSE file in the root directory of this source tree.
8+
*/
9+
// @remove-on-eject-end
10+
'use strict';
11+
12+
const loader = require('graphql-tag/loader');
13+
14+
module.exports = {
15+
process(src) {
16+
return loader.call({ cacheable() {} }, src);
17+
},
18+
};

‎packages/react-scripts/config/webpack.config.dev.js

+15-23
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,18 @@ module.exports = {
192192
babelrc: false,
193193
// @remove-on-eject-end
194194
presets: [require.resolve('babel-preset-react-app')],
195+
plugins: [
196+
[
197+
require.resolve('babel-plugin-named-asset-import'),
198+
{
199+
loaderMap: {
200+
svg: {
201+
ReactComponent: 'svgr/webpack![path]',
202+
},
203+
},
204+
},
205+
],
206+
],
195207
// This is a feature of `babel-loader` for webpack (not Babel itself).
196208
// It enables caching results in ./node_modules/.cache/babel-loader/
197209
// directory for faster rebuilds.
@@ -266,30 +278,10 @@ module.exports = {
266278
},
267279
],
268280
},
269-
// Allows you to use two kinds of imports for SVG:
270-
// import logoUrl from './logo.svg'; gives you the URL.
271-
// import { ReactComponent as Logo } from './logo.svg'; gives you a component.
281+
// The GraphQL loader preprocesses GraphQL queries in .graphql files.
272282
{
273-
test: /\.svg$/,
274-
use: [
275-
{
276-
loader: require.resolve('babel-loader'),
277-
options: {
278-
// @remove-on-eject-begin
279-
babelrc: false,
280-
// @remove-on-eject-end
281-
presets: [require.resolve('babel-preset-react-app')],
282-
cacheDirectory: true,
283-
},
284-
},
285-
require.resolve('svgr/webpack'),
286-
{
287-
loader: require.resolve('file-loader'),
288-
options: {
289-
name: 'static/media/[name].[hash:8].[ext]',
290-
},
291-
},
292-
],
283+
test: /\.(graphql)$/,
284+
loader: 'graphql-tag/loader',
293285
},
294286
// "file" loader makes sure those assets get served by WebpackDevServer.
295287
// When you `import` an asset, you get its (virtual) filename.

‎packages/react-scripts/config/webpack.config.prod.js

+15-23
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,18 @@ module.exports = {
200200
babelrc: false,
201201
// @remove-on-eject-end
202202
presets: [require.resolve('babel-preset-react-app')],
203+
plugins: [
204+
[
205+
require.resolve('babel-plugin-named-asset-import'),
206+
{
207+
loaderMap: {
208+
svg: {
209+
ReactComponent: 'svgr/webpack![path]',
210+
},
211+
},
212+
},
213+
],
214+
],
203215
compact: true,
204216
highlightCode: true,
205217
},
@@ -308,30 +320,10 @@ module.exports = {
308320
),
309321
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
310322
},
311-
// Allows you to use two kinds of imports for SVG:
312-
// import logoUrl from './logo.svg'; gives you the URL.
313-
// import { ReactComponent as Logo } from './logo.svg'; gives you a component.
323+
// The GraphQL loader preprocesses GraphQL queries in .graphql files.
314324
{
315-
test: /\.svg$/,
316-
use: [
317-
{
318-
loader: require.resolve('babel-loader'),
319-
options: {
320-
// @remove-on-eject-begin
321-
babelrc: false,
322-
// @remove-on-eject-end
323-
presets: [require.resolve('babel-preset-react-app')],
324-
cacheDirectory: true,
325-
},
326-
},
327-
require.resolve('svgr/webpack'),
328-
{
329-
loader: require.resolve('file-loader'),
330-
options: {
331-
name: 'static/media/[name].[hash:8].[ext]',
332-
},
333-
},
334-
],
325+
test: /\.(graphql)$/,
326+
loader: 'graphql-tag/loader',
335327
},
336328
// "file" loader makes sure assets end up in the `build` folder.
337329
// When you `import` an asset, you get its filename.

‎packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js

+26
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ describe('Integration', () => {
3131
);
3232
});
3333

34+
it('graphql files inclusion', async () => {
35+
const doc = await initDOM('graphql-inclusion');
36+
const children = doc.getElementById('graphql-inclusion').children;
37+
38+
// .graphql
39+
expect(children[0].textContent.replace(/\s/g, '')).to.equal(
40+
'{"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","variableDefinitions":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"test"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"test"},"value":{"kind":"StringValue","value":"test","block":false}}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"test"},"arguments":[],"directives":[]}]}}]}}],"loc":{"start":0,"end":40,"source":{"body":"{\\ntest(test:\\"test\\"){\\ntest\\n}\\n}\\n","name":"GraphQLrequest","locationOffset":{"line":1,"column":1}}}}'
41+
);
42+
});
43+
3444
it('image inclusion', async () => {
3545
const doc = await initDOM('image-inclusion');
3646

@@ -71,6 +81,22 @@ describe('Integration', () => {
7181
);
7282
});
7383

84+
it('svg component', async () => {
85+
const doc = await initDOM('svg-component');
86+
87+
expect(doc.getElementById('feature-svg-component').textContent).to.equal(
88+
''
89+
);
90+
});
91+
92+
it('svg in css', async () => {
93+
const doc = await initDOM('svg-in-css');
94+
95+
expect(
96+
doc.getElementsByTagName('style')[0].textContent.replace(/\s/g, '')
97+
).to.match(/\/static\/media\/logo\..+\.svg/);
98+
});
99+
74100
it('unknown ext inclusion', async () => {
75101
const doc = await initDOM('unknown-ext-inclusion');
76102

‎packages/react-scripts/fixtures/kitchensink/src/App.js

+18-3
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ class App extends Component {
8282
);
8383
break;
8484
case 'css-modules-inclusion':
85-
import(
86-
'./features/webpack/CssModulesInclusion'
87-
).then(f => this.setFeature(f.default));
85+
import('./features/webpack/CssModulesInclusion').then(f =>
86+
this.setFeature(f.default)
87+
);
8888
break;
8989
case 'custom-interpolation':
9090
import('./features/syntax/CustomInterpolation').then(f =>
@@ -111,6 +111,11 @@ class App extends Component {
111111
this.setFeature(f.default)
112112
);
113113
break;
114+
case 'graphql-inclusion':
115+
import('./features/webpack/GraphQLInclusion').then(f =>
116+
this.setFeature(f.default)
117+
);
118+
break;
114119
case 'image-inclusion':
115120
import('./features/webpack/ImageInclusion').then(f =>
116121
this.setFeature(f.default)
@@ -174,6 +179,16 @@ class App extends Component {
174179
this.setFeature(f.default)
175180
);
176181
break;
182+
case 'svg-component':
183+
import('./features/webpack/SvgComponent').then(f =>
184+
this.setFeature(f.default)
185+
);
186+
break;
187+
case 'svg-in-css':
188+
import('./features/webpack/SvgInCss').then(f =>
189+
this.setFeature(f.default)
190+
);
191+
break;
177192
case 'template-interpolation':
178193
import('./features/syntax/TemplateInterpolation').then(f =>
179194
this.setFeature(f.default)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Copyright (c) 2018-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import React from 'react';
9+
import A from './assets/graphql.graphql';
10+
11+
export default () => (
12+
<p id="graphql-inclusion">
13+
<span>{JSON.stringify(A)}</span>
14+
</p>
15+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* Copyright (c) 2018-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import React from 'react';
9+
import ReactDOM from 'react-dom';
10+
import GraphQLInclusion from './GraphQLInclusion';
11+
12+
describe('graphql files inclusion', () => {
13+
it('renders without crashing', () => {
14+
const div = document.createElement('div');
15+
ReactDOM.render(<GraphQLInclusion />, div);
16+
});
17+
});

‎packages/react-scripts/fixtures/kitchensink/src/features/webpack/SvgComponent.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
import React from 'react';
99
import { ReactComponent as Logo } from './assets/logo.svg';
1010

11-
export default () => <Logo />;
11+
export default () => <Logo id="feature-svg-component" />;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import React from 'react';
2+
import './assets/svg.css';
3+
4+
export default () => <div id="feature-svg-in-css" />;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import SvgInCss from './SvgInCss';
4+
5+
describe('svg in css', () => {
6+
it('renders without crashing', () => {
7+
const div = document.createElement('div');
8+
ReactDOM.render(<SvgInCss />, div);
9+
});
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
test(test: "test") {
3+
test
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#feature-svg-in-css {
2+
background-image: url("./logo.svg");
3+
}

‎packages/react-scripts/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"babel-eslint": "8.2.1",
2929
"babel-jest": "22.1.0",
3030
"babel-loader": "8.0.0-beta.0",
31+
"babel-plugin-named-asset-import": "^0.1.0",
3132
"babel-preset-react-app": "^3.1.1",
3233
"case-sensitive-paths-webpack-plugin": "2.1.1",
3334
"chalk": "2.3.0",
@@ -46,6 +47,8 @@
4647
"find-pkg": "1.0.0",
4748
"fs-extra": "5.0.0",
4849
"globby": "7.1.1",
50+
"graphql": "0.12.3",
51+
"graphql-tag": "2.6.1",
4952
"html-webpack-plugin": "2.30.1",
5053
"identity-obj-proxy": "3.0.0",
5154
"jest": "22.1.2",
@@ -56,7 +59,7 @@
5659
"raf": "3.4.0",
5760
"react-dev-utils": "^5.0.0",
5861
"style-loader": "0.19.1",
59-
"svgr": "1.6.0",
62+
"svgr": "1.8.1",
6063
"sw-precache-webpack-plugin": "0.11.4",
6164
"thread-loader": "1.1.2",
6265
"uglifyjs-webpack-plugin": "1.1.6",

‎packages/react-scripts/scripts/start.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ checkBrowsers(paths.appPath)
9595
// Load proxy config
9696
const proxySetting = require(paths.appPackageJson).proxy;
9797
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
98-
// Serve webpack assets generated by the compiler over a web sever.
98+
// Serve webpack assets generated by the compiler over a web server.
9999
const serverConfig = createDevServerConfig(
100100
proxyConfig,
101101
urls.lanUrlForConfig

‎packages/react-scripts/scripts/utils/createJestConfig.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ module.exports = (resolve, rootDir, srcRoots) => {
3838
transform: {
3939
'^.+\\.(js|jsx|mjs)$': resolve('config/jest/babelTransform.js'),
4040
'^.+\\.css$': resolve('config/jest/cssTransform.js'),
41-
'^(?!.*\\.(js|jsx|mjs|css|json)$)': resolve(
41+
'^.+\\.(graphql)$': resolve('config/jest/graphqlTransform.js'),
42+
'^(?!.*\\.(js|jsx|mjs|css|json|graphql)$)': resolve(
4243
'config/jest/fileTransform.js'
4344
),
4445
},

‎packages/react-scripts/template/README.md

+29
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ You can find the most recent version of this guide [here](https://github.com/fac
2727
- [Post-Processing CSS](#post-processing-css)
2828
- [Adding a CSS Preprocessor (Sass, Less etc.)](#adding-a-css-preprocessor-sass-less-etc)
2929
- [Adding Images, Fonts, and Files](#adding-images-fonts-and-files)
30+
- [Adding GraphQL files](#adding-graphql-files)
3031
- [Using the `public` Folder](#using-the-public-folder)
3132
- [Changing the HTML](#changing-the-html)
3233
- [Adding Assets Outside of the Module System](#adding-assets-outside-of-the-module-system)
@@ -729,6 +730,34 @@ Please be advised that this is also a custom feature of Webpack.
729730
**It is not required for React** but many people enjoy it (and React Native uses a similar mechanism for images).<br>
730731
An alternative way of handling static assets is described in the next section.
731732

733+
## Adding GraphQL files
734+
735+
> Note: this feature is available with react-scripts@2.0.0 and higher.
736+
737+
If you are using GraphQL, you can **`import` GraphQL files in a JavaScript module**.
738+
739+
By importing GraphQL queries instead of using a [template tag](https://github.com/apollographql/graphql-tag), they are preprocessed at build time. This eliminates the need to process them on the client at run time. It also allows you to separate your GraphQL queries from your code. You can put a GraphQL query in a file with a `.graphql` extension.
740+
741+
Here is an example:
742+
743+
```js
744+
// query.graphql
745+
{
746+
githubStats(repository: "facebook/react") {
747+
stars
748+
}
749+
}
750+
751+
// foo.js
752+
753+
import query from './query.graphql';
754+
755+
console.log(query);
756+
// {
757+
// "kind": "Document",
758+
// ...
759+
```
760+
732761
## Using the `public` Folder
733762

734763
>Note: this feature is available with `react-scripts@0.5.0` and higher.

0 commit comments

Comments
 (0)
Please sign in to comment.