@samitouri / QOS-React-2 / commits / c47c306a7a

refactor[ci/build]: preserve header format in artifacts (#27671)

In order to make Haste work with React's artifacts, It is important to keep headers in this format: ``` /** * ... ... * ... */ ``` For optimization purposes, Closure compiler will actually modify these headers by removing * prefixes, which is expected. We should pass sources to the compiler without license headers, with these changes the current flow will be: 1. Apply top-level definitions. For UMD-bundles, for example, or DEV-only bundles (e. g. `if (__DEV__) { ...`) 2. Apply licence headers for artifacts with sourcemaps: oss-production and oss-profiling bundles, they don't need to preserve the header format to comply with Haste. We need to apply these headers before passing sources to Closure, so it can build correct mappings for sourcemaps. 3. Pass these sources to closure compiler for minification and sourcemaps building. 4. Apply licence headers for artifacts without sourcemaps: dev bundles, fb bundles. This way the header style will be preserved and not changed by Closure.

Ruslan Lesiutin committed Nov 9, 2023 at 16:00 UTC c47c306a7a23d3c796b148d303764e2832da480c
2 files changed +246 -113
scripts/rollup/build.js
+34 -5
@@ -470,11 +470,10 @@ function getPlugins(
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(),
473 - // License and haste headers, top-level `if` blocks.
473 {
475 - name: 'license-and-headers',
474 + name: 'top-level-definitions',
475 renderChunk(source) {
477 - return Wrappers.wrapBundle(
476 + return Wrappers.wrapWithTopLevelDefinitions(
477 source,
478 bundleType,
479 globalName,
@@ -484,6 +483,21 @@ function getPlugins(
483 );
484 },
485 },
486 + // License and haste headers for artifacts with sourcemaps
487 + // For artifacts with sourcemaps we apply these headers
488 + // before passing sources to the Closure compiler, which will be building sourcemaps
489 + needsSourcemaps && {
490 + name: 'license-and-signature-header-for-artifacts-with-sourcemaps',
491 + renderChunk(source) {
492 + return Wrappers.wrapWithLicenseHeader(
493 + source,
494 + bundleType,
495 + globalName,
496 + filename,
497 + moduleType
498 + );
499 + },
500 + },
501 // Apply dead code elimination and/or minification.
502 // closure doesn't yet support leaving ESM imports intact
503 needsMinifiedByClosure &&
@@ -527,7 +541,7 @@ function getPlugins(
541 }),
542 needsSourcemaps && {
543 name: 'generate-prod-bundle-sourcemaps',
530 - async renderChunk(codeAfterLicense, chunk, options, meta) {
544 + async renderChunk(minifiedCodeWithChangedHeader, chunk, options, meta) {
545 // We want to generate a sourcemap that shows the production bundle source
546 // as it existed before Closure Compiler minified that chunk, rather than
547 // showing the "original" individual source files. This better shows
@@ -583,7 +597,7 @@ function getPlugins(
597
598 // Add the sourcemap URL to the actual bundle, so that tools pick it up
599 const sourceWithMappingUrl =
586 - codeAfterLicense +
600 + minifiedCodeWithChangedHeader +
601 `\n//# sourceMappingURL=${finalSourcemapFilename}`;
602
603 return {
@@ -592,6 +606,21 @@ function getPlugins(
606 };
607 },
608 },
609 + // License and haste headers for artifacts without sourcemaps
610 + // Primarily used for FB-artifacts, which should preserve specific format of the header
611 + // Which potentially can be changed by Closure minification
612 + !needsSourcemaps && {
613 + name: 'license-and-signature-header-for-artifacts-without-sourcemaps',
614 + renderChunk(source) {
615 + return Wrappers.wrapWithLicenseHeader(
616 + source,
617 + bundleType,
618 + globalName,
619 + filename,
620 + moduleType
621 + );
622 + },
623 + },
624 // Record bundle size.
625 sizes({
626 getSize: (size, gzip) => {
scripts/rollup/wrappers.js
+212 -108
@@ -53,7 +53,178 @@ const license = ` * Copyright (c) Meta Platforms, Inc. and affiliates.
53 * This source code is licensed under the MIT license found in the
54 * LICENSE file in the root directory of this source tree.`;
55
56 -const wrappers = {
56 +const topLevelDefinitionWrappers = {
57 + /***************** NODE_ES2015 *****************/
58 + [NODE_ES2015](source, globalName, filename, moduleType) {
59 + return `'use strict';
60 +
61 +${source}`;
62 + },
63 +
64 + /***************** ESM_DEV *****************/
65 + [ESM_DEV](source, globalName, filename, moduleType) {
66 + return source;
67 + },
68 +
69 + /***************** ESM_PROD *****************/
70 + [ESM_PROD](source, globalName, filename, moduleType) {
71 + return source;
72 + },
73 +
74 + /***************** BUN_DEV *****************/
75 + [BUN_DEV](source, globalName, filename, moduleType) {
76 + return source;
77 + },
78 +
79 + /***************** BUN_PROD *****************/
80 + [BUN_PROD](source, globalName, filename, moduleType) {
81 + return source;
82 + },
83 +
84 + /***************** UMD_DEV *****************/
85 + [UMD_DEV](source, globalName, filename, moduleType) {
86 + return source;
87 + },
88 +
89 + /***************** UMD_PROD *****************/
90 + [UMD_PROD](source, globalName, filename, moduleType) {
91 + return `(function(){${source}})();`;
92 + },
93 +
94 + /***************** UMD_PROFILING *****************/
95 + [UMD_PROFILING](source, globalName, filename, moduleType) {
96 + return `(function(){${source}})();`;
97 + },
98 +
99 + /***************** NODE_DEV *****************/
100 + [NODE_DEV](source, globalName, filename, moduleType) {
101 + return `'use strict';
102 +
103 +if (process.env.NODE_ENV !== "production") {
104 + (function() {
105 +${source}
106 + })();
107 +}`;
108 + },
109 +
110 + /***************** NODE_PROD *****************/
111 + [NODE_PROD](source, globalName, filename, moduleType) {
112 + return source;
113 + },
114 +
115 + /***************** NODE_PROFILING *****************/
116 + [NODE_PROFILING](source, globalName, filename, moduleType) {
117 + return source;
118 + },
119 +
120 + /****************** FB_WWW_DEV ******************/
121 + [FB_WWW_DEV](source, globalName, filename, moduleType) {
122 + return `'use strict';
123 +
124 +if (__DEV__) {
125 + (function() {
126 +${source}
127 + })();
128 +}`;
129 + },
130 +
131 + /****************** FB_WWW_PROD ******************/
132 + [FB_WWW_PROD](source, globalName, filename, moduleType) {
133 + return source;
134 + },
135 +
136 + /****************** FB_WWW_PROFILING ******************/
137 + [FB_WWW_PROFILING](source, globalName, filename, moduleType) {
138 + return source;
139 + },
140 +
141 + /****************** RN_OSS_DEV ******************/
142 + [RN_OSS_DEV](source, globalName, filename, moduleType) {
143 + return `'use strict';
144 +
145 +if (__DEV__) {
146 + (function() {
147 +${source}
148 + })();
149 +}`;
150 + },
151 +
152 + /****************** RN_OSS_PROD ******************/
153 + [RN_OSS_PROD](source, globalName, filename, moduleType) {
154 + return source;
155 + },
156 +
157 + /****************** RN_OSS_PROFILING ******************/
158 + [RN_OSS_PROFILING](source, globalName, filename, moduleType) {
159 + return source;
160 + },
161 +
162 + /****************** RN_FB_DEV ******************/
163 + [RN_FB_DEV](source, globalName, filename, moduleType) {
164 + return `'use strict';
165 +
166 +if (__DEV__) {
167 + (function() {
168 +${source}
169 + })();
170 +}`;
171 + },
172 +
173 + /****************** RN_FB_PROD ******************/
174 + [RN_FB_PROD](source, globalName, filename, moduleType) {
175 + return source;
176 + },
177 +
178 + /****************** RN_FB_PROFILING ******************/
179 + [RN_FB_PROFILING](source, globalName, filename, moduleType) {
180 + return source;
181 + },
182 +};
183 +
184 +const reconcilerWrappers = {
185 + /***************** NODE_DEV (reconciler only) *****************/
186 + [NODE_DEV](source, globalName, filename, moduleType) {
187 + return `'use strict';
188 +
189 +if (process.env.NODE_ENV !== "production") {
190 + module.exports = function $$$reconciler($$$config) {
191 + var exports = {};
192 +${source}
193 + return exports;
194 + };
195 + module.exports.default = module.exports;
196 + Object.defineProperty(module.exports, "__esModule", { value: true });
197 +}
198 +`;
199 + },
200 +
201 + /***************** NODE_PROD (reconciler only) *****************/
202 + [NODE_PROD](source, globalName, filename, moduleType) {
203 + return `module.exports = function $$$reconciler($$$config) {
204 +
205 + var exports = {};
206 +${source}
207 + return exports;
208 +};
209 +module.exports.default = module.exports;
210 +Object.defineProperty(module.exports, "__esModule", { value: true });
211 +`;
212 + },
213 +
214 + /***************** NODE_PROFILING (reconciler only) *****************/
215 + [NODE_PROFILING](source, globalName, filename, moduleType) {
216 + return `module.exports = function $$$reconciler($$$config) {
217 + var exports = {};
218 +${source}
219 + return exports;
220 +};
221 +module.exports.default = module.exports;
222 +Object.defineProperty(module.exports, "__esModule", { value: true });
223 +`;
224 + },
225 +};
226 +
227 +const licenseHeaderWrappers = {
228 /***************** NODE_ES2015 *****************/
229 [NODE_ES2015](source, globalName, filename, moduleType) {
230 return `/**
@@ -63,8 +234,6 @@ const wrappers = {
234 ${license}
235 */
236
66 -'use strict';
67 -
237 ${source}`;
238 },
239
@@ -107,7 +276,7 @@ ${source}`;
276 /***************** BUN_PROD *****************/
277 [BUN_PROD](source, globalName, filename, moduleType) {
278 return `/**
110 -* @license React
279 + * @license React
280 * ${filename}
281 *
282 ${license}
@@ -124,6 +293,7 @@ ${source}`;
293 *
294 ${license}
295 */
296 +
297 ${source}`;
298 },
299
@@ -135,7 +305,8 @@ ${source}`;
305 *
306 ${license}
307 */
138 -(function(){${source}})();`;
308 +
309 +${source}`;
310 },
311
312 /***************** UMD_PROFILING *****************/
@@ -146,7 +317,8 @@ ${license}
317 *
318 ${license}
319 */
149 -(function(){${source}})();`;
320 +
321 +${source}`;
322 },
323
324 /***************** NODE_DEV *****************/
@@ -158,13 +330,7 @@ ${license}
330 ${license}
331 */
332
161 -'use strict';
162 -
163 -if (process.env.NODE_ENV !== "production") {
164 - (function() {
165 -${source}
166 - })();
167 -}`;
333 +${source}`;
334 },
335
336 /***************** NODE_PROD *****************/
@@ -175,6 +341,7 @@ ${source}
341 *
342 ${license}
343 */
344 +
345 ${source}`;
346 },
347
@@ -186,13 +353,13 @@ ${source}`;
353 *
354 ${license}
355 */
356 +
357 ${source}`;
358 },
359
360 /****************** FB_WWW_DEV ******************/
361 [FB_WWW_DEV](source, globalName, filename, moduleType) {
362 return `/**
195 - * @preserve
363 ${license}
364 *
365 * @noflow
@@ -201,19 +368,12 @@ ${license}
368 * @preserve-invariant-messages
369 */
370
204 -'use strict';
205 -
206 -if (__DEV__) {
207 - (function() {
208 -${source}
209 - })();
210 -}`;
371 +${source}`;
372 },
373
374 /****************** FB_WWW_PROD ******************/
375 [FB_WWW_PROD](source, globalName, filename, moduleType) {
376 return `/**
216 - * @preserve
377 ${license}
378 *
379 * @noflow
@@ -228,7 +388,6 @@ ${source}`;
388 /****************** FB_WWW_PROFILING ******************/
389 [FB_WWW_PROFILING](source, globalName, filename, moduleType) {
390 return `/**
231 - * @preserve
391 ${license}
392 *
393 * @noflow
@@ -243,7 +402,6 @@ ${source}`;
402 /****************** RN_OSS_DEV ******************/
403 [RN_OSS_DEV](source, globalName, filename, moduleType) {
404 return signFile(`/**
246 - * @preserve
405 ${license}
406 *
407 * @noflow
@@ -253,19 +411,12 @@ ${license}
411 * ${getSigningToken()}
412 */
413
256 -'use strict';
257 -
258 -if (__DEV__) {
259 - (function() {
260 -${source}
261 - })();
262 -}`);
414 +${source}`);
415 },
416
417 /****************** RN_OSS_PROD ******************/
418 [RN_OSS_PROD](source, globalName, filename, moduleType) {
419 return signFile(`/**
268 - * @preserve
420 ${license}
421 *
422 * @noflow
@@ -281,7 +432,6 @@ ${source}`);
432 /****************** RN_OSS_PROFILING ******************/
433 [RN_OSS_PROFILING](source, globalName, filename, moduleType) {
434 return signFile(`/**
284 - * @preserve
435 ${license}
436 *
437 * @noflow
@@ -297,7 +447,6 @@ ${source}`);
447 /****************** RN_FB_DEV ******************/
448 [RN_FB_DEV](source, globalName, filename, moduleType) {
449 return signFile(`/**
300 - * @preserve
450 ${license}
451 *
452 * @noflow
@@ -306,19 +455,12 @@ ${license}
455 * ${getSigningToken()}
456 */
457
309 -'use strict';
310 -
311 -if (__DEV__) {
312 - (function() {
313 -${source}
314 - })();
315 -}`);
458 +${source}`);
459 },
460
461 /****************** RN_FB_PROD ******************/
462 [RN_FB_PROD](source, globalName, filename, moduleType) {
463 return signFile(`/**
321 - * @preserve
464 ${license}
465 *
466 * @noflow
@@ -333,7 +475,6 @@ ${source}`);
475 /****************** RN_FB_PROFILING ******************/
476 [RN_FB_PROFILING](source, globalName, filename, moduleType) {
477 return signFile(`/**
336 - * @preserve
478 ${license}
479 *
480 * @noflow
@@ -346,69 +487,7 @@ ${source}`);
487 },
488 };
489
349 -const reconcilerWrappers = {
350 - /***************** NODE_DEV (reconciler only) *****************/
351 - [NODE_DEV](source, globalName, filename, moduleType) {
352 - return `/**
353 - * @license React
354 - * ${filename}
355 - *
356 -${license}
357 - */
358 -
359 -'use strict';
360 -
361 -if (process.env.NODE_ENV !== "production") {
362 - module.exports = function $$$reconciler($$$config) {
363 - var exports = {};
364 -${source}
365 - return exports;
366 - };
367 - module.exports.default = module.exports;
368 - Object.defineProperty(module.exports, "__esModule", { value: true });
369 -}
370 -`;
371 - },
372 -
373 - /***************** NODE_PROD (reconciler only) *****************/
374 - [NODE_PROD](source, globalName, filename, moduleType) {
375 - return `/**
376 - * @license React
377 - * ${filename}
378 - *
379 -${license}
380 - */
381 -module.exports = function $$$reconciler($$$config) {
382 -
383 - var exports = {};
384 -${source}
385 - return exports;
386 -};
387 -module.exports.default = module.exports;
388 -Object.defineProperty(module.exports, "__esModule", { value: true });
389 -`;
390 - },
391 -
392 - /***************** NODE_PROFILING (reconciler only) *****************/
393 - [NODE_PROFILING](source, globalName, filename, moduleType) {
394 - return `/**
395 - * @license React
396 - * ${filename}
397 - *
398 -${license}
399 - */
400 -module.exports = function $$$reconciler($$$config) {
401 - var exports = {};
402 -${source}
403 - return exports;
404 -};
405 -module.exports.default = module.exports;
406 -Object.defineProperty(module.exports, "__esModule", { value: true });
407 -`;
408 - },
409 -};
410 -
411 -function wrapBundle(
490 +function wrapWithTopLevelDefinitions(
491 source,
492 bundleType,
493 globalName,
@@ -457,17 +536,42 @@ function wrapBundle(
536 `Unsupported build type for the reconciler package: ${bundleType}.`
537 );
538 }
539 +
540 return wrapper(source, globalName, filename, moduleType);
541 }
542
543 // All the other packages.
464 - const wrapper = wrappers[bundleType];
544 + const wrapper = topLevelDefinitionWrappers[bundleType];
545 if (typeof wrapper !== 'function') {
546 throw new Error(`Unsupported build type: ${bundleType}.`);
547 }
548 +
549 + return wrapper(source, globalName, filename, moduleType);
550 +}
551 +
552 +function wrapWithLicenseHeader(
553 + source,
554 + bundleType,
555 + globalName,
556 + filename,
557 + moduleType
558 +) {
559 + if (bundleType === BROWSER_SCRIPT) {
560 + // Bundles of type BROWSER_SCRIPT get sent straight to the browser without
561 + // additional processing. So we should exclude any extra wrapper comments.
562 + return source;
563 + }
564 +
565 + // All the other packages.
566 + const wrapper = licenseHeaderWrappers[bundleType];
567 + if (typeof wrapper !== 'function') {
568 + throw new Error(`Unsupported build type: ${bundleType}.`);
569 + }
570 +
571 return wrapper(source, globalName, filename, moduleType);
572 }
573
574 module.exports = {
472 - wrapBundle,
575 + wrapWithTopLevelDefinitions,
576 + wrapWithLicenseHeader,
577 };