Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Adding a staging environment to create webpack staging builds.
  • Loading branch information
Edo committed Oct 4, 2016
1 parent 38a1f27 commit f46a890
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
build
staging
.DS_Store
*.tgz
my-app*
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"e2e": "tasks/e2e.sh",
"postinstall": "lerna bootstrap",
"publish": "tasks/release.sh",
"stage": "node packages/react-scripts/scripts/stage.js",
"start": "node packages/react-scripts/scripts/start.js",
"test": "node packages/react-scripts/scripts/test.js --env=jsdom"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/babel-preset-react-app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ module.exports = {
// https://github.com/facebookincubator/create-react-app/issues/720
// It’s also nice that we can enforce `NODE_ENV` being specified.
var env = process.env.BABEL_ENV || process.env.NODE_ENV;
if (env !== 'development' && env !== 'test' && env !== 'production') {
if (env !== 'development' && env !== 'test' && env !== 'production' && env !== 'staging') {
throw new Error(
'Using `babel-preset-react-app` requires that you specify `NODE_ENV` or '+
'`BABEL_ENV` environment variables. Valid values are "development", ' +
'"test", and "production". Instead, received: ' + JSON.stringify(env) + '.'
'"test", "staging", and "production". Instead, received: ' + JSON.stringify(env) + '.'
);
}
var plugins = module.exports.plugins;
Expand All @@ -61,7 +61,7 @@ if (env === 'development' || env === 'test') {
require.resolve('babel-plugin-transform-react-jsx-self')
]);
}
if (env === 'production') {
if (env === 'production' || env === 'staging') {
// Optimization: hoist JSX that never changes out of render()
// Disabled because of issues:
// * https://github.com/facebookincubator/create-react-app/issues/525
Expand Down
1 change: 1 addition & 0 deletions packages/react-scripts/bin/react-scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var args = process.argv.slice(3);

switch (script) {
case 'build':
case 'stage':
case 'eject':
case 'start':
case 'test':
Expand Down
3 changes: 3 additions & 0 deletions packages/react-scripts/config/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var nodePaths = (process.env.NODE_PATH || '')
// config after eject: we're in ./config/
module.exports = {
appBuild: resolveApp('build'),
appStaging: resolveApp('staging'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveApp('src/index.js'),
Expand All @@ -57,6 +58,7 @@ function resolveOwn(relativePath) {
// config before eject: we're in ./node_modules/react-scripts/config/
module.exports = {
appBuild: resolveApp('build'),
appStaging: resolveApp('staging'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveApp('src/index.js'),
Expand All @@ -73,6 +75,7 @@ module.exports = {
// @remove-on-publish-begin
module.exports = {
appBuild: resolveOwn('../../../build'),
appStaging: resolveOwn('../../../staging'),
appPublic: resolveOwn('../template/public'),
appHtml: resolveOwn('../template/public/index.html'),
appIndexJs: resolveOwn('../template/src/index.js'),
Expand Down
5 changes: 0 additions & 5 deletions packages/react-scripts/config/webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,6 @@ 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.
Expand Down
28 changes: 28 additions & 0 deletions packages/react-scripts/config/webpack.config.staging.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// @remove-on-eject-begin
/**
* 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.
*/
// @remove-on-eject-end

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var paths = require('./paths');
var config = require('./webpack.config.prod');

module.exports = Object.assign(config, {
output: Object.assign(config.output, {
path: paths.appStaging,
}),
plugins: [new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml
})].concat(config.plugins.filter(plugin =>
!(plugin instanceof webpack.optimize.UglifyJsPlugin) &&
!(plugin instanceof HtmlWebpackPlugin)
))
});
95 changes: 95 additions & 0 deletions packages/react-scripts/scripts/stage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// @remove-on-eject-begin
/**
* 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.
*/
// @remove-on-eject-end

// Do this as the first thing so that any code reading it knows the right env.
process.env.NODE_ENV = 'staging';

// 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 rimrafSync = require('rimraf').sync;
var webpack = require('webpack');
var config = require('../config/webpack.config.staging');
var paths = require('../config/paths');
var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
var recursive = require('recursive-readdir');

// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}

recursive(paths.appStaging, (err, fileNames) => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
rimrafSync(paths.appStaging + '/*');

// Start the webpack build
build();

// Merge with the public folder
copyPublicFolder();
});


// Create the staging build and print the deployment instructions.
function build() {
console.log('Creating a staging build...');
webpack(config).run((err, stats) => {
if (err) {
console.error('Failed to create a staging build. Reason:');
console.error(err.message || err);
process.exit(1);
}

console.log(chalk.green('Compiled successfully.'));
console.log();

var openCommand = process.platform === 'win32' ? 'start' : 'open';
var homepagePath = require(paths.appPackageJson).homepage;
var publicPath = config.output.publicPath;
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('staging') + ' 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();
}
console.log('The ' + chalk.cyan('staging') + ' 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') + ' staging');
console.log(' ' + chalk.cyan(openCommand) + ' http://localhost:9000');
console.log();
}
});
}

function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appStaging, {
dereference: true,
filter: file => file !== paths.appHtml
});
}

0 comments on commit f46a890

Please sign in to comment.