11
const chalk = require('chalk');
12
const resolve = require('@rollup/plugin-node-resolve').nodeResolve;
13
const fs = require('fs');
14
+const path = require('path');
15
const argv = require('minimist')(process.argv.slice(2));
16
const Modules = require('./modules');
17
const Bundles = require('./bundles');
149
presets: [],
150
plugins: [...babelPlugins],
151
babelHelpers: 'bundled',
152
+ sourcemap: false,
153
};
154
if (isDevelopment) {
155
options.plugins.push(
317
}
318
}
319
320
+function getBundleTypeFlags(bundleType) {
321
+ const isUMDBundle =
322
+ bundleType === UMD_DEV ||
323
+ bundleType === UMD_PROD ||
324
+ bundleType === UMD_PROFILING;
325
+ const isFBWWWBundle =
326
+ bundleType === FB_WWW_DEV ||
327
+ bundleType === FB_WWW_PROD ||
328
+ bundleType === FB_WWW_PROFILING;
329
+ const isRNBundle =
330
+ bundleType === RN_OSS_DEV ||
331
+ bundleType === RN_OSS_PROD ||
332
+ bundleType === RN_OSS_PROFILING ||
333
+ bundleType === RN_FB_DEV ||
334
+ bundleType === RN_FB_PROD ||
335
+ bundleType === RN_FB_PROFILING;
336
+
337
+ const isFBRNBundle =
338
+ bundleType === RN_FB_DEV ||
339
+ bundleType === RN_FB_PROD ||
340
+ bundleType === RN_FB_PROFILING;
341
+
342
+ const shouldStayReadable = isFBWWWBundle || isRNBundle || forcePrettyOutput;
343
+
344
+ const shouldBundleDependencies =
345
+ bundleType === UMD_DEV ||
346
+ bundleType === UMD_PROD ||
347
+ bundleType === UMD_PROFILING;
348
+
349
+ return {
350
+ isUMDBundle,
351
+ isFBWWWBundle,
352
+ isRNBundle,
353
+ isFBRNBundle,
354
+ shouldBundleDependencies,
355
+ shouldStayReadable,
356
+ };
357
+}
358
+
359
function forbidFBJSImports() {
360
return {
361
name: 'forbidFBJSImports',
386
const forks = Modules.getForks(bundleType, entry, moduleType, bundle);
387
const isProduction = isProductionBundleType(bundleType);
388
const isProfiling = isProfilingBundleType(bundleType);
348
- const isUMDBundle =
349
- bundleType === UMD_DEV ||
350
- bundleType === UMD_PROD ||
351
- bundleType === UMD_PROFILING;
352
- const isFBWWWBundle =
353
- bundleType === FB_WWW_DEV ||
354
- bundleType === FB_WWW_PROD ||
355
- bundleType === FB_WWW_PROFILING;
356
- const isRNBundle =
357
- bundleType === RN_OSS_DEV ||
358
- bundleType === RN_OSS_PROD ||
359
- bundleType === RN_OSS_PROFILING ||
360
- bundleType === RN_FB_DEV ||
361
- bundleType === RN_FB_PROD ||
362
- bundleType === RN_FB_PROFILING;
363
- const shouldStayReadable = isFBWWWBundle || isRNBundle || forcePrettyOutput;
389
+
390
+ const {isUMDBundle, shouldStayReadable} = getBundleTypeFlags(bundleType);
391
+
392
+ const needsMinifiedByClosure = isProduction && bundleType !== ESM_PROD;
393
+
394
+ // Any other packages that should specifically _not_ have sourcemaps
395
+ const sourcemapPackageExcludes = [
396
+ // Having `//#sourceMappingUrl` for the `react-debug-tools` prod bundle breaks
397
+ // `ReactDevToolsHooksIntegration-test.js`, because it changes Node's generated
398
+ // stack traces and thus alters the hook name parsing behavior.
399
+ // Also, this is an internal-only package that doesn't need sourcemaps anyway
400
+ 'react-debug-tools',
401
+ ];
402
+
403
+ // Generate sourcemaps for true "production" build artifacts
404
+ // that will be used by bundlers, such as `react-dom.production.min.js`.
405
+ // Also include profiling builds as well.
406
+ // UMD builds are rarely used and not worth having sourcemaps.
407
+ const needsSourcemaps =
408
+ needsMinifiedByClosure &&
409
+ !isUMDBundle &&
410
+ !sourcemapPackageExcludes.includes(entry) &&
411
+ !shouldStayReadable;
412
+
413
return [
414
// Keep dynamic imports as externals
415
dynamicImports(),
419
const transformed = flowRemoveTypes(code);
420
return {
421
code: transformed.toString(),
373
- map: transformed.generateMap(),
422
+ map: null,
423
};
424
},
425
},
448
),
449
// Remove 'use strict' from individual source files.
450
{
451
+ name: "remove 'use strict'",
452
transform(source) {
453
return source.replace(/['"]use strict["']/g, '');
454
},
470
// I'm going to port "art" to ES modules to avoid this problem.
471
// Please don't enable this for anything else!
472
isUMDBundle && entry === 'react-art' && commonjs(),
423
- // Apply dead code elimination and/or minification.
424
- // closure doesn't yet support leaving ESM imports intact
425
- isProduction &&
426
- bundleType !== ESM_PROD &&
427
- closure({
428
- compilation_level: 'SIMPLE',
429
- language_in: 'ECMASCRIPT_2020',
430
- language_out:
431
- bundleType === NODE_ES2015
432
- ? 'ECMASCRIPT_2020'
433
- : bundleType === BROWSER_SCRIPT
434
- ? 'ECMASCRIPT5'
435
- : 'ECMASCRIPT5_STRICT',
436
- emit_use_strict:
437
- bundleType !== BROWSER_SCRIPT &&
438
- bundleType !== ESM_PROD &&
439
- bundleType !== ESM_DEV,
440
- env: 'CUSTOM',
441
- warning_level: 'QUIET',
442
- apply_input_source_maps: false,
443
- use_types_for_optimization: false,
444
- process_common_js_modules: false,
445
- rewrite_polyfills: false,
446
- inject_libraries: false,
447
- allow_dynamic_import: true,
448
-
449
- // Don't let it create global variables in the browser.
450
- // https://github.com/facebook/react/issues/10909
451
- assume_function_wrapper: !isUMDBundle,
452
- renaming: !shouldStayReadable,
453
- }),
454
- // Add the whitespace back if necessary.
455
- shouldStayReadable &&
456
- prettier({
457
- parser: 'flow',
458
- singleQuote: false,
459
- trailingComma: 'none',
460
- bracketSpacing: true,
461
- }),
473
// License and haste headers, top-level `if` blocks.
474
{
475
+ name: 'license-and-headers',
476
renderChunk(source) {
477
return Wrappers.wrapBundle(
478
source,
484
);
485
},
486
},
487
+ // Apply dead code elimination and/or minification.
488
+ // closure doesn't yet support leaving ESM imports intact
489
+ needsMinifiedByClosure &&
490
+ closure(
491
+ {
492
+ compilation_level: 'SIMPLE',
493
+ language_in: 'ECMASCRIPT_2020',
494
+ language_out:
495
+ bundleType === NODE_ES2015
496
+ ? 'ECMASCRIPT_2020'
497
+ : bundleType === BROWSER_SCRIPT
498
+ ? 'ECMASCRIPT5'
499
+ : 'ECMASCRIPT5_STRICT',
500
+ emit_use_strict:
501
+ bundleType !== BROWSER_SCRIPT &&
502
+ bundleType !== ESM_PROD &&
503
+ bundleType !== ESM_DEV,
504
+ env: 'CUSTOM',
505
+ warning_level: 'QUIET',
506
+ source_map_include_content: true,
507
+ use_types_for_optimization: false,
508
+ process_common_js_modules: false,
509
+ rewrite_polyfills: false,
510
+ inject_libraries: false,
511
+ allow_dynamic_import: true,
512
+
513
+ // Don't let it create global variables in the browser.
514
+ // https://github.com/facebook/react/issues/10909
515
+ assume_function_wrapper: !isUMDBundle,
516
+ renaming: !shouldStayReadable,
517
+ },
518
+ {needsSourcemaps}
519
+ ),
520
+ // Add the whitespace back if necessary.
521
+ shouldStayReadable &&
522
+ prettier({
523
+ parser: 'flow',
524
+ singleQuote: false,
525
+ trailingComma: 'none',
526
+ bracketSpacing: true,
527
+ }),
528
+ needsSourcemaps && {
529
+ name: 'generate-prod-bundle-sourcemaps',
530
+ async renderChunk(codeAfterLicense, chunk, options, meta) {
531
+ // We want to generate a sourcemap that shows the production bundle source
532
+ // as it existed before Closure Compiler minified that chunk, rather than
533
+ // showing the "original" individual source files. This better shows
534
+ // what is actually running in the app.
535
+
536
+ // Use a path like `node_modules/react/cjs/react.production.min.js.map` for the sourcemap file
537
+ const finalSourcemapPath = options.file.replace('.js', '.js.map');
538
+ const finalSourcemapFilename = path.basename(finalSourcemapPath);
539
+ const outputFolder = path.dirname(options.file);
540
+
541
+ // Read the sourcemap that Closure wrote to disk
542
+ const sourcemapAfterClosure = JSON.parse(
543
+ fs.readFileSync(finalSourcemapPath, 'utf8')
544
+ );
545
+
546
+ // Represent the "original" bundle as a file with no `.min` in the name
547
+ const filenameWithoutMin = filename.replace('.min', '');
548
+ // There's _one_ artifact where the incoming filename actually contains
549
+ // a folder name: "use-sync-external-store-shim/with-selector.production.js".
550
+ // The output path already has the right structure, but we need to strip this
551
+ // down to _just_ the JS filename.
552
+ const preMinifiedFilename = path.basename(filenameWithoutMin);
553
+
554
+ // CC generated a file list that only contains the tempfile name.
555
+ // Replace that with a more meaningful "source" name for this bundle
556
+ // that represents "the bundled source before minification".
557
+ sourcemapAfterClosure.sources = [preMinifiedFilename];
558
+ sourcemapAfterClosure.file = filename;
559
+
560
+ // We'll write the pre-minified source to disk as a separate file.
561
+ // Because it sits on disk, there's no need to have it in the `sourcesContent` array.
562
+ // That also makes the file easier to read, and available for use by scripts.
563
+ // This should be the only file in the array.
564
+ const [preMinifiedBundleSource] =
565
+ sourcemapAfterClosure.sourcesContent;
566
+
567
+ // Remove this entirely - we're going to write the file to disk instead.
568
+ delete sourcemapAfterClosure.sourcesContent;
569
+
570
+ const preMinifiedBundlePath = path.join(
571
+ outputFolder,
572
+ preMinifiedFilename
573
+ );
574
+
575
+ // Write the original source to disk as a separate file
576
+ fs.writeFileSync(preMinifiedBundlePath, preMinifiedBundleSource);
577
+
578
+ // Overwrite the Closure-generated file with the final combined sourcemap
579
+ fs.writeFileSync(
580
+ finalSourcemapPath,
581
+ JSON.stringify(sourcemapAfterClosure)
582
+ );
583
+
584
+ // Add the sourcemap URL to the actual bundle, so that tools pick it up
585
+ const sourceWithMappingUrl =
586
+ codeAfterLicense +
587
+ `\n//# sourceMappingURL=${finalSourcemapFilename}`;
588
+
589
+ return {
590
+ code: sourceWithMappingUrl,
591
+ map: null,
592
+ };
593
+ },
594
+ },
595
// Record bundle size.
596
sizes({
597
getSize: (size, gzip) => {
697
const format = getFormat(bundleType);
698
const packageName = Packaging.getPackageName(bundle.entry);
699
580
- const isFBWWWBundle =
581
- bundleType === FB_WWW_DEV ||
582
- bundleType === FB_WWW_PROD ||
583
- bundleType === FB_WWW_PROFILING;
584
-
585
- const isFBRNBundle =
586
- bundleType === RN_FB_DEV ||
587
- bundleType === RN_FB_PROD ||
588
- bundleType === RN_FB_PROFILING;
700
+ const {isFBWWWBundle, isFBRNBundle, shouldBundleDependencies} =
701
+ getBundleTypeFlags(bundleType);
702
703
let resolvedEntry = resolveEntryFork(
704
require.resolve(bundle.entry),
705
isFBWWWBundle || isFBRNBundle
706
);
707
595
- const shouldBundleDependencies =
596
- bundleType === UMD_DEV ||
597
- bundleType === UMD_PROD ||
598
- bundleType === UMD_PROFILING;
708
const peerGlobals = Modules.getPeerGlobals(bundle.externals, bundleType);
709
let externals = Object.keys(peerGlobals);
710
if (!shouldBundleDependencies) {