@samitouri / QOS-React / commits / f72043a369

Refactor the build scripts (#11787)

* Rewrite the build scripts * Don't crash when doing FB-only builds * Group sync imports under Sync.* * Don't print known errors twice * Use an exclamation that aligns vertically

Dan Abramov committed Dec 6, 2017 at 20:11 UTC f72043a36903a18703168a1ebfe271c150f27330
5 files changed +363 -417
package.json
+1 -1
@@ -73,6 +73,7 @@
73 "jest-runtime": "^21.3.0-beta.4",
74 "merge-stream": "^1.0.0",
75 "minimist": "^1.2.0",
76 + "mkdirp": "^0.5.1",
77 "ncp": "^2.0.0",
78 "object-assign": "^4.1.1",
79 "platform": "^1.1.0",
@@ -93,7 +94,6 @@
94 "through2": "^2.0.0",
95 "tmp": "~0.0.28",
96 "typescript": "~1.8.10",
96 - "uuid": "^3.1.0",
97 "yargs": "^6.3.0"
98 },
99 "devEngines": {
scripts/rollup/build.js
+177 -195
@@ -1,6 +1,6 @@
1 'use strict';
2
3 -const rollup = require('rollup').rollup;
3 +const {rollup} = require('rollup');
4 const babel = require('rollup-plugin-babel');
5 const closure = require('rollup-plugin-closure-compiler-js');
6 const commonjs = require('rollup-plugin-commonjs');
@@ -10,33 +10,40 @@ const stripBanner = require('rollup-plugin-strip-banner');
10 const chalk = require('chalk');
11 const path = require('path');
12 const resolve = require('rollup-plugin-node-resolve');
13 -const os = require('os');
13 const fs = require('fs');
15 -const rimraf = require('rimraf');
14 const argv = require('minimist')(process.argv.slice(2));
15 const Modules = require('./modules');
16 const Bundles = require('./bundles');
17 +const Stats = require('./stats');
18 +const Sync = require('./sync');
19 const sizes = require('./plugins/sizes-plugin');
20 const useForks = require('./plugins/use-forks-plugin');
21 -const Stats = require('./stats');
21 const extractErrorCodes = require('../error-codes/extract-errors');
23 -const syncReactDom = require('./sync').syncReactDom;
24 -const syncReactNative = require('./sync').syncReactNative;
25 -const syncReactNativeRT = require('./sync').syncReactNativeRT;
26 -const syncReactNativeCS = require('./sync').syncReactNativeCS;
22 const Packaging = require('./packaging');
23 +const {asyncCopyTo, asyncRimRaf} = require('./utils');
24 const codeFrame = require('babel-code-frame');
25 const Wrappers = require('./wrappers');
30 -const uuidv1 = require('uuid/v1');
26
32 -const UMD_DEV = Bundles.bundleTypes.UMD_DEV;
33 -const UMD_PROD = Bundles.bundleTypes.UMD_PROD;
34 -const NODE_DEV = Bundles.bundleTypes.NODE_DEV;
35 -const NODE_PROD = Bundles.bundleTypes.NODE_PROD;
36 -const FB_DEV = Bundles.bundleTypes.FB_DEV;
37 -const FB_PROD = Bundles.bundleTypes.FB_PROD;
38 -const RN_DEV = Bundles.bundleTypes.RN_DEV;
39 -const RN_PROD = Bundles.bundleTypes.RN_PROD;
27 +// Errors in promises should be fatal.
28 +let loggedErrors = new Set();
29 +process.on('unhandledRejection', err => {
30 + if (loggedErrors.has(err)) {
31 + // No need to print it twice.
32 + process.exit(1);
33 + }
34 + throw err;
35 +});
36 +
37 +const {
38 + UMD_DEV,
39 + UMD_PROD,
40 + NODE_DEV,
41 + NODE_PROD,
42 + FB_DEV,
43 + FB_PROD,
44 + RN_DEV,
45 + RN_PROD,
46 +} = Bundles.bundleTypes;
47
48 const requestedBundleTypes = (argv.type || '')
49 .split(',')
@@ -44,16 +51,12 @@ const requestedBundleTypes = (argv.type || '')
51 const requestedBundleNames = (argv._[0] || '')
52 .split(',')
53 .map(type => type.toLowerCase());
47 -const syncFbsource = argv['sync-fbsource'];
48 -const syncWww = argv['sync-www'];
54 +const syncFBSourcePath = argv['sync-fbsource'];
55 +const syncWWWPath = argv['sync-www'];
56 const shouldExtractErrors = argv['extract-errors'];
57 const errorCodeOpts = {
58 errorMapFilePath: 'scripts/error-codes/codes.json',
59 };
53 -const npmPackagesTmpDir = path.join(
54 - os.tmpdir(),
55 - `react-npm-packages-${uuidv1()}`
56 -);
60
61 const closureOptions = {
62 compilationLevel: 'SIMPLE',
@@ -105,54 +108,11 @@ function getBabelConfig(updateBabelOptions, bundleType, filename) {
108 }
109 }
110
108 -function handleRollupWarnings(warning) {
109 - if (warning.code === 'UNRESOLVED_IMPORT') {
110 - console.error(warning.message);
111 - process.exit(1);
112 - }
113 - if (warning.code === 'UNUSED_EXTERNAL_IMPORT') {
114 - const match = warning.message.match(/external module '([^']+)'/);
115 - if (!match || typeof match[1] !== 'string') {
116 - throw new Error(
117 - 'Could not parse a Rollup warning. ' + 'Fix this method.'
118 - );
119 - }
120 - const importSideEffects = Modules.getImportSideEffects();
121 - const externalModule = match[1];
122 - if (typeof importSideEffects[externalModule] !== 'boolean') {
123 - throw new Error(
124 - 'An external module "' +
125 - externalModule +
126 - '" is used in a DEV-only code path ' +
127 - 'but we do not know if it is safe to omit an unused require() to it in production. ' +
128 - 'Please add it to the `importSideEffects` list in `scripts/rollup/modules.js`.'
129 - );
130 - }
131 - // Don't warn. We will remove side effectless require() in a later pass.
132 - return;
133 - }
134 - console.warn(warning.message || warning);
135 -}
136 -
137 -function getRollupOutputOptions(
138 - filename,
139 - format,
140 - bundleType,
141 - globals,
142 - globalName,
143 - moduleType
144 -) {
111 +function getRollupOutputOptions(outputPath, format, globals, globalName) {
112 return Object.assign(
113 {},
114 {
148 - destDir: 'build/',
149 - file:
150 - 'build/' +
151 - Packaging.getOutputPathRelativeToBuildFolder(
152 - bundleType,
153 - filename,
154 - globalName
155 - ),
115 + file: outputPath,
116 format,
117 globals,
118 interop: false,
@@ -312,17 +272,17 @@ function getPlugins(
272 ].filter(Boolean);
273 }
274
315 -async function createBundle(bundle, bundleType) {
275 +function shouldSkipBundle(bundle, bundleType) {
276 const shouldSkipBundleType = bundle.bundleTypes.indexOf(bundleType) === -1;
277 if (shouldSkipBundleType) {
318 - return;
278 + return true;
279 }
280 if (requestedBundleTypes.length > 0) {
281 const isAskingForDifferentType = requestedBundleTypes.every(
282 requestedType => bundleType.indexOf(requestedType) === -1
283 );
284 if (isAskingForDifferentType) {
325 - return;
285 + return true;
286 }
287 }
288 if (requestedBundleNames.length > 0) {
@@ -330,9 +290,16 @@ async function createBundle(bundle, bundleType) {
290 requestedName => bundle.label.indexOf(requestedName) === -1
291 );
292 if (isAskingForDifferentNames) {
333 - return;
293 + return true;
294 }
295 }
296 + return false;
297 +}
298 +
299 +async function createBundle(bundle, bundleType) {
300 + if (shouldSkipBundle(bundle, bundleType)) {
301 + return;
302 + }
303
304 const filename = getFilename(bundle.entry, bundle.global, bundleType);
305 const logKey =
@@ -365,139 +332,154 @@ async function createBundle(bundle, bundleType) {
332 module => !importSideEffects[module]
333 );
334
335 + const rollupConfig = {
336 + input: resolvedEntry,
337 + pureExternalModules,
338 + external(id) {
339 + const containsThisModule = pkg => id === pkg || id.startsWith(pkg + '/');
340 + const isProvidedByDependency = externals.some(containsThisModule);
341 + if (!shouldBundleDependencies && isProvidedByDependency) {
342 + return true;
343 + }
344 + return !!peerGlobals[id];
345 + },
346 + onwarn: handleRollupWarning,
347 + plugins: getPlugins(
348 + bundle.entry,
349 + externals,
350 + bundle.babel,
351 + filename,
352 + bundleType,
353 + bundle.global,
354 + bundle.moduleType,
355 + bundle.modulesToStub
356 + ),
357 + // We can't use getters in www.
358 + legacy: bundleType === FB_DEV || bundleType === FB_PROD,
359 + };
360 + const [mainOutputPath, ...otherOutputPaths] = Packaging.getBundleOutputPaths(
361 + bundleType,
362 + filename,
363 + packageName
364 + );
365 + const rollupOutputOptions = getRollupOutputOptions(
366 + mainOutputPath,
367 + format,
368 + peerGlobals,
369 + bundle.global
370 + );
371 +
372 console.log(`${chalk.bgYellow.black(' BUILDING ')} ${logKey}`);
373 try {
370 - const result = await rollup({
371 - input: resolvedEntry,
372 - pureExternalModules,
373 - external(id) {
374 - const containsThisModule = pkg =>
375 - id === pkg || id.startsWith(pkg + '/');
376 - const isProvidedByDependency = externals.some(containsThisModule);
377 - if (!shouldBundleDependencies && isProvidedByDependency) {
378 - return true;
379 - }
380 - return !!peerGlobals[id];
381 - },
382 - onwarn: handleRollupWarnings,
383 - plugins: getPlugins(
384 - bundle.entry,
385 - externals,
386 - bundle.babel,
387 - filename,
388 - bundleType,
389 - bundle.global,
390 - bundle.moduleType,
391 - bundle.modulesToStub
392 - ),
393 - // We can't use getters in www.
394 - legacy: bundleType === FB_DEV || bundleType === FB_PROD,
395 - });
396 - await result.write(
397 - getRollupOutputOptions(
398 - filename,
399 - format,
400 - bundleType,
401 - peerGlobals,
402 - bundle.global,
403 - bundle.moduleType
404 - )
405 - );
406 - await Packaging.createNodePackage(
407 - bundleType,
408 - packageName,
409 - filename,
410 - npmPackagesTmpDir
411 - );
412 - console.log(`${chalk.bgGreen.black(' COMPLETE ')} ${logKey}\n`);
374 + const result = await rollup(rollupConfig);
375 + await result.write(rollupOutputOptions);
376 } catch (error) {
414 - if (error.code) {
415 - console.error(
416 - `\x1b[31m-- ${error.code}${error.plugin ? ` (${error.plugin})` : ''} --`
377 + console.log(`${chalk.bgRed.black(' OH NOES! ')} ${logKey}\n`);
378 + handleRollupError(error);
379 + throw error;
380 + }
381 + for (let i = 0; i < otherOutputPaths.length; i++) {
382 + await asyncCopyTo(mainOutputPath, otherOutputPaths[i]);
383 + }
384 + console.log(`${chalk.bgGreen.black(' COMPLETE ')} ${logKey}\n`);
385 +}
386 +
387 +function handleRollupWarning(warning) {
388 + if (warning.code === 'UNRESOLVED_IMPORT') {
389 + console.error(warning.message);
390 + process.exit(1);
391 + }
392 + if (warning.code === 'UNUSED_EXTERNAL_IMPORT') {
393 + const match = warning.message.match(/external module '([^']+)'/);
394 + if (!match || typeof match[1] !== 'string') {
395 + throw new Error(
396 + 'Could not parse a Rollup warning. ' + 'Fix this method.'
397 );
418 - console.error(error.message);
419 - const {file, line, column} = error.loc;
420 - if (file) {
421 - // This looks like an error from Rollup, e.g. missing export.
422 - // We'll use the accurate line numbers provided by Rollup but
423 - // use Babel code frame because it looks nicer.
424 - const rawLines = fs.readFileSync(file, 'utf-8');
425 - // column + 1 is required due to rollup counting column start position from 0
426 - // whereas babel-code-frame counts from 1
427 - const frame = codeFrame(rawLines, line, column + 1, {
428 - highlightCode: true,
429 - });
430 - console.error(frame);
431 - } else {
432 - // This looks like an error from a plugin (e.g. Babel).
433 - // In this case we'll resort to displaying the provided code frame
434 - // because we can't be sure the reported location is accurate.
435 - console.error(error.codeFrame);
436 - }
437 - } else {
438 - console.error(error);
398 }
440 - process.exit(1);
399 + const importSideEffects = Modules.getImportSideEffects();
400 + const externalModule = match[1];
401 + if (typeof importSideEffects[externalModule] !== 'boolean') {
402 + throw new Error(
403 + 'An external module "' +
404 + externalModule +
405 + '" is used in a DEV-only code path ' +
406 + 'but we do not know if it is safe to omit an unused require() to it in production. ' +
407 + 'Please add it to the `importSideEffects` list in `scripts/rollup/modules.js`.'
408 + );
409 + }
410 + // Don't warn. We will remove side effectless require() in a later pass.
411 + return;
412 }
413 + console.warn(warning.message || warning);
414 }
415
444 -// clear the build directory
445 -rimraf('build', async () => {
446 - try {
447 - // create a new build directory
448 - fs.mkdirSync('build');
449 - // create the temp directory for local npm packing and unpacking
450 - // in operating system's default temporary directory
451 - fs.mkdirSync(npmPackagesTmpDir);
452 - // create the packages folder for NODE+UMD bundles
453 - fs.mkdirSync(path.join('build', 'packages'));
454 - // create the dist folder for UMD bundles
455 - fs.mkdirSync(path.join('build', 'dist'));
416 +function handleRollupError(error) {
417 + loggedErrors.add(error);
418 + if (!error.code) {
419 + console.error(error);
420 + return;
421 + }
422 + console.error(
423 + `\x1b[31m-- ${error.code}${error.plugin ? ` (${error.plugin})` : ''} --`
424 + );
425 + console.error(error.message);
426 + const {file, line, column} = error.loc;
427 + if (file) {
428 + // This looks like an error from Rollup, e.g. missing export.
429 + // We'll use the accurate line numbers provided by Rollup but
430 + // use Babel code frame because it looks nicer.
431 + const rawLines = fs.readFileSync(file, 'utf-8');
432 + // column + 1 is required due to rollup counting column start position from 0
433 + // whereas babel-code-frame counts from 1
434 + const frame = codeFrame(rawLines, line, column + 1, {
435 + highlightCode: true,
436 + });
437 + console.error(frame);
438 + } else {
439 + // This looks like an error from a plugin (e.g. Babel).
440 + // In this case we'll resort to displaying the provided code frame
441 + // because we can't be sure the reported location is accurate.
442 + console.error(error.codeFrame);
443 + }
444 +}
445
457 - await Packaging.createFacebookWWWBuild();
458 - await Packaging.createReactNativeBuild();
459 - await Packaging.createReactNativeRTBuild();
460 - await Packaging.createReactNativeCSBuild();
446 +async function buildEverything() {
447 + await asyncRimRaf('build');
448
462 - // Run them serially for better console output
463 - // and to avoid any potential race conditions.
464 - for (const bundle of Bundles.bundles) {
465 - await createBundle(bundle, UMD_DEV);
466 - await createBundle(bundle, UMD_PROD);
467 - await createBundle(bundle, NODE_DEV);
468 - await createBundle(bundle, NODE_PROD);
469 - await createBundle(bundle, FB_DEV);
470 - await createBundle(bundle, FB_PROD);
471 - await createBundle(bundle, RN_DEV);
472 - await createBundle(bundle, RN_PROD);
473 - }
449 + // Run them serially for better console output
450 + // and to avoid any potential race conditions.
451 + for (const bundle of Bundles.bundles) {
452 + await createBundle(bundle, UMD_DEV);
453 + await createBundle(bundle, UMD_PROD);
454 + await createBundle(bundle, NODE_DEV);
455 + await createBundle(bundle, NODE_PROD);
456 + await createBundle(bundle, FB_DEV);
457 + await createBundle(bundle, FB_PROD);
458 + await createBundle(bundle, RN_DEV);
459 + await createBundle(bundle, RN_PROD);
460 + }
461
475 - if (syncFbsource) {
476 - await syncReactNative(path.join('build', 'react-native'), syncFbsource);
477 - await syncReactNativeRT(path.join('build', 'react-rt'), syncFbsource);
478 - await syncReactNativeCS(path.join('build', 'react-cs'), syncFbsource);
479 - } else if (syncWww) {
480 - await syncReactDom(path.join('build', 'facebook-www'), syncWww);
481 - }
462 + await Packaging.copyAllShims();
463 + await Packaging.prepareNpmPackages();
464
483 - console.log(Stats.printResults());
484 - // save the results for next run
485 - Stats.saveResults();
486 - if (shouldExtractErrors) {
487 - console.warn(
488 - '\nWarning: this build was created with --extract-errors enabled.\n' +
489 - 'this will result in extremely slow builds and should only be\n' +
490 - 'used when the error map needs to be rebuilt.\n'
491 - );
492 - }
493 - rimraf(npmPackagesTmpDir, err => {
494 - if (err) {
495 - console.error(err);
496 - process.exit(1);
497 - }
498 - });
499 - } catch (err) {
500 - console.error(err);
501 - process.exit(1);
465 + if (syncFBSourcePath) {
466 + await Sync.syncReactNative('build/react-native', syncFBSourcePath);
467 + await Sync.syncReactNativeRT('build/react-rt', syncFBSourcePath);
468 + await Sync.syncReactNativeCS('build/react-cs', syncFBSourcePath);
469 + } else if (syncWWWPath) {
470 + await Sync.syncReactDom('build/facebook-www', syncWWWPath);
471 }
503 -});
472 +
473 + console.log(Stats.printResults());
474 + Stats.saveResults();
475 +
476 + if (shouldExtractErrors) {
477 + console.warn(
478 + '\nWarning: this build was created with --extract-errors enabled.\n' +
479 + 'this will result in extremely slow builds and should only be\n' +
480 + 'used when the error map needs to be rebuilt.\n'
481 + );
482 + }
483 +}
484 +
485 +buildEverything();
scripts/rollup/packaging.js
+121 -182
@@ -1,40 +1,24 @@
1 'use strict';
2
3 -const basename = require('path').basename;
4 -const fs = require('fs');
5 -const join = require('path').join;
6 -const resolve = require('path').resolve;
3 +const {existsSync, readdirSync, unlinkSync} = require('fs');
4 const Bundles = require('./bundles');
8 -const asyncCopyTo = require('./utils').asyncCopyTo;
9 -const asyncExecuteCommand = require('./utils').asyncExecuteCommand;
10 -const asyncExtractTar = require('./utils').asyncExtractTar;
11 -
12 -const UMD_DEV = Bundles.bundleTypes.UMD_DEV;
13 -const UMD_PROD = Bundles.bundleTypes.UMD_PROD;
14 -const NODE_DEV = Bundles.bundleTypes.NODE_DEV;
15 -const NODE_PROD = Bundles.bundleTypes.NODE_PROD;
16 -const FB_DEV = Bundles.bundleTypes.FB_DEV;
17 -const FB_PROD = Bundles.bundleTypes.FB_PROD;
18 -const RN_DEV = Bundles.bundleTypes.RN_DEV;
19 -const RN_PROD = Bundles.bundleTypes.RN_PROD;
20 -
21 -const facebookWWW = 'facebook-www';
22 -
23 -// these files need to be copied to the react-native build
24 -const reactNativeSrcDependencies = [
25 - 'packages/shared/ReactTypes.js',
26 - 'packages/react-native-renderer/src/ReactNativeTypes.js',
27 -];
28 -
29 -// these files need to be copied to the react-rt build
30 -const reactNativeRTSrcDependencies = [
31 - 'packages/react-rt-renderer/src/ReactNativeRTTypes.js',
32 -];
33 -
34 -// these files need to be copied to the react-cs build
35 -const reactNativeCSSrcDependencies = [
36 - 'packages/react-cs-renderer/src/ReactNativeCSTypes.js',
37 -];
5 +const {
6 + asyncCopyTo,
7 + asyncExecuteCommand,
8 + asyncExtractTar,
9 + asyncRimRaf,
10 +} = require('./utils');
11 +
12 +const {
13 + UMD_DEV,
14 + UMD_PROD,
15 + NODE_DEV,
16 + NODE_PROD,
17 + FB_DEV,
18 + FB_PROD,
19 + RN_DEV,
20 + RN_PROD,
21 +} = Bundles.bundleTypes;
22
23 function getPackageName(name) {
24 if (name.indexOf('/') !== -1) {
@@ -43,172 +27,127 @@ function getPackageName(name) {
27 return name;
28 }
29
46 -async function createReactNativeBuild() {
47 - fs.mkdirSync(join('build', 'react-native'));
48 - fs.mkdirSync(join('build', 'react-native', 'shims'));
49 - const from = join('scripts', 'rollup', 'shims', 'react-native');
50 - const to = join('build', 'react-native', 'shims');
51 - await asyncCopyTo(from, to);
52 - await Promise.all(
53 - reactNativeSrcDependencies.map(srcDependency =>
54 - asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
55 - )
56 - );
57 -}
58 -
59 -async function createReactNativeRTBuild() {
60 - fs.mkdirSync(join('build', 'react-rt'));
61 - fs.mkdirSync(join('build', 'react-rt', 'shims'));
62 - const to = join('build', 'react-rt', 'shims');
63 - await Promise.all(
64 - reactNativeRTSrcDependencies.map(srcDependency =>
65 - asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
66 - )
67 - );
30 +function getBundleOutputPaths(bundleType, filename, packageName) {
31 + switch (bundleType) {
32 + case NODE_DEV:
33 + case NODE_PROD:
34 + return [`build/packages/${packageName}/cjs/${filename}`];
35 + case UMD_DEV:
36 + case UMD_PROD:
37 + return [
38 + `build/packages/${packageName}/umd/${filename}`,
39 + `build/dist/${filename}`,
40 + ];
41 + case FB_DEV:
42 + case FB_PROD:
43 + return [`build/facebook-www/${filename}`];
44 + case RN_DEV:
45 + case RN_PROD:
46 + switch (packageName) {
47 + case 'react-rt-renderer':
48 + return [`build/react-rt/${filename}`];
49 + case 'react-cs-renderer':
50 + return [`build/react-cs/${filename}`];
51 + case 'react-native-renderer':
52 + return [`build/react-native/${filename}`];
53 + default:
54 + throw new Error('Unknown RN package.');
55 + }
56 + default:
57 + throw new Error('Unknown bundle type.');
58 + }
59 }
60
70 -async function createReactNativeCSBuild() {
71 - fs.mkdirSync(join('build', 'react-cs'));
72 - fs.mkdirSync(join('build', 'react-cs', 'shims'));
73 - const to = join('build', 'react-cs', 'shims');
74 - await Promise.all(
75 - reactNativeCSSrcDependencies.map(srcDependency =>
76 - asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
77 - )
61 +async function copyWWWShims() {
62 + await asyncCopyTo(
63 + `${__dirname}/shims/facebook-www`,
64 + 'build/facebook-www/shims'
65 );
66 }
67
81 -async function createFacebookWWWBuild() {
82 - fs.mkdirSync(join('build', facebookWWW));
83 - fs.mkdirSync(join('build', facebookWWW, 'shims'));
84 - const from = join('scripts', 'rollup', 'shims', facebookWWW);
85 - const to = join('build', facebookWWW, 'shims');
86 - await asyncCopyTo(from, to);
68 +async function copyRNShims() {
69 + await Promise.all([
70 + // React Native
71 + asyncCopyTo(`${__dirname}/shims/react-native`, 'build/react-native/shims'),
72 + asyncCopyTo(
73 + require.resolve('shared/ReactTypes.js'),
74 + 'build/react-native/shims/ReactTypes.js'
75 + ),
76 + asyncCopyTo(
77 + require.resolve('react-native-renderer/src/ReactNativeTypes.js'),
78 + 'build/react-native/shims/ReactNativeTypes.js'
79 + ),
80 + // React Native CS
81 + asyncCopyTo(
82 + require.resolve('react-cs-renderer/src/ReactNativeCSTypes.js'),
83 + 'build/react-cs/shims/ReactNativeCSTypes.js'
84 + ),
85 + // React Native RT
86 + asyncCopyTo(
87 + require.resolve('react-rt-renderer/src/ReactNativeRTTypes.js'),
88 + 'build/react-rt/shims/ReactNativeRTTypes.js'
89 + ),
90 + ]);
91 }
92
89 -async function copyBundleIntoNodePackage(
90 - packageName,
91 - filename,
92 - bundleType,
93 - npmPackagesTmpDir
94 -) {
95 - const packageDirectory = resolve(`${npmPackagesTmpDir}/${packageName}`);
96 - if (!fs.existsSync(packageDirectory)) {
97 - return;
98 - }
99 - let from = resolve(`./build/${filename}`);
100 - let to = `${packageDirectory}/${filename}`;
101 - // for UMD bundles we have to move the files into a umd directory
102 - // within the package directory. we also need to set the from
103 - // to be the root build from directory
104 - if (bundleType === UMD_DEV || bundleType === UMD_PROD) {
105 - const distDirectory = `${packageDirectory}/umd`;
106 - // create a dist directory if not created
107 - if (!fs.existsSync(distDirectory)) {
108 - fs.mkdirSync(distDirectory);
109 - }
110 - from = resolve(`./build/dist/${filename}`);
111 - to = `${packageDirectory}/umd/${filename}`;
112 - }
113 - // for NODE bundles we have to move the files into a cjs directory
114 - // within the package directory. we also need to set the from
115 - // to be the root build from directory
116 - if (bundleType === NODE_DEV || bundleType === NODE_PROD) {
117 - const distDirectory = `${packageDirectory}/cjs`;
118 - // create a dist directory if not created
119 - if (!fs.existsSync(distDirectory)) {
120 - fs.mkdirSync(distDirectory);
121 - }
122 - to = `${packageDirectory}/cjs/${filename}`;
123 - }
124 - await asyncCopyTo(from, to);
125 - // delete the old file if this is a not a UMD bundle
126 - if (bundleType !== UMD_DEV && bundleType !== UMD_PROD) {
127 - fs.unlinkSync(from);
128 - }
93 +async function copyAllShims() {
94 + await Promise.all([copyWWWShims(), copyRNShims()]);
95 }
96
131 -async function copyNodePackageTemplate(packageName, npmPackagesTmpDir) {
132 - const from = resolve(`./packages/${packageName}`);
133 - const to = resolve(`${npmPackagesTmpDir}/${packageName}`);
134 - const npmFrom = resolve(`${from}/npm`);
135 - if (!fs.existsSync(npmFrom)) {
136 - // The package is not meant for npm consumption.
137 - return;
138 - }
139 - if (fs.existsSync(to)) {
140 - // We already created this package (e.g. due to another entry point).
141 - return;
142 - }
143 - await asyncCopyTo(npmFrom, to);
144 - await asyncCopyTo(resolve(`${from}/package.json`), `${to}/package.json`);
145 - await asyncCopyTo(resolve(`${from}/README.md`), `${to}/README.md`);
146 - await asyncCopyTo(resolve('./LICENSE'), `${to}/LICENSE`);
97 +function getTarOptions(tgzName, packageName) {
98 + // Files inside the `npm pack`ed archive start
99 + // with "package/" in their paths. We'll undo
100 + // this during extraction.
101 + const CONTENTS_FOLDER = 'package';
102 + return {
103 + src: tgzName,
104 + dest: `build/packages/${packageName}`,
105 + tar: {
106 + entries: [CONTENTS_FOLDER],
107 + map(header) {
108 + if (header.name.indexOf(CONTENTS_FOLDER + '/') === 0) {
109 + header.name = header.name.substring(CONTENTS_FOLDER.length + 1);
110 + }
111 + },
112 + },
113 + };
114 }
115
149 -async function packForNpmAndUnpack(packageName, npmPackagesTmpDir) {
150 - const packageTmpDir = resolve(`${npmPackagesTmpDir}/${packageName}`);
151 - const extractTmpDir = resolve(`${packageTmpDir}/extract`);
152 - const build = resolve(`./build/packages/${packageName}`);
153 - const npmFrom = resolve(`./packages/${packageName}/npm`);
154 - if (!fs.existsSync(npmFrom)) {
155 - return;
156 - }
157 - let tgzName = await asyncExecuteCommand(`cd ${packageTmpDir} && npm pack`);
158 - // In npm packages, files are grouped into a root directory(named 'package').
159 - // We only copy the packed files instead of extract the root 'package' directly to build directory
160 - await asyncExtractTar({
161 - src: `${packageTmpDir}/${tgzName.trim()}`,
162 - dest: extractTmpDir,
163 - });
164 - await asyncCopyTo(`${extractTmpDir}/package`, build);
116 +async function prepareNpmPackage(name) {
117 + await Promise.all([
118 + asyncCopyTo('LICENSE', `build/packages/${name}/LICENSE`),
119 + asyncCopyTo(
120 + `packages/${name}/package.json`,
121 + `build/packages/${name}/package.json`
122 + ),
123 + asyncCopyTo(
124 + `packages/${name}/README.md`,
125 + `build/packages/${name}/README.md`
126 + ),
127 + asyncCopyTo(`packages/${name}/npm`, `build/packages/${name}`),
128 + ]);
129 + const tgzName = (await asyncExecuteCommand(
130 + `npm pack build/packages/${name}`
131 + )).trim();
132 + await asyncRimRaf(`build/packages/${name}`);
133 + await asyncExtractTar(getTarOptions(tgzName, name));
134 + unlinkSync(tgzName);
135 }
136
167 -async function createNodePackage(
168 - bundleType,
169 - packageName,
170 - filename,
171 - npmPackagesTmpDir
172 -) {
173 - // the only case where we don't want to copy the package is for FB bundles
174 - if (bundleType === FB_DEV || bundleType === FB_PROD) {
137 +async function prepareNpmPackages() {
138 + if (!existsSync('build/packages')) {
139 + // We didn't build any npm packages.
140 return;
141 }
177 - await copyNodePackageTemplate(packageName, npmPackagesTmpDir);
178 - await copyBundleIntoNodePackage(
179 - packageName,
180 - filename,
181 - bundleType,
182 - npmPackagesTmpDir
142 + const builtPackageFolders = readdirSync('build/packages').filter(
143 + dir => dir.charAt(0) !== '.'
144 );
184 - // Packing packages locally, simulate npm publish,
185 - // Then unpacking generated packages to build directory
186 - await packForNpmAndUnpack(packageName, npmPackagesTmpDir);
187 -}
188 -
189 -function getOutputPathRelativeToBuildFolder(bundleType, filename, hasteName) {
190 - if (bundleType === FB_DEV || bundleType === FB_PROD) {
191 - return `${facebookWWW}/${filename}`;
192 - } else if (bundleType === UMD_DEV || bundleType === UMD_PROD) {
193 - return `dist/${filename}`;
194 - } else if (bundleType === RN_DEV || bundleType === RN_PROD) {
195 - if (hasteName === 'ReactRTRenderer') {
196 - return `react-rt/${filename}`;
197 - } else if (hasteName === 'ReactCSRenderer') {
198 - return `react-cs/${filename}`;
199 - } else {
200 - return `react-native/${filename}`;
201 - }
202 - }
203 - return filename;
145 + await Promise.all(builtPackageFolders.map(prepareNpmPackage));
146 }
147
148 module.exports = {
207 - getOutputPathRelativeToBuildFolder,
208 - createNodePackage,
149 + copyAllShims,
150 getPackageName,
210 - createFacebookWWWBuild,
211 - createReactNativeBuild,
212 - createReactNativeRTBuild,
213 - createReactNativeCSBuild,
151 + getBundleOutputPaths,
152 + prepareNpmPackages,
153 };
scripts/rollup/utils.js
+64 -35
@@ -1,60 +1,89 @@
1 'use strict';
2
3 const ncp = require('ncp').ncp;
4 -const join = require('path').join;
5 -const resolve = require('path').resolve;
4 +const path = require('path');
5 +const mkdirp = require('mkdirp');
6 +const rimraf = require('rimraf');
7 const exec = require('child_process').exec;
8 const targz = require('targz');
9
10 function asyncCopyTo(from, to) {
10 - return new Promise(_resolve => {
11 - ncp(from, to, error => {
12 - if (error) {
13 - console.error(error);
14 - process.exit(1);
15 - }
16 - _resolve();
17 - });
18 - });
19 -}
20 -
21 -function resolvePath(path) {
22 - if (path[0] === '~') {
23 - return join(process.env.HOME, path.slice(1));
24 - } else {
25 - return resolve(path);
26 - }
11 + return asyncMkDirP(path.dirname(to)).then(
12 + () =>
13 + new Promise((resolve, reject) => {
14 + ncp(from, to, error => {
15 + if (error) {
16 + // Wrap to have a useful stack trace.
17 + reject(new Error(error));
18 + return;
19 + }
20 + resolve();
21 + });
22 + })
23 + );
24 }
25
26 function asyncExecuteCommand(command) {
30 - return new Promise(_resolve =>
27 + return new Promise((resolve, reject) =>
28 exec(command, (error, stdout) => {
32 - if (!error) {
33 - _resolve(stdout);
34 - } else {
35 - console.error(error);
36 - process.exit(1);
29 + if (error) {
30 + reject(error);
31 + return;
32 }
33 + resolve(stdout);
34 })
35 );
36 }
37
38 function asyncExtractTar(options) {
43 - return new Promise(_resolve =>
39 + return new Promise((resolve, reject) =>
40 targz.decompress(options, error => {
45 - if (!error) {
46 - _resolve();
47 - } else {
48 - console.error(error);
49 - process.exit(1);
41 + if (error) {
42 + reject(error);
43 + return;
44 }
45 + resolve();
46 })
47 );
48 }
49
50 +function asyncMkDirP(filepath) {
51 + return new Promise((resolve, reject) =>
52 + mkdirp(filepath, error => {
53 + if (error) {
54 + reject(error);
55 + return;
56 + }
57 + resolve();
58 + })
59 + );
60 +}
61 +
62 +function asyncRimRaf(filepath) {
63 + return new Promise((resolve, reject) =>
64 + rimraf(filepath, error => {
65 + if (error) {
66 + reject(error);
67 + return;
68 + }
69 + resolve();
70 + })
71 + );
72 +}
73 +
74 +function resolvePath(filepath) {
75 + if (filepath[0] === '~') {
76 + return path.join(process.env.HOME, filepath.slice(1));
77 + } else {
78 + return path.resolve(filepath);
79 + }
80 +}
81 +
82 module.exports = {
56 - asyncCopyTo: asyncCopyTo,
57 - resolvePath: resolvePath,
58 - asyncExecuteCommand: asyncExecuteCommand,
59 - asyncExtractTar: asyncExtractTar,
83 + asyncCopyTo,
84 + resolvePath,
85 + asyncExecuteCommand,
86 + asyncExtractTar,
87 + asyncMkDirP,
88 + asyncRimRaf,
89 };
yarn.lock
-4
@@ -4788,10 +4788,6 @@ uuid@^3.0.0:
4788 version "3.0.1"
4789 resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
4790
4791 -uuid@^3.1.0:
4792 - version "3.1.0"
4793 - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
4794 -
4791 v8flags@^2.0.10:
4792 version "2.1.1"
4793 resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"