diff --git a/config/babel.dev.js b/config/babel.dev.js index 64545127d07..16e4ce0f256 100644 --- a/config/babel.dev.js +++ b/config/babel.dev.js @@ -9,7 +9,6 @@ module.exports = { babelrc: false, - cacheDirectory: true, presets: [ 'babel-preset-es2015', 'babel-preset-es2016', diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js deleted file mode 100644 index 949e9465fcd..00000000000 --- a/config/webpack.config.dev.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * 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. - */ - -var path = require('path'); -var autoprefixer = require('autoprefixer'); -var webpack = require('webpack'); -var HtmlWebpackPlugin = require('html-webpack-plugin'); -var paths = require('./paths'); - -module.exports = { - devtool: 'eval', - entry: [ - require.resolve('webpack-dev-server/client'), - require.resolve('webpack/hot/dev-server'), - require.resolve('./polyfills'), - path.join(paths.appSrc, 'index') - ], - output: { - // Next line is not used in dev but WebpackDevServer crashes without it: - path: paths.appBuild, - pathinfo: true, - filename: 'bundle.js', - publicPath: '/' - }, - resolve: { - extensions: ['', '.js', '.json'], - 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') - } - }, - resolveLoader: { - root: paths.ownNodeModules, - moduleTemplates: ['*-loader'] - }, - module: { - preLoaders: [ - { - test: /\.js$/, - loader: 'eslint', - include: paths.appSrc, - } - ], - loaders: [ - { - test: /\.js$/, - include: paths.appSrc, - loader: 'babel', - query: require('./babel.dev') - }, - { - test: /\.css$/, - include: [paths.appSrc, paths.appNodeModules], - loader: 'style!css!postcss' - }, - { - test: /\.json$/, - include: [paths.appSrc, paths.appNodeModules], - loader: 'json' - }, - { - test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)$/, - include: [paths.appSrc, paths.appNodeModules], - loader: 'file', - }, - { - test: /\.(mp4|webm)$/, - include: [paths.appSrc, paths.appNodeModules], - loader: 'url?limit=10000' - } - ] - }, - eslint: { - configFile: path.join(__dirname, 'eslint.js'), - useEslintrc: false - }, - postcss: function() { - return [autoprefixer]; - }, - plugins: [ - new HtmlWebpackPlugin({ - inject: true, - template: paths.appHtml, - favicon: paths.appFavicon, - }), - new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"development"' }), - // Note: only CSS is currently hot reloaded - new webpack.HotModuleReplacementPlugin() - ] -}; diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js deleted file mode 100644 index e085c274649..00000000000 --- a/config/webpack.config.prod.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * 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. - */ - -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 url = require('url'); -var paths = require('./paths'); - -var homepagePath = require(paths.appPackageJson).homepage; -var publicPath = homepagePath ? url.parse(homepagePath).pathname : '/'; -if (!publicPath.endsWith('/')) { - // Prevents incorrect paths in file-loader - publicPath += '/'; -} - -module.exports = { - bail: true, - devtool: 'source-map', - entry: [ - require.resolve('./polyfills'), - path.join(paths.appSrc, 'index') - ], - output: { - path: paths.appBuild, - filename: '[name].[chunkhash:8].js', - chunkFilename: '[name].[chunkhash:8].chunk.js', - publicPath: publicPath - }, - resolve: { - extensions: ['', '.js', '.json'], - 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') - } - }, - resolveLoader: { - root: paths.ownNodeModules, - moduleTemplates: ['*-loader'] - }, - module: { - preLoaders: [ - { - test: /\.js$/, - loader: 'eslint', - include: paths.appSrc - } - ], - loaders: [ - { - test: /\.js$/, - include: paths.appSrc, - loader: 'babel', - query: require('./babel.prod') - }, - { - test: /\.css$/, - include: [paths.appSrc, paths.appNodeModules], - // Disable autoprefixer in css-loader itself: - // https://github.com/webpack/css-loader/issues/281 - // We already have it thanks to postcss. - loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss') - }, - { - test: /\.json$/, - include: [paths.appSrc, paths.appNodeModules], - loader: 'json' - }, - { - test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)$/, - include: [paths.appSrc, paths.appNodeModules], - loader: 'file', - query: { - name: '[name].[hash:8].[ext]' - } - }, - { - test: /\.(mp4|webm)$/, - include: [paths.appSrc, paths.appNodeModules], - loader: 'url?limit=10000' - } - ] - }, - eslint: { - // TODO: consider separate config for production, - // e.g. to enable no-console and no-debugger only in prod. - configFile: path.join(__dirname, 'eslint.js'), - useEslintrc: false - }, - postcss: function() { - return [autoprefixer]; - }, - plugins: [ - new HtmlWebpackPlugin({ - inject: true, - template: paths.appHtml, - favicon: paths.appFavicon, - minify: { - removeComments: true, - collapseWhitespace: true, - removeRedundantAttributes: true, - useShortDoctype: true, - removeEmptyAttributes: true, - removeStyleLinkTypeAttributes: true, - keepClosingSlash: true, - minifyJS: true, - minifyCSS: true, - minifyURLs: true - } - }), - new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }), - new webpack.optimize.OccurrenceOrderPlugin(), - new webpack.optimize.DedupePlugin(), - new webpack.optimize.UglifyJsPlugin({ - compressor: { - screw_ie8: true, - warnings: false - }, - mangle: { - screw_ie8: true - }, - output: { - comments: false, - screw_ie8: true - } - }), - new ExtractTextPlugin('[name].[contenthash:8].css') - ] -}; diff --git a/package.json b/package.json index c4999d12558..9d380cea3f8 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "autoprefixer": "6.3.7", "babel-core": "6.11.4", "babel-eslint": "6.1.2", - "babel-loader": "6.2.4", "babel-plugin-syntax-trailing-function-commas": "6.8.0", "babel-plugin-transform-class-properties": "6.11.5", "babel-plugin-transform-object-rest-spread": "6.8.0", @@ -39,32 +38,24 @@ "babel-preset-es2015": "6.9.0", "babel-preset-es2016": "6.11.3", "babel-preset-react": "6.11.1", + "babel-pundle": "1.0.0", "babel-runtime": "6.11.6", "chalk": "1.1.3", "cross-spawn": "4.0.0", - "css-loader": "0.23.1", "detect-port": "0.1.4", "eslint": "3.1.1", - "eslint-loader": "1.4.1", "eslint-plugin-flow-vars": "0.5.0", "eslint-plugin-import": "1.12.0", "eslint-plugin-jsx-a11y": "2.0.1", "eslint-plugin-react": "5.2.2", - "extract-text-webpack-plugin": "1.0.1", - "file-loader": "0.9.0", - "filesize": "3.3.0", "fs-extra": "0.30.0", - "gzip-size": "3.0.0", - "html-webpack-plugin": "2.22.0", - "json-loader": "0.5.4", + "mkdirp": "^0.5.1", "opn": "4.0.2", - "postcss-loader": "0.9.1", + "process-bootstrap": "1.0.0", "promise": "7.1.1", + "pundle": "1.1.0", + "pundle-dev": "1.1.0", "rimraf": "2.5.4", - "style-loader": "0.13.1", - "url-loader": "0.5.7", - "webpack": "1.13.1", - "webpack-dev-server": "1.14.1", "whatwg-fetch": "1.0.0" }, "devDependencies": { diff --git a/scripts/build.js b/scripts/build.js index 7642ce3f418..bf8576fd849 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -10,34 +10,50 @@ process.env.NODE_ENV = 'production'; var fs = require('fs'); -var filesize = require('filesize'); -var gzipSize = require('gzip-size'); +var path = require('path'); +var mkdirp = require('mkdirp') +var Pundle = require('pundle') var rimrafSync = require('rimraf').sync; -var webpack = require('webpack'); -var config = require('../config/webpack.config.prod'); var paths = require('../config/paths'); // Remove all content but keep the directory so that // if you're in it, you don't end up in Trash rimrafSync(paths.appBuild + '/*'); -function logBuildSize(assets, extension) { - for (var i = 0; i < assets.length; i++) { - var asset = assets[i]; - if (asset.name.endsWith('.' + extension)) { - var fileContents = fs.readFileSync(paths.appBuild + '/' + asset.name); - console.log('Size (gzipped) of ' + asset.name + ': ' + filesize(gzipSize.sync(fileContents))); - } - } -} - -webpack(config).run(function(err, stats) { - if (err) { - console.error('Failed to create a production build. Reason:'); - console.error(err.message || err); - process.exit(1); - } +var pundle = new Pundle({ + entry: [require.resolve('../config/polyfills'), 'index.js'], + rootDirectory: path.normalize(path.join(__dirname, '../template/src')), + pathType: 'filePath', + moduleDirectories: ['node_modules'], +}) +pundle.loadPlugins([ + [require.resolve('babel-pundle'), { + config: require('../config/babel.prod'), + }], +]).then(function() { + return pundle.compile() +}).then(function() { + return new Promise(function(resolve, reject) { + mkdirp(paths.appBuild, function(error) { + if (error) { + reject(error) + } else { + resolve() + } + }) + }) +}).then(function() { + return new Promise(function(resolve, reject) { + fs.writeFile(path.join(paths.appBuild, 'bundle.js'), pundle.generate().contents, function(error) { + if (error) { + reject(error) + } else { + resolve() + } + }) + }) +}).then(function() { var openCommand = process.platform === 'win32' ? 'start' : 'open'; var homepagePath = require(paths.appPackageJson).homepage; console.log('Successfully generated a bundle in the build folder!'); @@ -61,9 +77,10 @@ webpack(config).run(function(err, stats) { console.log(' pushstate-server build'); console.log(' ' + openCommand + ' http://localhost:9000'); console.log(); - var assets = stats.toJson()['assets']; - logBuildSize(assets, 'js'); - logBuildSize(assets, 'css'); } console.log('The bundle is optimized and ready to be deployed to production.'); -}); +}, function(err) { + console.error('Failed to create a production build. Reason:'); + console.error(err.message || err); + process.exitCode = 1 +}) diff --git a/scripts/start.js b/scripts/start.js index 15243229d37..8648cef5e6d 100644 --- a/scripts/start.js +++ b/scripts/start.js @@ -9,184 +9,47 @@ process.env.NODE_ENV = 'development'; -var path = require('path'); -var chalk = require('chalk'); -var webpack = require('webpack'); -var WebpackDevServer = require('webpack-dev-server'); -var execSync = require('child_process').execSync; -var opn = require('opn'); -var detect = require('detect-port'); -var prompt = require('./utils/prompt'); -var config = require('../config/webpack.config.dev'); - -// 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; -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); - } - }; -} - -var friendlySyntaxErrorLabel = 'Syntax error:'; - -function isLikelyASyntaxError(message) { - return message.indexOf(friendlySyntaxErrorLabel) !== -1; -} - -// This is a little hacky. -// It would be easier if webpack provided a rich error object. - -function formatMessage(message) { - return message - // Make some common errors shorter: - .replace( - // Babel syntax error - 'Module build failed: SyntaxError:', - friendlySyntaxErrorLabel - ) - .replace( - // Webpack file not found error - /Module not found: Error: Cannot resolve 'file' or 'directory'/, - 'Module not found:' - ) - // Internal stacks are generally useless so we strip them - .replace(/^\s*at\s.*:\d+:\d+[\s\)]*\n/gm, '') // at ... ...:x:y - // Webpack loader names obscure CSS filenames - .replace('./~/css-loader!./~/postcss-loader!', ''); -} - -function clearConsole() { - process.stdout.write('\x1bc'); -} - -function setupCompiler(port) { - compiler = webpack(config, handleCompile); - - compiler.plugin('invalid', function() { - clearConsole(); - console.log('Compiling...'); - }); - - compiler.plugin('done', function(stats) { - clearConsole(); - var hasErrors = stats.hasErrors(); - var hasWarnings = stats.hasWarnings(); - if (!hasErrors && !hasWarnings) { - console.log(chalk.green('Compiled successfully!')); - console.log(); - console.log('The app is running at http://localhost:' + port + '/'); - console.log(); - return; - } - - var json = stats.toJson(); - var formattedErrors = json.errors.map(message => - 'Error in ' + formatMessage(message) - ); - var formattedWarnings = json.warnings.map(message => - 'Warning in ' + formatMessage(message) - ); - - if (hasErrors) { - console.log(chalk.red('Failed to compile.')); - console.log(); - if (formattedErrors.some(isLikelyASyntaxError)) { - // If there are any syntax errors, show just them. - // This prevents a confusing ESLint parsing error - // preceding a much more useful Babel syntax error. - formattedErrors = formattedErrors.filter(isLikelyASyntaxError); - } - formattedErrors.forEach(message => { - console.log(message); - console.log(); - }); - // If errors exist, ignore warnings. - return; - } - - if (hasWarnings) { - console.log(chalk.yellow('Compiled with warnings.')); - console.log(); - formattedWarnings.forEach(message => { - console.log(message); - console.log(); - }); - - 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.'); - } - }); -} - -function openBrowser(port) { - 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 ' + - path.resolve(__dirname, './utils/chrome.applescript') + - ' http://localhost:' + port + '/' - ); - return; - } catch (err) { - // Ignore errors. - } - } - // Fallback to opn - // (It will always open new tab) - opn('http://localhost:' + port + '/'); -} - -function runDevServer(port) { - new WebpackDevServer(compiler, { - historyApiFallback: true, - hot: true, // Note: only CSS is currently hot reloaded - publicPath: config.output.publicPath, - quiet: true - }).listen(port, (err, result) => { - if (err) { - return console.log(err); - } - - clearConsole(); - console.log(chalk.cyan('Starting the development server...')); - console.log(); - openBrowser(port); - }); -} - -function run(port) { - setupCompiler(port); - runDevServer(port); -} - -detect(DEFAULT_PORT).then(port => { - if (port === DEFAULT_PORT) { - run(port); - return; - } - - 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?'; - - prompt(question, true).then(shouldChangePort => { - if (shouldChangePort) { - run(port); - } - }); -}); +require('process-bootstrap')('react-app', 'REACT-APP') + +var Path = require('path'); +var debug = require('debug'); +var Server = require('pundle-dev'); +var debugInfo = debug('REACT-APP:Info'); +var debugError = debug('REACT-APP:Error'); + +var port = process.env.PORT || 3000; + +var server = new Server({ + pundle: { + entry: [require.resolve('../config/polyfills'), 'index.js'], + rootDirectory: Path.normalize(Path.join(__dirname, '../template/src')), + pathType: 'filePath', + moduleDirectories: ['node_modules'], + }, + server: { + port: port, + error: debugError, + ready() { + debugInfo('Ready') + }, + generated() { + debugInfo('Regenerated') + }, + hmr: true, + sourceMap: true, + sourceRoot: Path.normalize(Path.join(__dirname, '../template')), + }, + watcher: {}, + generator: { + sourceMap: true, + wrapper: 'hmr', + }, +}) + +server.pundle.loadPlugins([ + [require.resolve('babel-pundle'), { + config: require('../config/babel.dev'), + }], +]).then(function() { + return server.activate() +}).catch(debugError) diff --git a/template/index.html b/template/index.html index 72e10e94c6c..4d6799da4f5 100644 --- a/template/index.html +++ b/template/index.html @@ -7,6 +7,7 @@
+