Skip to content

Instantly share code, notes, and snippets.

@ohbarye
Created November 20, 2016 03:45
Show Gist options
  • Save ohbarye/302e06c80e28fd813cf1be3b5b8788bb to your computer and use it in GitHub Desktop.
Save ohbarye/302e06c80e28fd813cf1be3b5b8788bb to your computer and use it in GitHub Desktop.
Diff by `npm run eject` of create-react-app version 0.6.0
diff --git a/config/env.js b/config/env.js
new file mode 100644
index 0000000..5d0ab7b
--- /dev/null
+++ b/config/env.js
@@ -0,0 +1,28 @@
+// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
+// injected into the application via DefinePlugin in Webpack configuration.
+
+var REACT_APP = /^REACT_APP_/i;
+
+function getClientEnvironment(publicUrl) {
+ var processEnv = Object
+ .keys(process.env)
+ .filter(key => REACT_APP.test(key))
+ .reduce((env, key) => {
+ env[key] = JSON.stringify(process.env[key]);
+ return env;
+ }, {
+ // Useful for determining whether we’re running in production mode.
+ // Most importantly, it switches React into the correct mode.
+ 'NODE_ENV': JSON.stringify(
+ process.env.NODE_ENV || 'development'
+ ),
+ // Useful for resolving the correct path to static assets in `public`.
+ // For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
+ // This should only be used as an escape hatch. Normally you would put
+ // images into the `src` and `import` them in code to get their paths.
+ 'PUBLIC_URL': JSON.stringify(publicUrl)
+ });
+ return {'process.env': processEnv};
+}
+
+module.exports = getClientEnvironment;
diff --git a/config/jest/CSSStub.js b/config/jest/CSSStub.js
new file mode 100644
index 0000000..f053ebf
--- /dev/null
+++ b/config/jest/CSSStub.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/config/jest/FileStub.js b/config/jest/FileStub.js
new file mode 100644
index 0000000..0a445d0
--- /dev/null
+++ b/config/jest/FileStub.js
@@ -0,0 +1 @@
+module.exports = "test-file-stub";
diff --git a/config/paths.js b/config/paths.js
new file mode 100644
index 0000000..2793e68
--- /dev/null
+++ b/config/paths.js
@@ -0,0 +1,57 @@
+var path = require('path');
+var fs = require('fs');
+
+// Make sure any symlinks in the project folder are resolved:
+// https://github.com/facebookincubator/create-react-app/issues/637
+var appDirectory = fs.realpathSync(process.cwd());
+function resolveApp(relativePath) {
+ return path.resolve(appDirectory, relativePath);
+}
+
+// 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.
+
+// It works similar to `NODE_PATH` in Node itself:
+// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
+
+// 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(resolveApp);
+
+// config after eject: we're in ./config/
+module.exports = {
+ appBuild: resolveApp('build'),
+ appPublic: resolveApp('public'),
+ appHtml: resolveApp('public/index.html'),
+ appIndexJs: resolveApp('src/index.js'),
+ appPackageJson: resolveApp('package.json'),
+ appSrc: resolveApp('src'),
+ testsSetup: resolveApp('src/setupTests.js'),
+ appNodeModules: resolveApp('node_modules'),
+ ownNodeModules: resolveApp('node_modules'),
+ nodePaths: nodePaths
+};
+
+
+
+// config before publish: we're in ./packages/react-scripts/config/
+if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) {
+ module.exports = {
+ appBuild: resolveOwn('../../../build'),
+ appPublic: resolveOwn('../template/public'),
+ appHtml: resolveOwn('../template/public/index.html'),
+ appIndexJs: resolveOwn('../template/src/index.js'),
+ appPackageJson: resolveOwn('../package.json'),
+ appSrc: resolveOwn('../template/src'),
+ testsSetup: resolveOwn('../template/src/setupTests.js'),
+ appNodeModules: resolveOwn('../node_modules'),
+ ownNodeModules: resolveOwn('../node_modules'),
+ nodePaths: nodePaths
+ };
+}
diff --git a/config/polyfills.js b/config/polyfills.js
new file mode 100644
index 0000000..7e60150
--- /dev/null
+++ b/config/polyfills.js
@@ -0,0 +1,14 @@
+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');
+}
+
+// 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
new file mode 100644
index 0000000..1563153
--- /dev/null
+++ b/config/webpack.config.dev.js
@@ -0,0 +1,197 @@
+var path = require('path');
+var autoprefixer = require('autoprefixer');
+var webpack = require('webpack');
+var findCacheDir = require('find-cache-dir');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
+var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
+var getClientEnvironment = require('./env');
+var paths = require('./paths');
+
+// Webpack uses `publicPath` to determine where the app is being served from.
+// In development, we always serve from the root. This makes config easier.
+var publicPath = '/';
+// `publicUrl` is just like `publicPath`, but we will provide it to our app
+// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
+// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
+var publicUrl = '';
+// Get environment variables to inject into our app.
+var env = getClientEnvironment(publicUrl);
+
+// This is the development configuration.
+// It is focused on developer experience and fast rebuilds.
+// The production configuration is different and lives in a separate file.
+module.exports = {
+ // This makes the bundle appear split into separate modules in the devtools.
+ // We don't use source maps here because they can be confusing:
+ // https://github.com/facebookincubator/create-react-app/issues/343#issuecomment-237241875
+ // You may want 'cheap-module-source-map' instead if you prefer source maps.
+ devtool: 'eval',
+ // These are the "entry points" to our application.
+ // This means they will be the "root" imports that are included in JS bundle.
+ // The first two entry points enable "hot" CSS and auto-refreshes for JS.
+ entry: [
+ // Include an alternative client for WebpackDevServer. A client's job is to
+ // connect to WebpackDevServer by a socket and get notified about changes.
+ // When you save a file, the client will either apply hot updates (in case
+ // of CSS changes), or refresh the page (in case of JS changes). When you
+ // make a syntax error, this client will display a syntax error overlay.
+ // Note: instead of the default WebpackDevServer client, we use a custom one
+ // to bring better experience for Create React App users. You can replace
+ // the line below with these two lines if you prefer the stock client:
+ // require.resolve('webpack-dev-server/client') + '?/',
+ // require.resolve('webpack/hot/dev-server'),
+ require.resolve('react-dev-utils/webpackHotDevClient'),
+ // We ship a few polyfills by default:
+ require.resolve('./polyfills'),
+ // Finally, this is your app's code:
+ paths.appIndexJs
+ // We include the app code last so that if there is a runtime error during
+ // initialization, it doesn't blow up the WebpackDevServer client, and
+ // changing JS code would still trigger a refresh.
+ ],
+ output: {
+ // Next line is not used in dev but WebpackDevServer crashes without it:
+ path: paths.appBuild,
+ // Add /* filename */ comments to generated require()s in the output.
+ pathinfo: true,
+ // This does not produce a real file. It's just the virtual path that is
+ // served by WebpackDevServer in development. This is the JS bundle
+ // containing code from all our entry points, and the Webpack runtime.
+ filename: 'static/js/bundle.js',
+ // This is the URL that app is served from. We use "/" in development.
+ 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.
+ // 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: {
+ // 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'
+ }
+ },
+
+ module: {
+ // First, run the linter.
+ // It's important to do this before Babel processes the JS.
+ preLoaders: [
+ {
+ test: /\.(js|jsx)$/,
+ loader: 'eslint',
+ include: paths.appSrc,
+ }
+ ],
+ loaders: [
+ // Process JS with Babel.
+ {
+ test: /\.(js|jsx)$/,
+ include: paths.appSrc,
+ loader: 'babel',
+ query: {
+
+ // This is a feature of `babel-loader` for webpack (not Babel itself).
+ // It enables caching results in ./node_modules/.cache/react-scripts/
+ // directory for faster rebuilds. We use findCacheDir() because of:
+ // https://github.com/facebookincubator/create-react-app/issues/483
+ cacheDirectory: findCacheDir({
+ name: 'react-scripts'
+ })
+ }
+ },
+ // "postcss" loader applies autoprefixer to our CSS.
+ // "css" loader resolves paths in CSS and adds assets as dependencies.
+ // "style" loader turns CSS into JS modules that inject <style> tags.
+ // In production, we use a plugin to extract that CSS to a file, but
+ // in development "style" loader enables hot editing of CSS.
+ {
+ test: /\.css$/,
+ loader: 'style!css?importLoaders=1!postcss'
+ },
+ // JSON is not enabled by default in Webpack but both Node and Browserify
+ // allow it implicitly so we also enable it.
+ {
+ test: /\.json$/,
+ 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: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
+ loader: 'file',
+ query: {
+ name: 'static/media/[name].[hash:8].[ext]'
+ }
+ },
+ // "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|wav|mp3|m4a|aac|oga)(\?.*)?$/,
+ loader: 'url',
+ query: {
+ limit: 10000,
+ name: 'static/media/[name].[hash:8].[ext]'
+ }
+ }
+ ]
+ },
+
+ // We use PostCSS for autoprefixing only.
+ postcss: function() {
+ return [
+ autoprefixer({
+ browsers: [
+ '>1%',
+ 'last 4 versions',
+ 'Firefox ESR',
+ 'not ie < 9', // React doesn't support IE8 anyway
+ ]
+ }),
+ ];
+ },
+ plugins: [
+ // Makes the public URL available as %PUBLIC_URL% in index.html, e.g.:
+ // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
+ // In development, this will be an empty string.
+ new InterpolateHtmlPlugin({
+ PUBLIC_URL: publicUrl
+ }),
+ // Generates an `index.html` file with the <script> injected.
+ new HtmlWebpackPlugin({
+ inject: true,
+ template: paths.appHtml,
+ }),
+ // Makes some environment variables available to the JS code, for example:
+ // if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
+ new webpack.DefinePlugin(env),
+ // This is necessary to emit hot updates (currently CSS only):
+ new webpack.HotModuleReplacementPlugin(),
+ // Watcher doesn't work well if you mistype casing in a path so we use
+ // a plugin that prints an error when you attempt to do this.
+ // See https://github.com/facebookincubator/create-react-app/issues/240
+ new CaseSensitivePathsPlugin(),
+ // If you require a missing module and then `npm install` it, you still have
+ // to restart the development server for Webpack to discover it. This plugin
+ // makes the discovery automatic so you don't have to restart.
+ // See https://github.com/facebookincubator/create-react-app/issues/186
+ new WatchMissingNodeModulesPlugin(paths.appNodeModules)
+ ],
+ // Some libraries import Node modules but don't use them in the browser.
+ // Tell Webpack to provide empty mocks for them so importing them works.
+ node: {
+ fs: 'empty',
+ net: 'empty',
+ tls: 'empty'
+ }
+};
diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js
new file mode 100644
index 0000000..95cc16a
--- /dev/null
+++ b/config/webpack.config.prod.js
@@ -0,0 +1,238 @@
+var path = require('path');
+var autoprefixer = require('autoprefixer');
+var webpack = require('webpack');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var ExtractTextPlugin = require('extract-text-webpack-plugin');
+var ManifestPlugin = require('webpack-manifest-plugin');
+var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
+var url = require('url');
+var paths = require('./paths');
+var getClientEnvironment = require('./env');
+
+function ensureSlash(path, needsSlash) {
+ var hasSlash = path.endsWith('/');
+ if (hasSlash && !needsSlash) {
+ return path.substr(path, path.length - 1);
+ } else if (!hasSlash && needsSlash) {
+ return path + '/';
+ } else {
+ return path;
+ }
+}
+
+// We use "homepage" field to infer "public path" at which the app is served.
+// Webpack needs to know it to put the right <script> hrefs into HTML even in
+// single-page apps that may serve index.html for nested URLs like /todos/42.
+// We can't use a relative path in HTML because we don't want to load something
+// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
+var homepagePath = require(paths.appPackageJson).homepage;
+var homepagePathname = homepagePath ? url.parse(homepagePath).pathname : '/';
+// Webpack uses `publicPath` to determine where the app is being served from.
+// It requires a trailing slash, or the file assets will get an incorrect path.
+var publicPath = ensureSlash(homepagePathname, true);
+// `publicUrl` is just like `publicPath`, but we will provide it to our app
+// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
+// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
+var publicUrl = ensureSlash(homepagePathname, false);
+// Get environment variables to inject into our app.
+var env = getClientEnvironment(publicUrl);
+
+// Assert this just to be safe.
+// Development builds of React are slow and not intended for production.
+if (env['process.env'].NODE_ENV !== '"production"') {
+ throw new Error('Production builds must have NODE_ENV=production.');
+}
+
+// This is the production configuration.
+// It compiles slowly and is focused on producing a fast and minimal bundle.
+// The development configuration is different and lives in a separate file.
+module.exports = {
+ // Don't attempt to continue if there are any errors.
+ bail: true,
+ // We generate sourcemaps in production. This is slow but gives good results.
+ // You can exclude the *.map files from the build during deployment.
+ devtool: 'source-map',
+ // In production, we only want to load the polyfills and the app code.
+ entry: [
+ require.resolve('./polyfills'),
+ paths.appIndexJs
+ ],
+ output: {
+ // The build folder.
+ path: paths.appBuild,
+ // Generated JS file names (with nested folders).
+ // There will be one main bundle, and one file per asynchronous chunk.
+ // We don't currently advertise code splitting but Webpack supports it.
+ filename: 'static/js/[name].[chunkhash:8].js',
+ chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
+ // We inferred the "public path" (such as / or /my-project) from homepage.
+ 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.
+ // 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: {
+ // 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'
+ }
+ },
+
+ module: {
+ // First, run the linter.
+ // It's important to do this before Babel processes the JS.
+ preLoaders: [
+ {
+ test: /\.(js|jsx)$/,
+ loader: 'eslint',
+ include: paths.appSrc
+ }
+ ],
+ loaders: [
+ // Process JS with Babel.
+ {
+ test: /\.(js|jsx)$/,
+ include: paths.appSrc,
+ loader: 'babel',
+
+ },
+ // The notation here is somewhat confusing.
+ // "postcss" loader applies autoprefixer to our CSS.
+ // "css" loader resolves paths in CSS and adds assets as dependencies.
+ // "style" loader normally turns CSS into JS modules injecting <style>,
+ // but unlike in development configuration, we do something different.
+ // `ExtractTextPlugin` first applies the "postcss" and "css" loaders
+ // (second argument), then grabs the result CSS and puts it into a
+ // separate file in our build process. This way we actually ship
+ // a single CSS file in production instead of JS code injecting <style>
+ // tags. If you use code splitting, however, any async bundles will still
+ // use the "style" loader inside the async code so CSS from them won't be
+ // in the main CSS file.
+ {
+ test: /\.css$/,
+ // "?-autoprefixer" disables autoprefixer in css-loader itself:
+ // https://github.com/webpack/css-loader/issues/281
+ // 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?importLoaders=1&-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.
+ {
+ test: /\.json$/,
+ loader: 'json'
+ },
+ // "file" loader makes sure those assets end up in the `build` folder.
+ // When you `import` an asset, you get its filename.
+ {
+ test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
+ loader: 'file',
+ query: {
+ name: 'static/media/[name].[hash:8].[ext]'
+ }
+ },
+ // "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|wav|mp3|m4a|aac|oga)(\?.*)?$/,
+ loader: 'url',
+ query: {
+ limit: 10000,
+ name: 'static/media/[name].[hash:8].[ext]'
+ }
+ }
+ ]
+ },
+
+ // We use PostCSS for autoprefixing only.
+ postcss: function() {
+ return [
+ autoprefixer({
+ browsers: [
+ '>1%',
+ 'last 4 versions',
+ 'Firefox ESR',
+ 'not ie < 9', // React doesn't support IE8 anyway
+ ]
+ }),
+ ];
+ },
+ plugins: [
+ // Makes the public URL available as %PUBLIC_URL% in index.html, e.g.:
+ // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
+ // In production, it will be an empty string unless you specify "homepage"
+ // in `package.json`, in which case it will be the pathname of that URL.
+ new InterpolateHtmlPlugin({
+ PUBLIC_URL: publicUrl
+ }),
+ // Generates an `index.html` file with the <script> injected.
+ new HtmlWebpackPlugin({
+ inject: true,
+ template: paths.appHtml,
+ minify: {
+ removeComments: true,
+ collapseWhitespace: true,
+ removeRedundantAttributes: true,
+ useShortDoctype: true,
+ removeEmptyAttributes: true,
+ removeStyleLinkTypeAttributes: true,
+ keepClosingSlash: true,
+ minifyJS: true,
+ minifyCSS: true,
+ minifyURLs: true
+ }
+ }),
+ // Makes some environment variables available to the JS code, for example:
+ // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
+ // It is absolutely essential that NODE_ENV was set to production here.
+ // Otherwise React will be compiled in the very slow development mode.
+ new webpack.DefinePlugin(env),
+ // This helps ensure the builds are consistent if source hasn't changed:
+ new webpack.optimize.OccurrenceOrderPlugin(),
+ // Try to dedupe duplicated modules, if any:
+ new webpack.optimize.DedupePlugin(),
+ // Minify the code.
+ new webpack.optimize.UglifyJsPlugin({
+ compress: {
+ screw_ie8: true, // React doesn't support IE8
+ warnings: false
+ },
+ mangle: {
+ screw_ie8: true
+ },
+ output: {
+ comments: false,
+ screw_ie8: true
+ }
+ }),
+ // Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
+ new ExtractTextPlugin('static/css/[name].[contenthash:8].css'),
+ // Generate a manifest file which contains a mapping of all asset filenames
+ // to their corresponding output file so that tools can pick it up without
+ // having to parse `index.html`.
+ new ManifestPlugin({
+ fileName: 'asset-manifest.json'
+ })
+ ],
+ // Some libraries import Node modules but don't use them in the browser.
+ // Tell Webpack to provide empty mocks for them so importing them works.
+ node: {
+ fs: 'empty',
+ net: 'empty',
+ tls: 'empty'
+ }
+};
diff --git a/package.json b/package.json
index 19ae198..6535b9f 100644
--- a/package.json
+++ b/package.json
@@ -3,16 +3,84 @@
"version": "0.1.0",
"private": true,
"devDependencies": {
- "react-scripts": "0.7.0"
+ "autoprefixer": "6.5.1",
+ "babel-core": "6.17.0",
+ "babel-eslint": "7.0.0",
+ "babel-jest": "16.0.0",
+ "babel-loader": "6.2.5",
+ "babel-preset-react-app": "^1.0.0",
+ "case-sensitive-paths-webpack-plugin": "1.1.4",
+ "chalk": "1.1.3",
+ "connect-history-api-fallback": "1.3.0",
+ "cross-spawn": "4.0.2",
+ "css-loader": "0.25.0",
+ "detect-port": "1.0.1",
+ "dotenv": "2.0.0",
+ "eslint": "3.8.1",
+ "eslint-config-react-app": "^0.3.0",
+ "eslint-loader": "1.6.0",
+ "eslint-plugin-flowtype": "2.21.0",
+ "eslint-plugin-import": "2.0.1",
+ "eslint-plugin-jsx-a11y": "2.2.3",
+ "eslint-plugin-react": "6.4.1",
+ "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-webpack-plugin": "2.24.0",
+ "http-proxy-middleware": "0.17.2",
+ "jest": "16.0.2",
+ "json-loader": "0.5.4",
+ "object-assign": "4.1.0",
+ "path-exists": "2.1.0",
+ "postcss-loader": "1.0.0",
+ "promise": "7.1.1",
+ "react-dev-utils": "^0.3.0",
+ "recursive-readdir": "2.1.0",
+ "rimraf": "2.5.4",
+ "strip-ansi": "3.0.1",
+ "style-loader": "0.13.1",
+ "url-loader": "0.5.7",
+ "webpack": "1.13.2",
+ "webpack-dev-server": "1.16.2",
+ "webpack-manifest-plugin": "1.1.0",
+ "whatwg-fetch": "1.0.0"
},
"dependencies": {
"react": "^15.4.0",
"react-dom": "^15.4.0"
},
"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test --env=jsdom",
- "eject": "react-scripts eject"
+ "start": "node scripts/start.js",
+ "build": "node scripts/build.js",
+ "test": "node scripts/test.js --env=jsdom"
+ },
+ "jest": {
+ "moduleFileExtensions": [
+ "jsx",
+ "js",
+ "json"
+ ],
+ "moduleNameMapper": {
+ "^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/config/jest/FileStub.js",
+ "^.+\\.css$": "<rootDir>/config/jest/CSSStub.js"
+ },
+ "setupFiles": [
+ "<rootDir>/config/polyfills.js"
+ ],
+ "testPathIgnorePatterns": [
+ "<rootDir>/(build|docs|node_modules)/"
+ ],
+ "testEnvironment": "node"
+ },
+ "babel": {
+ "presets": [
+ "react-app"
+ ]
+ },
+ "eslintConfig": {
+ "extends": "react-app"
}
-}
+}
\ No newline at end of file
diff --git a/scripts/build.js b/scripts/build.js
new file mode 100644
index 0000000..43c5069
--- /dev/null
+++ b/scripts/build.js
@@ -0,0 +1,205 @@
+// Do this as the first thing so that any code reading it knows the right env.
+process.env.NODE_ENV = 'production';
+
+// Load environment variables from .env file. Suppress warnings using silent
+// if this file is missing. dotenv will never modify any environment variables
+// that have already been set.
+// https://github.com/motdotla/dotenv
+require('dotenv').config({silent: true});
+
+var chalk = require('chalk');
+var fs = require('fs-extra');
+var path = require('path');
+var filesize = require('filesize');
+var gzipSize = require('gzip-size').sync;
+var rimrafSync = require('rimraf').sync;
+var webpack = require('webpack');
+var config = require('../config/webpack.config.prod');
+var paths = require('../config/paths');
+var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
+var recursive = require('recursive-readdir');
+var stripAnsi = require('strip-ansi');
+
+// Warn and crash if required files are missing
+if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
+ process.exit(1);
+}
+
+// Input: /User/dan/app/build/static/js/main.82be8.js
+// Output: /static/js/main.js
+function removeFileNameHash(fileName) {
+ return fileName
+ .replace(paths.appBuild, '')
+ .replace(/\/?(.*)(\.\w+)(\.js|\.css)/, (match, p1, p2, p3) => p1 + p3);
+}
+
+// Input: 1024, 2048
+// Output: "(+1 KB)"
+function getDifferenceLabel(currentSize, previousSize) {
+ var FIFTY_KILOBYTES = 1024 * 50;
+ var difference = currentSize - previousSize;
+ var fileSize = !Number.isNaN(difference) ? filesize(difference) : 0;
+ if (difference >= FIFTY_KILOBYTES) {
+ return chalk.red('+' + fileSize);
+ } else if (difference < FIFTY_KILOBYTES && difference > 0) {
+ return chalk.yellow('+' + fileSize);
+ } else if (difference < 0) {
+ return chalk.green(fileSize);
+ } else {
+ return '';
+ }
+}
+
+// First, read the current file sizes in build directory.
+// This lets us display how much they changed later.
+recursive(paths.appBuild, (err, fileNames) => {
+ var previousSizeMap = (fileNames || [])
+ .filter(fileName => /\.(js|css)$/.test(fileName))
+ .reduce((memo, fileName) => {
+ var contents = fs.readFileSync(fileName);
+ var key = removeFileNameHash(fileName);
+ memo[key] = gzipSize(contents);
+ return memo;
+ }, {});
+
+ // Remove all content but keep the directory so that
+ // if you're in it, you don't end up in Trash
+ rimrafSync(paths.appBuild + '/*');
+
+ // Start the webpack build
+ build(previousSizeMap);
+
+ // Merge with the public folder
+ copyPublicFolder();
+});
+
+// Print a detailed summary of build files.
+function printFileSizes(stats, previousSizeMap) {
+ var assets = stats.toJson().assets
+ .filter(asset => /\.(js|css)$/.test(asset.name))
+ .map(asset => {
+ var fileContents = fs.readFileSync(paths.appBuild + '/' + asset.name);
+ var size = gzipSize(fileContents);
+ var previousSize = previousSizeMap[removeFileNameHash(asset.name)];
+ var difference = getDifferenceLabel(size, previousSize);
+ return {
+ folder: path.join('build', path.dirname(asset.name)),
+ name: path.basename(asset.name),
+ size: size,
+ sizeLabel: filesize(size) + (difference ? ' (' + difference + ')' : '')
+ };
+ });
+ assets.sort((a, b) => b.size - a.size);
+ var longestSizeLabelLength = Math.max.apply(null,
+ assets.map(a => stripAnsi(a.sizeLabel).length)
+ );
+ assets.forEach(asset => {
+ var sizeLabel = asset.sizeLabel;
+ var sizeLength = stripAnsi(sizeLabel).length;
+ if (sizeLength < longestSizeLabelLength) {
+ var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength);
+ sizeLabel += rightPadding;
+ }
+ console.log(
+ ' ' + sizeLabel +
+ ' ' + chalk.dim(asset.folder + path.sep) + chalk.cyan(asset.name)
+ );
+ });
+}
+
+// Print out errors
+function printErrors(summary, errors) {
+ console.log(chalk.red(summary));
+ console.log();
+ errors.forEach(err => {
+ console.log(err.message || err);
+ console.log();
+ });
+}
+
+// Create the production build and print the deployment instructions.
+function build(previousSizeMap) {
+ console.log('Creating an optimized production build...');
+ webpack(config).run((err, stats) => {
+ if (err) {
+ printErrors('Failed to compile.', [err]);
+ process.exit(1);
+ }
+
+ if (stats.compilation.errors.length) {
+ printErrors('Failed to compile.', stats.compilation.errors);
+ process.exit(1);
+ }
+
+ console.log(chalk.green('Compiled successfully.'));
+ console.log();
+
+ console.log('File sizes after gzip:');
+ console.log();
+ printFileSizes(stats, previousSizeMap);
+ console.log();
+
+ var openCommand = process.platform === 'win32' ? 'start' : 'open';
+ var homepagePath = require(paths.appPackageJson).homepage;
+ var publicPath = config.output.publicPath;
+ if (homepagePath && homepagePath.indexOf('.github.io/') !== -1) {
+ // "homepage": "http://user.github.io/project"
+ console.log('The project was built assuming it is hosted at ' + chalk.green(publicPath) + '.');
+ console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.');
+ console.log();
+ 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.cyan('npm') + ' install --save-dev gh-pages');
+ console.log();
+ console.log('Add the following script in your ' + chalk.cyan('package.json') + '.');
+ console.log();
+ console.log(' ' + chalk.dim('// ...'));
+ console.log(' ' + chalk.yellow('"scripts"') + ': {');
+ console.log(' ' + chalk.dim('// ...'));
+ console.log(' ' + chalk.yellow('"deploy"') + ': ' + chalk.yellow('"gh-pages -d build"'));
+ console.log(' }');
+ console.log();
+ console.log('Then run:');
+ console.log();
+ console.log(' ' + chalk.cyan('npm') + ' run deploy');
+ console.log();
+ } else if (publicPath !== '/') {
+ // "homepage": "http://mywebsite.com/project"
+ console.log('The project was built assuming it is hosted at ' + chalk.green(publicPath) + '.');
+ console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.');
+ console.log();
+ console.log('The ' + chalk.cyan('build') + ' folder is ready to be deployed.');
+ console.log();
+ } else {
+ // no homepage or "homepage": "http://mywebsite.com"
+ console.log('The project was built assuming it is hosted at the server root.');
+ if (homepagePath) {
+ // "homepage": "http://mywebsite.com"
+ console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.');
+ console.log();
+ } else {
+ // no homepage
+ console.log('To override this, specify the ' + chalk.green('homepage') + ' in your ' + chalk.cyan('package.json') + '.');
+ console.log('For example, add this to build it for GitHub Pages:')
+ console.log();
+ console.log(' ' + chalk.green('"homepage"') + chalk.cyan(': ') + chalk.green('"http://myname.github.io/myapp"') + chalk.cyan(','));
+ console.log();
+ }
+ 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.cyan('npm') + ' install -g pushstate-server');
+ console.log(' ' + chalk.cyan('pushstate-server') + ' build');
+ console.log(' ' + chalk.cyan(openCommand) + ' http://localhost:9000');
+ console.log();
+ }
+ });
+}
+
+function copyPublicFolder() {
+ fs.copySync(paths.appPublic, paths.appBuild, {
+ dereference: true,
+ filter: file => file !== paths.appHtml
+ });
+}
diff --git a/scripts/start.js b/scripts/start.js
new file mode 100644
index 0000000..4e8e4d2
--- /dev/null
+++ b/scripts/start.js
@@ -0,0 +1,268 @@
+process.env.NODE_ENV = 'development';
+
+// Load environment variables from .env file. Suppress warnings using silent
+// if this file is missing. dotenv will never modify any environment variables
+// that have already been set.
+// https://github.com/motdotla/dotenv
+require('dotenv').config({silent: true});
+
+var chalk = require('chalk');
+var webpack = require('webpack');
+var WebpackDevServer = require('webpack-dev-server');
+var historyApiFallback = require('connect-history-api-fallback');
+var httpProxyMiddleware = require('http-proxy-middleware');
+var detect = require('detect-port');
+var clearConsole = require('react-dev-utils/clearConsole');
+var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
+var formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
+var openBrowser = require('react-dev-utils/openBrowser');
+var prompt = require('react-dev-utils/prompt');
+var config = require('../config/webpack.config.dev');
+var paths = require('../config/paths');
+
+// Warn and crash if required files are missing
+if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
+ process.exit(1);
+}
+
+// Tools like Cloud9 rely on this.
+var DEFAULT_PORT = process.env.PORT || 3000;
+var compiler;
+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) {
+ if (err || stats.hasErrors() || stats.hasWarnings()) {
+ process.exit(1);
+ } else {
+ process.exit(0);
+ }
+ };
+}
+
+function setupCompiler(host, 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);
+
+ // "invalid" event fires when you have changed a file, and Webpack is
+ // recompiling a bundle. WebpackDevServer takes care to pause serving the
+ // bundle, so if you refresh, it'll wait instead of serving the old one.
+ // "invalid" is short for "bundle invalidated", it doesn't imply any errors.
+ compiler.plugin('invalid', function() {
+ clearConsole();
+ console.log('Compiling...');
+ });
+
+ // "done" event fires when Webpack has finished recompiling the bundle.
+ // Whether or not you have warnings or errors, you will get this event.
+ compiler.plugin('done', function(stats) {
+ clearConsole();
+
+ // 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 messages = formatWebpackMessages(stats.toJson({}, true));
+ if (!messages.errors.length && !messages.warnings.length) {
+ console.log(chalk.green('Compiled successfully!'));
+ console.log();
+ console.log('The app is running at:');
+ console.log();
+ console.log(' ' + chalk.cyan(protocol + '://' + host + ':' + 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') + '.');
+ console.log();
+ }
+
+ // If errors exist, only show errors.
+ if (messages.errors.length) {
+ console.log(chalk.red('Failed to compile.'));
+ console.log();
+ messages.errors.forEach(message => {
+ console.log(message);
+ console.log();
+ });
+ return;
+ }
+
+ // Show warnings if no errors were found.
+ if (messages.warnings.length) {
+ console.log(chalk.yellow('Compiled with warnings.'));
+ console.log();
+ messages.warnings.forEach(message => {
+ console.log(message);
+ console.log();
+ });
+ // Teach some ESLint tricks.
+ console.log('You may use special comments to disable some warnings.');
+ console.log('Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.');
+ console.log('Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.');
+ }
+ });
+}
+
+// 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) {
+ // `proxy` lets you to specify a fallback server during development.
+ // Every unrecognized request will be forwarded to it.
+ var proxy = require(paths.appPackageJson).proxy;
+ devServer.use(historyApiFallback({
+ // Paths with dots should still use the history fallback.
+ // See https://github.com/facebookincubator/create-react-app/issues/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.
+ // We use a heuristic: if request `accept`s text/html, we pick /index.html.
+ // Modern browsers include text/html into `accept` header when navigating.
+ // However API calls like `fetch()` won’t generally accept text/html.
+ // If this heuristic doesn’t work well for you, don’t use `proxy`.
+ htmlAcceptHeaders: proxy ?
+ ['text/html'] :
+ ['text/html', '*/*']
+ }));
+ if (proxy) {
+ if (typeof proxy !== 'string') {
+ console.log(chalk.red('When specified, "proxy" in package.json must be a string.'));
+ console.log(chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".'));
+ console.log(chalk.red('Either remove "proxy" from package.json, or make it a string.'));
+ process.exit(1);
+ }
+
+ // Otherwise, if proxy is specified, we will let it handle any request.
+ // There are a few exceptions which we won't send to the proxy:
+ // - /index.html (served as HTML5 history API fallback)
+ // - /*.hot-update.json (WebpackDevServer uses this too for hot reloading)
+ // - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
+ // Tip: use https://jex.im/regulex/ to visualize the regex
+ var mayProxy = /^(?!\/(index\.html$|.*\.hot-update\.json$|sockjs-node\/)).*$/;
+ devServer.use(mayProxy,
+ // Pass the scope regex both to Express and to the middleware for proxying
+ // of both HTTP and WebSockets to work without false positives.
+ httpProxyMiddleware(pathname => mayProxy.test(pathname), {
+ target: proxy,
+ logLevel: 'silent',
+ onError: onProxyError(proxy),
+ secure: false,
+ changeOrigin: true
+ })
+ );
+ }
+ // Finally, by now we have certainly resolved the URL.
+ // It may be /index.html, so let the dev server try serving it again.
+ devServer.use(devServer.middleware);
+}
+
+function runDevServer(host, port, protocol) {
+ var devServer = new WebpackDevServer(compiler, {
+ // Silence WebpackDevServer's own logs since they're generally not useful.
+ // It will still show compile warnings and errors with this setting.
+ clientLogLevel: 'none',
+ // By default WebpackDevServer serves physical files from current directory
+ // in addition to all the virtual build products that it serves from memory.
+ // This is confusing because those files won’t automatically be available in
+ // production build folder unless we copy them. However, copying the whole
+ // project directory is dangerous because we may expose sensitive files.
+ // Instead, we establish a convention that only files in `public` directory
+ // get served. Our build script will copy `public` into the `build` folder.
+ // In `index.html`, you can get URL of `public` folder with %PUBLIC_PATH%:
+ // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
+ // In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
+ // Note that we only recommend to use `public` folder as an escape hatch
+ // for files like `favicon.ico`, `manifest.json`, and libraries that are
+ // for some reason broken when imported through Webpack. If you just want to
+ // use an image, put it in `src` and `import` it from JavaScript instead.
+ contentBase: paths.appPublic,
+ // 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
+ // in the Webpack development configuration. Note that only changes
+ // to CSS are currently hot reloaded. JS changes will refresh the browser.
+ hot: true,
+ // It is important to tell WebpackDevServer to use the same "root" path
+ // as we specified in the config. In development, we always serve from /.
+ publicPath: config.output.publicPath,
+ // WebpackDevServer is noisy by default so we emit custom message instead
+ // by listening to the compiler events with `compiler.plugin` calls above.
+ quiet: true,
+ // Reportedly, this avoids CPU overload on some systems.
+ // 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",
+ host: host
+ });
+
+ // Our custom middleware proxies requests to /index.html or a remote API.
+ addMiddleware(devServer);
+
+ // Launch WebpackDevServer.
+ devServer.listen(port, (err, result) => {
+ if (err) {
+ return console.log(err);
+ }
+
+ clearConsole();
+ console.log(chalk.cyan('Starting the development server...'));
+ console.log();
+ openBrowser(protocol + '://' + host + ':' + port + '/');
+ });
+}
+
+function run(port) {
+ var protocol = process.env.HTTPS === 'true' ? "https" : "http";
+ var host = process.env.HOST || 'localhost';
+ setupCompiler(host, port, protocol);
+ runDevServer(host, port, protocol);
+}
+
+// We attempt to use the default port but if it is busy, we offer the user to
+// run on a different port. `detect()` Promise resolves to the next free port.
+detect(DEFAULT_PORT).then(port => {
+ if (port === DEFAULT_PORT) {
+ run(port);
+ return;
+ }
+
+ clearConsole();
+ var question =
+ 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) {
+ run(port);
+ }
+ });
+});
diff --git a/scripts/test.js b/scripts/test.js
new file mode 100644
index 0000000..aec2050
--- /dev/null
+++ b/scripts/test.js
@@ -0,0 +1,19 @@
+process.env.NODE_ENV = 'test';
+process.env.PUBLIC_URL = '';
+
+// Load environment variables from .env file. Suppress warnings using silent
+// if this file is missing. dotenv will never modify any environment variables
+// that have already been set.
+// https://github.com/motdotla/dotenv
+require('dotenv').config({silent: true});
+
+const jest = require('jest');
+const argv = process.argv.slice(2);
+
+// Watch unless on CI
+if (!process.env.CI) {
+ argv.push('--watch');
+}
+
+
+jest.run(argv);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment