Skip to content

Commit 9d7ead2

Browse files
committed
add watch script to react-scripts
1 parent db008e6 commit 9d7ead2

File tree

6 files changed

+540
-1
lines changed

6 files changed

+540
-1
lines changed

Diff for: package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"publish": "tasks/release.sh",
1010
"start": "node packages/react-scripts/scripts/start.js",
1111
"test": "node packages/react-scripts/scripts/test.js --env=jsdom",
12+
"watch": "node packages/react-scripts/scripts/watch.js",
1213
"format": "prettier --trailing-comma es5 --single-quote --write 'packages/*/*.js' 'packages/*/!(node_modules)/**/*.js'"
1314
},
1415
"devDependencies": {
@@ -17,4 +18,4 @@
1718
"lerna-changelog": "^0.2.3",
1819
"prettier": "^0.21.0"
1920
}
20-
}
21+
}

Diff for: packages/react-dev-utils/cleanBuildFolder.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"use strict";
2+
var recursive = require("recursive-readdir");
3+
var path = require("path");
4+
var fs = require("fs");
5+
var difference = require("lodash/difference");
6+
7+
module.exports = function cleanBuildFolder(appBuild, stats) {
8+
return new Promise(resolve => {
9+
// Read the current contents of build folder
10+
recursive(appBuild, (err, fileNames) => {
11+
var assets = stats.toJson().assets;
12+
var assetFileNames = assets
13+
.map(asset => path.join(appBuild, asset.name)) // Get the full path from stats
14+
.filter(Boolean);
15+
16+
// Check the differences in hash
17+
var differences = difference(fileNames,assetFileNames)
18+
.filter((names) => names.includes(path.join(appBuild, 'static')))
19+
// Only delete in the static folder
20+
21+
differences.forEach(file => {
22+
if (fs.existsSync(file)) {
23+
fs.unlinkSync(file);
24+
}
25+
});
26+
resolve(differences);
27+
});
28+
});
29+
};

Diff for: packages/react-dev-utils/isProduction.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
"use strict"
12+
module.exports = function isProduction(){
13+
return process.env.NODE_ENV === 'production'
14+
}
+303
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
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+
"use strict"
12+
var autoprefixer = require('autoprefixer');
13+
var webpack = require('webpack');
14+
var HtmlWebpackPlugin = require('html-webpack-plugin');
15+
var ExtractTextPlugin = require('extract-text-webpack-plugin');
16+
var ManifestPlugin = require('webpack-manifest-plugin');
17+
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
18+
var paths = require('./paths');
19+
var getClientEnvironment = require('./env');
20+
var isProduction = require('react-dev-utils/isProduction');
21+
22+
// @remove-on-eject-begin
23+
// `path` is not used after eject - see https://github.com/facebookincubator/create-react-app/issues/1174
24+
var path = require('path');
25+
// @remove-on-eject-end
26+
27+
// Webpack uses `publicPath` to determine where the app is being served from.
28+
// It requires a trailing slash, or the file assets will get an incorrect path.
29+
var publicPath = paths.servedPath;
30+
// Some apps do not use client-side routing with pushState.
31+
// For these, "homepage" can be set to "." to enable relative asset paths.
32+
var shouldUseRelativeAssetPaths = publicPath === './';
33+
// `publicUrl` is just like `publicPath`, but we will provide it to our app
34+
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
35+
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
36+
var publicUrl = publicPath.slice(0, -1);
37+
// Get environment variables to inject into our app.
38+
var env = getClientEnvironment(publicUrl);
39+
40+
// Fall back to development if not production
41+
if (env.stringified['process.env'].NODE_ENV !== '"production"') {
42+
process.env.NODE_ENV = 'development';
43+
}
44+
45+
// Note: defined here because it will be used more than once.
46+
const cssFilename = 'static/css/' +
47+
process.env.NODE_ENV +
48+
'.[name].[contenthash:8].css';
49+
50+
// ExtractTextPlugin expects the build output to be flat.
51+
// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27)
52+
// However, our output is structured with css, js and media folders.
53+
// To have this structure working with relative paths, we have to use custom options.
54+
const extractTextPluginOptions = shouldUseRelativeAssetPaths
55+
? // Making sure that the publicPath goes back to to build folder.
56+
{ publicPath: Array(cssFilename.split('/').length).join('../') }
57+
: {};
58+
59+
// This is the watching configuration.
60+
// It defaults to development mode for quick iteration
61+
module.exports = {
62+
watch: true,
63+
context: paths.appSrc,
64+
devtool: isProduction() ? 'source-map' : 'cheap-module-source-map',
65+
// There are no support for live reloading changes in this mode
66+
entry: [require.resolve('./polyfills'), paths.appIndexJs],
67+
output: {
68+
// The build folder.
69+
path: paths.appBuild,
70+
// Generated JS file names (with nested folders).
71+
// There will be one main bundle, and one file per asynchronous chunk.
72+
// We don't currently advertise code splitting but Webpack supports it.
73+
// There's prefix in the filename to identify which NODE_ENV generated this build
74+
filename: 'static/js/' + process.env.NODE_ENV + '.[name].[chunkhash:8].js',
75+
chunkFilename: (
76+
'static/js/' + process.env.NODE_ENV + '.[name].[chunkhash:8].chunk.js'
77+
),
78+
// We inferred the "public path" (such as / or /my-project) from homepage.
79+
publicPath: publicPath
80+
},
81+
resolve: {
82+
// This allows you to set a fallback for where Webpack should look for modules.
83+
// We read `NODE_PATH` environment variable in `paths.js` and pass paths here.
84+
// We placed these paths second because we want `node_modules` to "win"
85+
// if there are any conflicts. This matches Node resolution mechanism.
86+
// https://github.com/facebookincubator/create-react-app/issues/253
87+
modules: ['node_modules'].concat(paths.nodePaths),
88+
// These are the reasonable defaults supported by the Node ecosystem.
89+
// We also include JSX as a common component filename extension to support
90+
// some tools, although we do not recommend using it, see:
91+
// https://github.com/facebookincubator/create-react-app/issues/290
92+
extensions: ['.js', '.json', '.jsx'],
93+
alias: {
94+
// Support React Native Web
95+
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
96+
'react-native': 'react-native-web'
97+
}
98+
},
99+
// @remove-on-eject-begin
100+
// Resolve loaders (webpack plugins for CSS, images, transpilation) from the
101+
// directory of `react-scripts` itself rather than the project directory.
102+
resolveLoader: {
103+
modules: [
104+
paths.ownNodeModules,
105+
// Lerna hoists everything, so we need to look in our app directory
106+
paths.appNodeModules
107+
]
108+
},
109+
// @remove-on-eject-end
110+
// This part is essentially the same as production configuration, but it remove
111+
// the minification on development
112+
module: {
113+
rules: [
114+
// Disable require.ensure as it's not a standard language feature.
115+
{ parser: { requireEnsure: false } },
116+
// First, run the linter.
117+
// It's important to do this before Babel processes the JS.
118+
{
119+
test: /\.(js|jsx)$/,
120+
enforce: 'pre',
121+
use: [
122+
{
123+
// @remove-on-eject-begin
124+
// Point ESLint to our predefined config.
125+
options: {
126+
// TODO: consider separate config for production,
127+
// e.g. to enable no-console and no-debugger only in production.
128+
configFile: path.join(__dirname, '../.eslintrc'),
129+
useEslintrc: false
130+
},
131+
// @remove-on-eject-end
132+
loader: 'eslint-loader'
133+
}
134+
],
135+
include: paths.appSrc
136+
},
137+
// ** ADDING/UPDATING LOADERS **
138+
// The "url" loader handles all assets unless explicitly excluded.
139+
// The `exclude` list *must* be updated with every change to loader extensions.
140+
// When adding a new loader, you must add its `test`
141+
// as a new entry in the `exclude` list in the "url" loader.
142+
143+
// "url" loader embeds assets smaller than specified size as data URLs to avoid requests.
144+
// Otherwise, it acts like the "file" loader.
145+
{
146+
exclude: [/\.html$/, /\.(js|jsx)$/, /\.css$/, /\.json$/, /\.svg$/],
147+
loader: 'url-loader',
148+
options: {
149+
limit: 10000,
150+
name: (
151+
'static/media/' + process.env.NODE_ENV + '.[name].[hash:8].[ext]'
152+
)
153+
}
154+
},
155+
// Process JS with Babel.
156+
{
157+
test: /\.(js|jsx)$/,
158+
include: paths.appSrc,
159+
loader: 'babel-loader',
160+
// @remove-on-eject-begin
161+
options: {
162+
babelrc: false,
163+
presets: [require.resolve('babel-preset-react-app')]
164+
}
165+
166+
// @remove-on-eject-end
167+
},
168+
// The notation here is somewhat confusing.
169+
// "postcss" loader applies autoprefixer to our CSS.
170+
// "css" loader resolves paths in CSS and adds assets as dependencies.
171+
// "style" loader normally turns CSS into JS modules injecting <style>,
172+
// but unlike in development configuration, we do something different.
173+
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
174+
// (second argument), then grabs the result CSS and puts it into a
175+
// separate file in our build process. This way we actually ship
176+
// a single CSS file in production instead of JS code injecting <style>
177+
// tags. If you use code splitting, however, any async bundles will still
178+
// use the "style" loader inside the async code so CSS from them won't be
179+
// in the main CSS file.
180+
{
181+
test: /\.css$/,
182+
loader: ExtractTextPlugin.extract(
183+
Object.assign(
184+
{
185+
fallback: 'style-loader',
186+
use: [
187+
{
188+
loader: 'css-loader',
189+
options: {
190+
importLoaders: 1
191+
}
192+
},
193+
{
194+
loader: 'postcss-loader',
195+
options: {
196+
ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
197+
plugins: function() {
198+
return [
199+
autoprefixer({
200+
browsers: [
201+
'>1%',
202+
'last 4 versions',
203+
'Firefox ESR',
204+
'not ie < 9' // React doesn't support IE8 anyway
205+
]
206+
})
207+
];
208+
}
209+
}
210+
}
211+
]
212+
},
213+
extractTextPluginOptions
214+
)
215+
)
216+
217+
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
218+
},
219+
// "file" loader for svg
220+
{
221+
test: /\.svg$/,
222+
loader: 'file-loader',
223+
options: {
224+
name: (
225+
'static/media/' + process.env.NODE_ENV + '.[name].[hash:8].[ext]'
226+
)
227+
}
228+
}
229+
// ** STOP ** Are you adding a new loader?
230+
// Remember to add the new extension(s) to the "url" loader exclusion list.
231+
]
232+
},
233+
plugins: [
234+
// Makes some environment variables available in index.html.
235+
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
236+
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
237+
// In production, it will be an empty string unless you specify "homepage"
238+
// in `package.json`, in which case it will be the pathname of that URL.
239+
new InterpolateHtmlPlugin(env.raw),
240+
// Generates an `index.html` file with the <script> injected.
241+
new HtmlWebpackPlugin({
242+
inject: true,
243+
template: paths.appHtml,
244+
minify: (
245+
isProduction()
246+
? // Minify the code if in production.
247+
{
248+
removeComments: true,
249+
collapseWhitespace: true,
250+
removeRedundantAttributes: true,
251+
useShortDoctype: true,
252+
removeEmptyAttributes: true,
253+
removeStyleLinkTypeAttributes: true,
254+
keepClosingSlash: true,
255+
minifyJS: true,
256+
minifyCSS: true,
257+
minifyURLs: true
258+
}
259+
: false
260+
)
261+
}),
262+
// Makes some environment variables available to the JS code, for example:
263+
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
264+
// It is absolutely essential that NODE_ENV was set to production here.
265+
// Otherwise React will be compiled in the very slow development mode.
266+
new webpack.DefinePlugin(env.stringified),
267+
// Minify js if in production.
268+
isProduction()
269+
? new webpack.optimize.UglifyJsPlugin({
270+
compress: {
271+
screw_ie8: true, // React doesn't support IE8
272+
warnings: false
273+
},
274+
mangle: {
275+
screw_ie8: true
276+
},
277+
output: {
278+
comments: false,
279+
screw_ie8: true
280+
},
281+
sourceMap: true
282+
})
283+
: false,
284+
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
285+
new ExtractTextPlugin({
286+
filename: cssFilename
287+
}),
288+
// Generate a manifest file which contains a mapping of all asset filenames
289+
// to their corresponding output file so that tools can pick it up without
290+
// having to parse `index.html`.
291+
// We also read this file to delete stale files in build folder
292+
new ManifestPlugin({
293+
fileName: 'asset-manifest.json'
294+
})
295+
].filter(Boolean), // remove falsy plugin on development
296+
// Some libraries import Node modules but don't use them in the browser.
297+
// Tell Webpack to provide empty mocks for them so importing them works.
298+
node: {
299+
fs: 'empty',
300+
net: 'empty',
301+
tls: 'empty'
302+
}
303+
};

Diff for: packages/react-scripts/scripts/init.js

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module.exports = function(
3838
appPackage.scripts = {
3939
start: 'react-scripts start',
4040
build: 'react-scripts build',
41+
watch: 'react-scripts watch',
4142
test: 'react-scripts test --env=jsdom',
4243
eject: 'react-scripts eject',
4344
};

0 commit comments

Comments
 (0)