Skip to content

Commit f46a890

Browse files
author
Edo
committed
Adding a staging environment to create webpack staging builds.
1 parent 38a1f27 commit f46a890

File tree

8 files changed

+132
-8
lines changed

8 files changed

+132
-8
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
node_modules/
22
build
3+
staging
34
.DS_Store
45
*.tgz
56
my-app*

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"e2e": "tasks/e2e.sh",
77
"postinstall": "lerna bootstrap",
88
"publish": "tasks/release.sh",
9+
"stage": "node packages/react-scripts/scripts/stage.js",
910
"start": "node packages/react-scripts/scripts/start.js",
1011
"test": "node packages/react-scripts/scripts/test.js --env=jsdom"
1112
},

packages/babel-preset-react-app/index.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ module.exports = {
4545
// https://github.com/facebookincubator/create-react-app/issues/720
4646
// It’s also nice that we can enforce `NODE_ENV` being specified.
4747
var env = process.env.BABEL_ENV || process.env.NODE_ENV;
48-
if (env !== 'development' && env !== 'test' && env !== 'production') {
48+
if (env !== 'development' && env !== 'test' && env !== 'production' && env !== 'staging') {
4949
throw new Error(
5050
'Using `babel-preset-react-app` requires that you specify `NODE_ENV` or '+
5151
'`BABEL_ENV` environment variables. Valid values are "development", ' +
52-
'"test", and "production". Instead, received: ' + JSON.stringify(env) + '.'
52+
'"test", "staging", and "production". Instead, received: ' + JSON.stringify(env) + '.'
5353
);
5454
}
5555
var plugins = module.exports.plugins;
@@ -61,7 +61,7 @@ if (env === 'development' || env === 'test') {
6161
require.resolve('babel-plugin-transform-react-jsx-self')
6262
]);
6363
}
64-
if (env === 'production') {
64+
if (env === 'production' || env === 'staging') {
6565
// Optimization: hoist JSX that never changes out of render()
6666
// Disabled because of issues:
6767
// * https://github.com/facebookincubator/create-react-app/issues/525

packages/react-scripts/bin/react-scripts.js

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var args = process.argv.slice(3);
55

66
switch (script) {
77
case 'build':
8+
case 'stage':
89
case 'eject':
910
case 'start':
1011
case 'test':

packages/react-scripts/config/paths.js

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ var nodePaths = (process.env.NODE_PATH || '')
3838
// config after eject: we're in ./config/
3939
module.exports = {
4040
appBuild: resolveApp('build'),
41+
appStaging: resolveApp('staging'),
4142
appPublic: resolveApp('public'),
4243
appHtml: resolveApp('public/index.html'),
4344
appIndexJs: resolveApp('src/index.js'),
@@ -57,6 +58,7 @@ function resolveOwn(relativePath) {
5758
// config before eject: we're in ./node_modules/react-scripts/config/
5859
module.exports = {
5960
appBuild: resolveApp('build'),
61+
appStaging: resolveApp('staging'),
6062
appPublic: resolveApp('public'),
6163
appHtml: resolveApp('public/index.html'),
6264
appIndexJs: resolveApp('src/index.js'),
@@ -73,6 +75,7 @@ module.exports = {
7375
// @remove-on-publish-begin
7476
module.exports = {
7577
appBuild: resolveOwn('../../../build'),
78+
appStaging: resolveOwn('../../../staging'),
7679
appPublic: resolveOwn('../template/public'),
7780
appHtml: resolveOwn('../template/public/index.html'),
7881
appIndexJs: resolveOwn('../template/src/index.js'),

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

-5
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@ var publicUrl = ensureSlash(homepagePathname, false);
4747
// Get environment variables to inject into our app.
4848
var env = getClientEnvironment(publicUrl);
4949

50-
// Assert this just to be safe.
51-
// Development builds of React are slow and not intended for production.
52-
if (env['process.env'].NODE_ENV !== '"production"') {
53-
throw new Error('Production builds must have NODE_ENV=production.');
54-
}
5550

5651
// This is the production configuration.
5752
// It compiles slowly and is focused on producing a fast and minimal bundle.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// @remove-on-eject-begin
2+
/**
3+
* Copyright (c) 2015-present, Facebook, Inc.
4+
* All rights reserved.
5+
*
6+
* This source code is licensed under the BSD-style license found in the
7+
* LICENSE file in the root directory of this source tree. An additional grant
8+
* of patent rights can be found in the PATENTS file in the same directory.
9+
*/
10+
// @remove-on-eject-end
11+
12+
var webpack = require('webpack');
13+
var HtmlWebpackPlugin = require('html-webpack-plugin');
14+
var paths = require('./paths');
15+
var config = require('./webpack.config.prod');
16+
17+
module.exports = Object.assign(config, {
18+
output: Object.assign(config.output, {
19+
path: paths.appStaging,
20+
}),
21+
plugins: [new HtmlWebpackPlugin({
22+
inject: true,
23+
template: paths.appHtml
24+
})].concat(config.plugins.filter(plugin =>
25+
!(plugin instanceof webpack.optimize.UglifyJsPlugin) &&
26+
!(plugin instanceof HtmlWebpackPlugin)
27+
))
28+
});
+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// @remove-on-eject-begin
2+
/**
3+
* Copyright (c) 2015-present, Facebook, Inc.
4+
* All rights reserved.
5+
*
6+
* This source code is licensed under the BSD-style license found in the
7+
* LICENSE file in the root directory of this source tree. An additional grant
8+
* of patent rights can be found in the PATENTS file in the same directory.
9+
*/
10+
// @remove-on-eject-end
11+
12+
// Do this as the first thing so that any code reading it knows the right env.
13+
process.env.NODE_ENV = 'staging';
14+
15+
// Load environment variables from .env file. Suppress warnings using silent
16+
// if this file is missing. dotenv will never modify any environment variables
17+
// that have already been set.
18+
// https://github.com/motdotla/dotenv
19+
require('dotenv').config({silent: true});
20+
21+
var chalk = require('chalk');
22+
var fs = require('fs-extra');
23+
var rimrafSync = require('rimraf').sync;
24+
var webpack = require('webpack');
25+
var config = require('../config/webpack.config.staging');
26+
var paths = require('../config/paths');
27+
var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
28+
var recursive = require('recursive-readdir');
29+
30+
// Warn and crash if required files are missing
31+
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
32+
process.exit(1);
33+
}
34+
35+
recursive(paths.appStaging, (err, fileNames) => {
36+
// Remove all content but keep the directory so that
37+
// if you're in it, you don't end up in Trash
38+
rimrafSync(paths.appStaging + '/*');
39+
40+
// Start the webpack build
41+
build();
42+
43+
// Merge with the public folder
44+
copyPublicFolder();
45+
});
46+
47+
48+
// Create the staging build and print the deployment instructions.
49+
function build() {
50+
console.log('Creating a staging build...');
51+
webpack(config).run((err, stats) => {
52+
if (err) {
53+
console.error('Failed to create a staging build. Reason:');
54+
console.error(err.message || err);
55+
process.exit(1);
56+
}
57+
58+
console.log(chalk.green('Compiled successfully.'));
59+
console.log();
60+
61+
var openCommand = process.platform === 'win32' ? 'start' : 'open';
62+
var homepagePath = require(paths.appPackageJson).homepage;
63+
var publicPath = config.output.publicPath;
64+
if (publicPath !== '/') {
65+
// "homepage": "http://mywebsite.com/project"
66+
console.log('The project was built assuming it is hosted at ' + chalk.green(publicPath) + '.');
67+
console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.');
68+
console.log();
69+
console.log('The ' + chalk.cyan('staging') + ' folder is ready to be deployed.');
70+
console.log();
71+
} else {
72+
// no homepage or "homepage": "http://mywebsite.com"
73+
console.log('The project was built assuming it is hosted at the server root.');
74+
if (homepagePath) {
75+
// "homepage": "http://mywebsite.com"
76+
console.log('You can control this with the ' + chalk.green('homepage') + ' field in your ' + chalk.cyan('package.json') + '.');
77+
console.log();
78+
}
79+
console.log('The ' + chalk.cyan('staging') + ' folder is ready to be deployed.');
80+
console.log('You may also serve it locally with a static server:')
81+
console.log();
82+
console.log(' ' + chalk.cyan('npm') + ' install -g pushstate-server');
83+
console.log(' ' + chalk.cyan('pushstate-server') + ' staging');
84+
console.log(' ' + chalk.cyan(openCommand) + ' http://localhost:9000');
85+
console.log();
86+
}
87+
});
88+
}
89+
90+
function copyPublicFolder() {
91+
fs.copySync(paths.appPublic, paths.appStaging, {
92+
dereference: true,
93+
filter: file => file !== paths.appHtml
94+
});
95+
}

0 commit comments

Comments
 (0)