Use async/await in Rollup scripts (#11669)
Dan Abramov committed
Nov 27, 2017 at 17:57 UTC
a65a8abc65cd31c862f5e83eb24a8dc68458b521
3 files changed
+194
-269
scripts/rollup/build.js
+115
-152
@@ -89,10 +89,8 @@ function getBabelConfig(updateBabelOptions, bundleType, filename) {
89
plugins: options.plugins.concat([
90
// Use object-assign polyfill in open source
91
resolve('./scripts/babel/transform-object-assign-require'),
92
-
92
// Minify invariant messages
93
require('../error-codes/replace-invariant-error-codes'),
95
-
94
// Wrap warning() calls in a __DEV__ check so they are stripped from production.
95
require('./plugins/wrap-warning-with-env-check'),
96
]),
@@ -310,17 +308,17 @@ function getPlugins(
308
].filter(Boolean);
309
}
310
313
-function createBundle(bundle, bundleType) {
311
+async function createBundle(bundle, bundleType) {
312
const shouldSkipBundleType = bundle.bundleTypes.indexOf(bundleType) === -1;
313
if (shouldSkipBundleType) {
316
- return Promise.resolve();
314
+ return;
315
}
316
if (requestedBundleTypes.length > 0) {
317
const isAskingForDifferentType = requestedBundleTypes.every(
318
requestedType => bundleType.indexOf(requestedType) === -1
319
);
320
if (isAskingForDifferentType) {
323
- return Promise.resolve();
321
+ return;
322
}
323
}
324
if (requestedBundleNames.length > 0) {
@@ -328,7 +326,7 @@ function createBundle(bundle, bundleType) {
326
requestedName => bundle.label.indexOf(requestedName) === -1
327
);
328
if (isAskingForDifferentNames) {
331
- return Promise.resolve();
329
+ return;
330
}
331
}
332
@@ -364,160 +362,125 @@ function createBundle(bundle, bundleType) {
362
);
363
364
console.log(`${chalk.bgYellow.black(' BUILDING ')} ${logKey}`);
367
- return rollup({
368
- input: resolvedEntry,
369
- pureExternalModules,
370
- external(id) {
371
- const containsThisModule = pkg => id === pkg || id.startsWith(pkg + '/');
372
- const isProvidedByDependency = externals.some(containsThisModule);
373
- if (!shouldBundleDependencies && isProvidedByDependency) {
374
- return true;
375
- }
376
- return !!peerGlobals[id];
377
- },
378
- onwarn: handleRollupWarnings,
379
- plugins: getPlugins(
380
- bundle.entry,
381
- externals,
382
- bundle.babel,
383
- filename,
384
- bundleType,
385
- bundle.global,
386
- bundle.moduleType,
387
- bundle.modulesToStub,
388
- bundle.featureFlags
389
- ),
390
- // We can't use getters in www.
391
- legacy: bundleType === FB_DEV || bundleType === FB_PROD,
392
- })
393
- .then(result =>
394
- result.write(
395
- getRollupOutputOptions(
396
- filename,
397
- format,
398
- bundleType,
399
- peerGlobals,
400
- bundle.global,
401
- bundle.moduleType
402
- )
403
- )
404
- )
405
- .then(() => Packaging.createNodePackage(bundleType, packageName, filename))
406
- .then(() => {
407
- console.log(`${chalk.bgGreen.black(' COMPLETE ')} ${logKey}\n`);
408
- })
409
- .catch(error => {
410
- if (error.code) {
411
- console.error(
412
- `\x1b[31m-- ${error.code}${
413
- error.plugin ? ` (${error.plugin})` : ''
414
- } --`
415
- );
416
- console.error(error.message);
417
-
418
- const {file, line, column} = error.loc;
419
- if (file) {
420
- // This looks like an error from Rollup, e.g. missing export.
421
- // We'll use the accurate line numbers provided by Rollup but
422
- // use Babel code frame because it looks nicer.
423
- const rawLines = fs.readFileSync(file, 'utf-8');
424
- // column + 1 is required due to rollup counting column start position from 0
425
- // whereas babel-code-frame counts from 1
426
- const frame = codeFrame(rawLines, line, column + 1, {
427
- highlightCode: true,
428
- });
429
- console.error(frame);
430
- } else {
431
- // This looks like an error from a plugin (e.g. Babel).
432
- // In this case we'll resort to displaying the provided code frame
433
- // because we can't be sure the reported location is accurate.
434
- console.error(error.codeFrame);
365
+ try {
366
+ const result = await rollup({
367
+ input: resolvedEntry,
368
+ pureExternalModules,
369
+ external(id) {
370
+ const containsThisModule = pkg =>
371
+ id === pkg || id.startsWith(pkg + '/');
372
+ const isProvidedByDependency = externals.some(containsThisModule);
373
+ if (!shouldBundleDependencies && isProvidedByDependency) {
374
+ return true;
375
}
376
+ return !!peerGlobals[id];
377
+ },
378
+ onwarn: handleRollupWarnings,
379
+ plugins: getPlugins(
380
+ bundle.entry,
381
+ externals,
382
+ bundle.babel,
383
+ filename,
384
+ bundleType,
385
+ bundle.global,
386
+ bundle.moduleType,
387
+ bundle.modulesToStub,
388
+ bundle.featureFlags
389
+ ),
390
+ // We can't use getters in www.
391
+ legacy: bundleType === FB_DEV || bundleType === FB_PROD,
392
+ });
393
+ await result.write(
394
+ getRollupOutputOptions(
395
+ filename,
396
+ format,
397
+ bundleType,
398
+ peerGlobals,
399
+ bundle.global,
400
+ bundle.moduleType
401
+ )
402
+ );
403
+ await Packaging.createNodePackage(bundleType, packageName, filename);
404
+ console.log(`${chalk.bgGreen.black(' COMPLETE ')} ${logKey}\n`);
405
+ } catch (error) {
406
+ if (error.code) {
407
+ console.error(
408
+ `\x1b[31m-- ${error.code}${error.plugin ? ` (${error.plugin})` : ''} --`
409
+ );
410
+ console.error(error.message);
411
+ const {file, line, column} = error.loc;
412
+ if (file) {
413
+ // This looks like an error from Rollup, e.g. missing export.
414
+ // We'll use the accurate line numbers provided by Rollup but
415
+ // use Babel code frame because it looks nicer.
416
+ const rawLines = fs.readFileSync(file, 'utf-8');
417
+ // column + 1 is required due to rollup counting column start position from 0
418
+ // whereas babel-code-frame counts from 1
419
+ const frame = codeFrame(rawLines, line, column + 1, {
420
+ highlightCode: true,
421
+ });
422
+ console.error(frame);
423
} else {
437
- console.error(error);
424
+ // This looks like an error from a plugin (e.g. Babel).
425
+ // In this case we'll resort to displaying the provided code frame
426
+ // because we can't be sure the reported location is accurate.
427
+ console.error(error.codeFrame);
428
}
439
- process.exit(1);
440
- });
429
+ } else {
430
+ console.error(error);
431
+ }
432
+ process.exit(1);
433
+ }
434
}
435
436
// clear the build directory
444
-rimraf('build', () => {
445
- // create a new build directory
446
- fs.mkdirSync('build');
447
- // create the packages folder for NODE+UMD bundles
448
- fs.mkdirSync(join('build', 'packages'));
449
- // create the dist folder for UMD bundles
450
- fs.mkdirSync(join('build', 'dist'));
437
+rimraf('build', async () => {
438
+ try {
439
+ // create a new build directory
440
+ fs.mkdirSync('build');
441
+ // create the packages folder for NODE+UMD bundles
442
+ fs.mkdirSync(join('build', 'packages'));
443
+ // create the dist folder for UMD bundles
444
+ fs.mkdirSync(join('build', 'dist'));
445
452
- const tasks = [
453
- Packaging.createFacebookWWWBuild,
454
- Packaging.createReactNativeBuild,
455
- Packaging.createReactNativeRTBuild,
456
- Packaging.createReactNativeCSBuild,
457
- ];
458
- for (const bundle of Bundles.bundles) {
459
- tasks.push(
460
- () => createBundle(bundle, UMD_DEV),
461
- () => createBundle(bundle, UMD_PROD),
462
- () => createBundle(bundle, NODE_DEV),
463
- () => createBundle(bundle, NODE_PROD),
464
- () => createBundle(bundle, FB_DEV),
465
- () => createBundle(bundle, FB_PROD),
466
- () => createBundle(bundle, RN_DEV),
467
- () => createBundle(bundle, RN_PROD)
468
- );
469
- }
470
- if (syncFbsource) {
471
- tasks.push(() =>
472
- syncReactNative(join('build', 'react-native'), syncFbsource)
473
- );
474
- tasks.push(() =>
475
- syncReactNativeRT(join('build', 'react-rt'), syncFbsource)
476
- );
477
- tasks.push(() =>
478
- syncReactNativeCS(join('build', 'react-cs'), syncFbsource)
479
- );
480
- } else if (syncWww) {
481
- tasks.push(() => syncReactDom(join('build', 'facebook-www'), syncWww));
482
- }
483
- // rather than run concurrently, opt to run them serially
484
- // this helps improve console/warning/error output
485
- // and fixes a bunch of IO failures that sometimes occurred
486
- return runWaterfall(tasks)
487
- .then(() => {
488
- // output the results
489
- console.log(Stats.printResults());
490
- // save the results for next run
491
- Stats.saveResults();
492
- if (shouldExtractErrors) {
493
- console.warn(
494
- '\nWarning: this build was created with --extract-errors enabled.\n' +
495
- 'this will result in extremely slow builds and should only be\n' +
496
- 'used when the error map needs to be rebuilt.\n'
497
- );
498
- }
499
- })
500
- .catch(err => {
501
- console.error(err);
502
- process.exit(1);
503
- });
504
-});
446
+ await Packaging.createFacebookWWWBuild();
447
+ await Packaging.createReactNativeBuild();
448
+ await Packaging.createReactNativeRTBuild();
449
+ await Packaging.createReactNativeCSBuild();
450
506
-function runWaterfall(promiseFactories) {
507
- if (promiseFactories.length === 0) {
508
- return Promise.resolve();
509
- }
451
+ // Run them serially for better console output
452
+ // and to avoid any potential race conditions.
453
+ for (const bundle of Bundles.bundles) {
454
+ await createBundle(bundle, UMD_DEV);
455
+ await createBundle(bundle, UMD_PROD);
456
+ await createBundle(bundle, NODE_DEV);
457
+ await createBundle(bundle, NODE_PROD);
458
+ await createBundle(bundle, FB_DEV);
459
+ await createBundle(bundle, FB_PROD);
460
+ await createBundle(bundle, RN_DEV);
461
+ await createBundle(bundle, RN_PROD);
462
+ }
463
511
- const head = promiseFactories[0];
512
- const tail = promiseFactories.slice(1);
464
+ if (syncFbsource) {
465
+ await syncReactNative(join('build', 'react-native'), syncFbsource);
466
+ await syncReactNativeRT(join('build', 'react-rt'), syncFbsource);
467
+ await syncReactNativeCS(join('build', 'react-cs'), syncFbsource);
468
+ } else if (syncWww) {
469
+ await syncReactDom(join('build', 'facebook-www'), syncWww);
470
+ }
471
514
- const nextPromiseFactory = head;
515
- const nextPromise = nextPromiseFactory();
516
- if (!nextPromise || typeof nextPromise.then !== 'function') {
517
- throw new Error('runWaterfall() received something that is not a Promise.');
472
+ console.log(Stats.printResults());
473
+ // save the results for next run
474
+ Stats.saveResults();
475
+ if (shouldExtractErrors) {
476
+ console.warn(
477
+ '\nWarning: this build was created with --extract-errors enabled.\n' +
478
+ 'this will result in extremely slow builds and should only be\n' +
479
+ 'used when the error map needs to be rebuilt.\n'
480
+ );
481
+ }
482
+ } catch (err) {
483
+ console.error(err);
484
+ process.exit(1);
485
}
519
-
520
- return nextPromise.then(() => {
521
- return runWaterfall(tail);
522
- });
523
-}
486
+});
scripts/rollup/packaging.js
+62
-98
@@ -41,149 +41,113 @@ function getPackageName(name) {
41
return name;
42
}
43
44
-function createReactNativeBuild() {
45
- // create the react-native folder for FB bundles
44
+async function createReactNativeBuild() {
45
fs.mkdirSync(join('build', 'react-native'));
47
- // create the react-native shims folder for FB shims
46
fs.mkdirSync(join('build', 'react-native', 'shims'));
49
- // copy in all the shims from build/rollup/shims/react-native
47
const from = join('scripts', 'rollup', 'shims', 'react-native');
48
const to = join('build', 'react-native', 'shims');
52
-
53
- return asyncCopyTo(from, to).then(() => {
54
- let promises = [];
55
- // we also need to copy over some specific files from src
56
- // defined in reactNativeSrcDependencies
57
- for (const srcDependency of reactNativeSrcDependencies) {
58
- promises.push(
59
- asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
60
- );
61
- }
62
- return Promise.all(promises);
63
- });
49
+ await asyncCopyTo(from, to);
50
+ await Promise.all(
51
+ reactNativeSrcDependencies.map(srcDependency =>
52
+ asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
53
+ )
54
+ );
55
}
56
66
-function createReactNativeRTBuild() {
67
- // create the react-rt folder for FB bundles
57
+async function createReactNativeRTBuild() {
58
fs.mkdirSync(join('build', 'react-rt'));
69
- // create the react-rt shims folder for FB shims
59
fs.mkdirSync(join('build', 'react-rt', 'shims'));
71
-
60
const to = join('build', 'react-rt', 'shims');
73
-
74
- let promises = [];
75
- // we also need to copy over some specific files from src
76
- // defined in reactNativeRTSrcDependencies
77
- for (const srcDependency of reactNativeRTSrcDependencies) {
78
- promises.push(
61
+ await Promise.all(
62
+ reactNativeRTSrcDependencies.map(srcDependency =>
63
asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
80
- );
81
- }
82
- return Promise.all(promises);
64
+ )
65
+ );
66
}
67
85
-function createReactNativeCSBuild() {
86
- // create the react-cs folder for FB bundles
68
+async function createReactNativeCSBuild() {
69
fs.mkdirSync(join('build', 'react-cs'));
88
- // create the react-cs shims folder for FB shims
70
fs.mkdirSync(join('build', 'react-cs', 'shims'));
90
-
71
const to = join('build', 'react-cs', 'shims');
92
-
93
- let promises = [];
94
- // we also need to copy over some specific files from src
95
- // defined in reactNativeCSSrcDependencies
96
- for (const srcDependency of reactNativeCSSrcDependencies) {
97
- promises.push(
72
+ await Promise.all(
73
+ reactNativeCSSrcDependencies.map(srcDependency =>
74
asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
99
- );
100
- }
101
- return Promise.all(promises);
75
+ )
76
+ );
77
}
78
104
-function createFacebookWWWBuild() {
105
- // create the facebookWWW folder for FB bundles
79
+async function createFacebookWWWBuild() {
80
fs.mkdirSync(join('build', facebookWWW));
107
- // create the facebookWWW shims folder for FB shims
81
fs.mkdirSync(join('build', facebookWWW, 'shims'));
109
- // copy in all the shims from build/rollup/shims/facebook-www
82
const from = join('scripts', 'rollup', 'shims', facebookWWW);
83
const to = join('build', facebookWWW, 'shims');
112
-
113
- return asyncCopyTo(from, to);
84
+ await asyncCopyTo(from, to);
85
}
86
116
-function copyBundleIntoNodePackage(packageName, filename, bundleType) {
87
+async function copyBundleIntoNodePackage(packageName, filename, bundleType) {
88
const packageDirectory = resolve(`./build/packages/${packageName}`);
118
-
119
- if (fs.existsSync(packageDirectory)) {
120
- let from = resolve(`./build/${filename}`);
121
- let to = `${packageDirectory}/${filename}`;
122
- // for UMD bundles we have to move the files into a umd directory
123
- // within the package directory. we also need to set the from
124
- // to be the root build from directory
125
- if (bundleType === UMD_DEV || bundleType === UMD_PROD) {
126
- const distDirectory = `${packageDirectory}/umd`;
127
- // create a dist directory if not created
128
- if (!fs.existsSync(distDirectory)) {
129
- fs.mkdirSync(distDirectory);
130
- }
131
- from = resolve(`./build/dist/${filename}`);
132
- to = `${packageDirectory}/umd/${filename}`;
89
+ if (!fs.existsSync(packageDirectory)) {
90
+ return;
91
+ }
92
+ let from = resolve(`./build/${filename}`);
93
+ let to = `${packageDirectory}/${filename}`;
94
+ // for UMD bundles we have to move the files into a umd directory
95
+ // within the package directory. we also need to set the from
96
+ // to be the root build from directory
97
+ if (bundleType === UMD_DEV || bundleType === UMD_PROD) {
98
+ const distDirectory = `${packageDirectory}/umd`;
99
+ // create a dist directory if not created
100
+ if (!fs.existsSync(distDirectory)) {
101
+ fs.mkdirSync(distDirectory);
102
}
134
- // for NODE bundles we have to move the files into a cjs directory
135
- // within the package directory. we also need to set the from
136
- // to be the root build from directory
137
- if (bundleType === NODE_DEV || bundleType === NODE_PROD) {
138
- const distDirectory = `${packageDirectory}/cjs`;
139
- // create a dist directory if not created
140
- if (!fs.existsSync(distDirectory)) {
141
- fs.mkdirSync(distDirectory);
142
- }
143
- to = `${packageDirectory}/cjs/${filename}`;
103
+ from = resolve(`./build/dist/${filename}`);
104
+ to = `${packageDirectory}/umd/${filename}`;
105
+ }
106
+ // for NODE bundles we have to move the files into a cjs directory
107
+ // within the package directory. we also need to set the from
108
+ // to be the root build from directory
109
+ if (bundleType === NODE_DEV || bundleType === NODE_PROD) {
110
+ const distDirectory = `${packageDirectory}/cjs`;
111
+ // create a dist directory if not created
112
+ if (!fs.existsSync(distDirectory)) {
113
+ fs.mkdirSync(distDirectory);
114
}
145
- return asyncCopyTo(from, to).then(() => {
146
- // delete the old file if this is a not a UMD bundle
147
- if (bundleType !== UMD_DEV && bundleType !== UMD_PROD) {
148
- fs.unlinkSync(from);
149
- }
150
- });
151
- } else {
152
- return Promise.resolve();
115
+ to = `${packageDirectory}/cjs/${filename}`;
116
+ }
117
+ await asyncCopyTo(from, to);
118
+ // delete the old file if this is a not a UMD bundle
119
+ if (bundleType !== UMD_DEV && bundleType !== UMD_PROD) {
120
+ fs.unlinkSync(from);
121
}
122
}
123
156
-function copyNodePackageTemplate(packageName) {
124
+async function copyNodePackageTemplate(packageName) {
125
const from = resolve(`./packages/${packageName}`);
126
const to = resolve(`./build/packages/${packageName}`);
127
const npmFrom = resolve(`${from}/npm`);
128
if (!fs.existsSync(npmFrom)) {
129
// The package is not meant for npm consumption.
162
- return Promise.resolve();
130
+ return;
131
}
132
if (fs.existsSync(to)) {
133
// We already created this package (e.g. due to another entry point).
166
- return Promise.resolve();
134
+ return;
135
}
136
// TODO: verify that all copied files are either in the "files"
137
// whitelist or implicitly published by npm.
170
- return asyncCopyTo(npmFrom, to).then(() =>
171
- Promise.all([
172
- asyncCopyTo(resolve(`${from}/package.json`), `${to}/package.json`),
173
- asyncCopyTo(resolve(`${from}/README.md`), `${to}/README.md`),
174
- asyncCopyTo(resolve('./LICENSE'), `${to}/LICENSE`),
175
- ])
176
- );
138
+ await asyncCopyTo(npmFrom, to);
139
+ await asyncCopyTo(resolve(`${from}/package.json`), `${to}/package.json`);
140
+ await asyncCopyTo(resolve(`${from}/README.md`), `${to}/README.md`);
141
+ await asyncCopyTo(resolve('./LICENSE'), `${to}/LICENSE`);
142
}
143
179
-function createNodePackage(bundleType, packageName, filename) {
144
+async function createNodePackage(bundleType, packageName, filename) {
145
// the only case where we don't want to copy the package is for FB bundles
181
- if (bundleType !== FB_DEV && bundleType !== FB_PROD) {
182
- return copyNodePackageTemplate(packageName).then(() =>
183
- copyBundleIntoNodePackage(packageName, filename, bundleType)
184
- );
146
+ if (bundleType === FB_DEV || bundleType === FB_PROD) {
147
+ return;
148
}
186
- return Promise.resolve();
149
+ await copyNodePackageTemplate(packageName);
150
+ await copyBundleIntoNodePackage(packageName, filename, bundleType);
151
}
152
153
function getOutputPathRelativeToBuildFolder(bundleType, filename, hasteName) {
scripts/rollup/sync.js
+17
-19
@@ -11,18 +11,14 @@ const RELATIVE_RN_CS_PATH = 'xplat/js/RKJSModules/Libraries/CS/downstream/';
11
const RELATIVE_RN_RT_PATH = 'xplat/js/RKJSModules/Libraries/RT/downstream/';
12
const RELATIVE_WWW_PATH = 'html/shared/react/';
13
14
-function doSync(buildPath, destPath) {
14
+async function doSync(buildPath, destPath) {
15
console.log(`${chalk.bgYellow.black(' SYNCING ')} React to ${destPath}`);
16
17
- const promise = asyncCopyTo(buildPath, destPath);
18
- promise.then(() => {
19
- console.log(`${chalk.bgGreen.black(' SYNCED ')} React to ${destPath}`);
20
- });
21
-
22
- return promise;
17
+ await asyncCopyTo(buildPath, destPath);
18
+ console.log(`${chalk.bgGreen.black(' SYNCED ')} React to ${destPath}`);
19
}
20
25
-function syncReactDom(buildPath, wwwPath) {
21
+async function syncReactDom(buildPath, wwwPath) {
22
wwwPath = typeof wwwPath === 'string' ? wwwPath : DEFAULT_WWW_PATH;
23
24
if (wwwPath.charAt(wwwPath.length - 1) !== '/') {
@@ -30,11 +26,14 @@ function syncReactDom(buildPath, wwwPath) {
26
}
27
28
const destPath = resolvePath(wwwPath + RELATIVE_WWW_PATH);
33
-
34
- return doSync(buildPath, destPath);
29
+ await doSync(buildPath, destPath);
30
}
31
37
-function syncReactNativeHelper(buildPath, fbSourcePath, relativeDestPath) {
32
+async function syncReactNativeHelper(
33
+ buildPath,
34
+ fbSourcePath,
35
+ relativeDestPath
36
+) {
37
fbSourcePath =
38
typeof fbSourcePath === 'string' ? fbSourcePath : DEFAULT_FB_SOURCE_PATH;
39
@@ -43,20 +42,19 @@ function syncReactNativeHelper(buildPath, fbSourcePath, relativeDestPath) {
42
}
43
44
const destPath = resolvePath(fbSourcePath + relativeDestPath);
46
-
47
- return doSync(buildPath, destPath);
45
+ await doSync(buildPath, destPath);
46
}
47
50
-function syncReactNative(buildPath, fbSourcePath) {
51
- return syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_PATH);
48
+async function syncReactNative(buildPath, fbSourcePath) {
49
+ await syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_PATH);
50
}
51
54
-function syncReactNativeCS(buildPath, fbSourcePath) {
55
- return syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_CS_PATH);
52
+async function syncReactNativeCS(buildPath, fbSourcePath) {
53
+ await syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_CS_PATH);
54
}
55
58
-function syncReactNativeRT(buildPath, fbSourcePath) {
59
- return syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_RT_PATH);
56
+async function syncReactNativeRT(buildPath, fbSourcePath) {
57
+ await syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_RT_PATH);
58
}
59
60
module.exports = {