From 8bda34d3185194c6e70d04b2f65d4ec42f5ff94a Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 13:55:44 -0400 Subject: [PATCH 01/20] Update [ghstack-poisoned] --- .circleci/config.yml | 2 +- .github/workflows/runtime_build.yml | 46 +- scripts/rollup/build-all-release-channels.js | 46 +- scripts/rollup/build-ghaction.js | 870 +++++++++++++++++++ 4 files changed, 950 insertions(+), 14 deletions(-) create mode 100644 scripts/rollup/build-ghaction.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 18372084d3685..a4671f4f58a64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -97,7 +97,7 @@ jobs: steps: - checkout - setup_node_modules - - run: yarn build + - run: yarn build --ci=circleci - persist_to_workspace: root: . paths: diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 6753b083298f2..05125d812339f 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -8,9 +8,33 @@ on: - 'compiler/**' jobs: + define_build_params: + name: Build build params + runs-on: ubuntu-latest + outputs: + bundle_type: ${{ steps.define_bundle_types.outputs.result }} + release_channel: ${{ steps.define_release_channels.outputs.result }} + steps: + - uses: actions/github-script@v7 + id: define_bundle_types + with: + script: | + const {bundleTypes} = require('.scripts/rollup/bundles'); + return Object.values(bundleTypes); + - uses: actions/github-script@v7 + id: define_release_channels + with: + script: | + return ['stable', 'experimental']; + build: name: yarn build runs-on: ubuntu-latest + needs: define_build_params + strategy: + matrix: + bundle_type: ${{ fromJSON(needs.define_build_params.outputs.bundle_type) }} + release_channel: ${{ fromJSON(needs.define_build_params.outputs.release_channel) }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -25,17 +49,17 @@ jobs: path: "**/node_modules" key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - - run: yarn build - - name: Cache build - uses: actions/cache@v4 - id: build_cache + - run: yarn build --b=${{ matrix.bundle_type }} --r=${{ matrix.release_channel }} --ci=github + - name: Archive build + uses: actions/upload-artifact@v4 with: - path: "build/**" - key: yarn-build-${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + name: build-${{ matrix.release_channel }}-${{ matrix.bundle_type }} + path: | + build/** lint_build: name: yarn lint-build - needs: build + needs: [define_build_params, build] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -50,11 +74,9 @@ jobs: with: path: "**/node_modules" key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} - - name: Restore cached build - uses: actions/cache@v4 - id: build_cache + - name: Restore archived build + uses: actions/download-artifact@v4 with: - path: "build/**" - key: yarn-build-${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + name: build-${{ needs.define_build_params.outputs.release_channel }}-${{ needs.define_build_params.outputs.bundle_type }} - run: yarn install --frozen-lockfile - run: yarn lint-build diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 5e8cd27cf5e47..9c5951d5264c0 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -15,6 +15,9 @@ const { canaryChannelLabel, rcNumber, } = require('../../ReactVersions'); +const yargs = require('yargs'); +const Bundles = require('./bundles'); +const {buildEverything} = require('./build-ghaction'); // Runs the build script for both stable and experimental release channels, // by configuring an environment variable. @@ -53,7 +56,48 @@ fs.writeFileSync( `export default '${PLACEHOLDER_REACT_VERSION}';\n` ); -if (process.env.CIRCLE_NODE_TOTAL) { +const argv = yargs.wrap(yargs.terminalWidth()).options({ + releaseChannel: { + alias: 'r', + describe: 'Build the given release channel.', + requiresArg: true, + type: 'string', + default: 'experimental', + choices: ['experimental', 'stable'], + }, + bundleType: { + alias: 'b', + describe: 'Build the given bundle type.', + requiresArg: true, + type: 'string', + choices: Object.values(Bundles.bundleTypes), + }, + ci: { + describe: 'Run tests in CI', + requiresArg: false, + type: 'choices', + choices: ['circleci', 'github'], + }, +}).argv; + +if (argv.ci === 'github') { + // ./scripts/rollup/build was being used by spawning a new process and passing via ENV variables + // so let's just preserve this for now and rewrite it later to just take a function arg + process.env.RELEASE_CHANNEL = argv.releaseChannel; + buildEverything(argv.bundleType); + switch (argv.releaseChannel) { + case 'stable': { + processStable('./build'); + break; + } + case 'experimental': { + processExperimental('./build'); + break; + } + default: + throw new Error(`Unknown release channel ${argv.releaseChannel}`); + } +} else if (argv.ci === 'circleci') { // In CI, we use multiple concurrent processes. Allocate half the processes to // build the stable channel, and the other half for experimental. Override // the environment variables to "trick" the underlying build script. diff --git a/scripts/rollup/build-ghaction.js b/scripts/rollup/build-ghaction.js new file mode 100644 index 0000000000000..fa3effee4ddd7 --- /dev/null +++ b/scripts/rollup/build-ghaction.js @@ -0,0 +1,870 @@ +'use strict'; + +const rollup = require('rollup'); +const babel = require('@rollup/plugin-babel').babel; +const closure = require('./plugins/closure-plugin'); +const flowRemoveTypes = require('flow-remove-types'); +const prettier = require('rollup-plugin-prettier'); +const replace = require('@rollup/plugin-replace'); +const stripBanner = require('rollup-plugin-strip-banner'); +const chalk = require('chalk'); +const resolve = require('@rollup/plugin-node-resolve').nodeResolve; +const fs = require('fs'); +const argv = require('minimist')(process.argv.slice(2)); +const Modules = require('./modules'); +const Bundles = require('./bundles'); +const Stats = require('./stats'); +const Sync = require('./sync'); +const sizes = require('./plugins/sizes-plugin'); +const useForks = require('./plugins/use-forks-plugin'); +const dynamicImports = require('./plugins/dynamic-imports'); +const Packaging = require('./packaging'); +const {asyncRimRaf} = require('./utils'); +const codeFrame = require('@babel/code-frame'); +const Wrappers = require('./wrappers'); + +const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL; + +// Default to building in experimental mode. If the release channel is set via +// an environment variable, then check if it's "experimental". +const __EXPERIMENTAL__ = + typeof RELEASE_CHANNEL === 'string' + ? RELEASE_CHANNEL === 'experimental' + : true; + +// Errors in promises should be fatal. +let loggedErrors = new Set(); +process.on('unhandledRejection', err => { + if (loggedErrors.has(err)) { + // No need to print it twice. + process.exit(1); + } + throw err; +}); + +const { + NODE_ES2015, + ESM_DEV, + ESM_PROD, + NODE_DEV, + NODE_PROD, + NODE_PROFILING, + BUN_DEV, + BUN_PROD, + FB_WWW_DEV, + FB_WWW_PROD, + FB_WWW_PROFILING, + RN_OSS_DEV, + RN_OSS_PROD, + RN_OSS_PROFILING, + RN_FB_DEV, + RN_FB_PROD, + RN_FB_PROFILING, + BROWSER_SCRIPT, +} = Bundles.bundleTypes; + +const {getFilename} = Bundles; + +function parseRequestedNames(names, toCase) { + let result = []; + for (let i = 0; i < names.length; i++) { + let splitNames = names[i].split(','); + for (let j = 0; j < splitNames.length; j++) { + let name = splitNames[j].trim(); + if (!name) { + continue; + } + if (toCase === 'uppercase') { + name = name.toUpperCase(); + } else if (toCase === 'lowercase') { + name = name.toLowerCase(); + } + result.push(name); + } + } + return result; +} + +const argvType = Array.isArray(argv.type) ? argv.type : [argv.type]; +const requestedBundleTypes = argv.type + ? parseRequestedNames(argvType, 'uppercase') + : []; + +const requestedBundleNames = parseRequestedNames(argv._, 'lowercase'); +const forcePrettyOutput = argv.pretty; +const isWatchMode = argv.watch; +const syncFBSourcePath = argv['sync-fbsource']; +const syncWWWPath = argv['sync-www']; + +// Non-ES2015 stuff applied before closure compiler. +const babelPlugins = [ + // These plugins filter out non-ES2015. + ['@babel/plugin-proposal-class-properties', {loose: true}], + 'syntax-trailing-function-commas', + // These use loose mode which avoids embedding a runtime. + // TODO: Remove object spread from the source. Prefer Object.assign instead. + [ + '@babel/plugin-proposal-object-rest-spread', + {loose: true, useBuiltIns: true}, + ], + ['@babel/plugin-transform-template-literals', {loose: true}], + // TODO: Remove for...of from the source. It requires a runtime to be embedded. + '@babel/plugin-transform-for-of', + // TODO: Remove array spread from the source. Prefer .apply instead. + ['@babel/plugin-transform-spread', {loose: true, useBuiltIns: true}], + '@babel/plugin-transform-parameters', + // TODO: Remove array destructuring from the source. Requires runtime. + ['@babel/plugin-transform-destructuring', {loose: true, useBuiltIns: true}], + // Transform Object spread to shared/assign + require('../babel/transform-object-assign'), +]; + +const babelToES5Plugins = [ + // These plugins transform DEV mode. Closure compiler deals with these in PROD. + '@babel/plugin-transform-literals', + '@babel/plugin-transform-arrow-functions', + '@babel/plugin-transform-block-scoped-functions', + '@babel/plugin-transform-shorthand-properties', + '@babel/plugin-transform-computed-properties', + ['@babel/plugin-transform-block-scoping', {throwIfClosureRequired: true}], +]; + +function getBabelConfig( + updateBabelOptions, + bundleType, + packageName, + externals, + isDevelopment, + bundle +) { + const canAccessReactObject = + packageName === 'react' || externals.indexOf('react') !== -1; + let options = { + exclude: '/**/node_modules/**', + babelrc: false, + configFile: false, + presets: [], + plugins: [...babelPlugins], + babelHelpers: 'bundled', + sourcemap: false, + }; + if (isDevelopment) { + options.plugins.push( + ...babelToES5Plugins, + // Turn console.error/warn() into a custom wrapper + [ + require('../babel/transform-replace-console-calls'), + { + shouldError: !canAccessReactObject, + }, + ] + ); + } + if (updateBabelOptions) { + options = updateBabelOptions(options); + } + // Controls whether to replace error messages with error codes in production. + // By default, error messages are replaced in production. + if (!isDevelopment && bundle.minifyWithProdErrorCodes !== false) { + options.plugins.push(require('../error-codes/transform-error-messages')); + } + + return options; +} + +let getRollupInteropValue = id => { + // We're setting Rollup to assume that imports are ES modules unless otherwise specified. + // However, we also compile ES import syntax to `require()` using Babel. + // This causes Rollup to turn uses of `import SomeDefaultImport from 'some-module' into + // references to `SomeDefaultImport.default` due to CJS/ESM interop. + // Some CJS modules don't have a `.default` export, and the rewritten import is incorrect. + // Specifying `interop: 'default'` instead will have Rollup use the imported variable as-is, + // without adding a `.default` to the reference. + const modulesWithCommonJsExports = [ + 'art/core/transform', + 'art/modes/current', + 'art/modes/fast-noSideEffects', + 'art/modes/svg', + 'JSResourceReferenceImpl', + 'error-stack-parser', + 'neo-async', + 'webpack/lib/dependencies/ModuleDependency', + 'webpack/lib/dependencies/NullDependency', + 'webpack/lib/Template', + ]; + + if (modulesWithCommonJsExports.includes(id)) { + return 'default'; + } + + // For all other modules, handle imports without any import helper utils + return 'esModule'; +}; + +function getRollupOutputOptions( + outputPath, + format, + globals, + globalName, + bundleType +) { + const isProduction = isProductionBundleType(bundleType); + + return { + file: outputPath, + format, + globals, + freeze: !isProduction, + interop: getRollupInteropValue, + name: globalName, + sourcemap: false, + esModule: false, + exports: 'auto', + }; +} + +function getFormat(bundleType) { + switch (bundleType) { + case NODE_ES2015: + case NODE_DEV: + case NODE_PROD: + case NODE_PROFILING: + case BUN_DEV: + case BUN_PROD: + case FB_WWW_DEV: + case FB_WWW_PROD: + case FB_WWW_PROFILING: + case RN_OSS_DEV: + case RN_OSS_PROD: + case RN_OSS_PROFILING: + case RN_FB_DEV: + case RN_FB_PROD: + case RN_FB_PROFILING: + return `cjs`; + case ESM_DEV: + case ESM_PROD: + return `es`; + case BROWSER_SCRIPT: + return `iife`; + } +} + +function isProductionBundleType(bundleType) { + switch (bundleType) { + case NODE_ES2015: + return true; + case ESM_DEV: + case NODE_DEV: + case BUN_DEV: + case FB_WWW_DEV: + case RN_OSS_DEV: + case RN_FB_DEV: + return false; + case ESM_PROD: + case NODE_PROD: + case BUN_PROD: + case NODE_PROFILING: + case FB_WWW_PROD: + case FB_WWW_PROFILING: + case RN_OSS_PROD: + case RN_OSS_PROFILING: + case RN_FB_PROD: + case RN_FB_PROFILING: + case BROWSER_SCRIPT: + return true; + default: + throw new Error(`Unknown type: ${bundleType}`); + } +} + +function isProfilingBundleType(bundleType) { + switch (bundleType) { + case NODE_ES2015: + case FB_WWW_DEV: + case FB_WWW_PROD: + case NODE_DEV: + case NODE_PROD: + case BUN_DEV: + case BUN_PROD: + case RN_FB_DEV: + case RN_FB_PROD: + case RN_OSS_DEV: + case RN_OSS_PROD: + case ESM_DEV: + case ESM_PROD: + case BROWSER_SCRIPT: + return false; + case FB_WWW_PROFILING: + case NODE_PROFILING: + case RN_FB_PROFILING: + case RN_OSS_PROFILING: + return true; + default: + throw new Error(`Unknown type: ${bundleType}`); + } +} + +function getBundleTypeFlags(bundleType) { + const isFBWWWBundle = + bundleType === FB_WWW_DEV || + bundleType === FB_WWW_PROD || + bundleType === FB_WWW_PROFILING; + const isRNBundle = + bundleType === RN_OSS_DEV || + bundleType === RN_OSS_PROD || + bundleType === RN_OSS_PROFILING || + bundleType === RN_FB_DEV || + bundleType === RN_FB_PROD || + bundleType === RN_FB_PROFILING; + + const isFBRNBundle = + bundleType === RN_FB_DEV || + bundleType === RN_FB_PROD || + bundleType === RN_FB_PROFILING; + + const shouldStayReadable = isFBWWWBundle || isRNBundle || forcePrettyOutput; + + return { + isFBWWWBundle, + isRNBundle, + isFBRNBundle, + shouldStayReadable, + }; +} + +function forbidFBJSImports() { + return { + name: 'forbidFBJSImports', + resolveId(importee, importer) { + if (/^fbjs\//.test(importee)) { + throw new Error( + `Don't import ${importee} (found in ${importer}). ` + + `Use the utilities in packages/shared/ instead.` + ); + } + }, + }; +} + +function getPlugins( + entry, + externals, + updateBabelOptions, + filename, + packageName, + bundleType, + globalName, + moduleType, + pureExternalModules, + bundle +) { + try { + const forks = Modules.getForks(bundleType, entry, moduleType, bundle); + const isProduction = isProductionBundleType(bundleType); + const isProfiling = isProfilingBundleType(bundleType); + + const needsMinifiedByClosure = + bundleType !== ESM_PROD && bundleType !== ESM_DEV; + + return [ + // Keep dynamic imports as externals + dynamicImports(), + { + name: 'rollup-plugin-flow-remove-types', + transform(code) { + const transformed = flowRemoveTypes(code); + return { + code: transformed.toString(), + map: null, + }; + }, + }, + // Shim any modules that need forking in this environment. + useForks(forks), + // Ensure we don't try to bundle any fbjs modules. + forbidFBJSImports(), + // Use Node resolution mechanism. + resolve({ + // skip: externals, // TODO: options.skip was removed in @rollup/plugin-node-resolve 3.0.0 + }), + // Remove license headers from individual modules + stripBanner({ + exclude: 'node_modules/**/*', + }), + // Compile to ES2015. + babel( + getBabelConfig( + updateBabelOptions, + bundleType, + packageName, + externals, + !isProduction, + bundle + ) + ), + // Remove 'use strict' from individual source files. + { + name: "remove 'use strict'", + transform(source) { + return source.replace(/['"]use strict["']/g, ''); + }, + }, + // Turn __DEV__ and process.env checks into constants. + replace({ + preventAssignment: true, + values: { + __DEV__: isProduction ? 'false' : 'true', + __PROFILE__: isProfiling || !isProduction ? 'true' : 'false', + 'process.env.NODE_ENV': isProduction + ? "'production'" + : "'development'", + __EXPERIMENTAL__, + }, + }), + { + name: 'top-level-definitions', + renderChunk(source) { + return Wrappers.wrapWithTopLevelDefinitions( + source, + bundleType, + globalName, + filename, + moduleType, + bundle.wrapWithModuleBoundaries + ); + }, + }, + // For production builds, compile with Closure. We do this even for the + // "non-minified" production builds because Closure is much better at + // minification than what most applications use. During this step, we do + // preserve the original symbol names, though, so the resulting code is + // relatively readable. + // + // For the minified builds, the names will be mangled later. + // + // We don't bother with sourcemaps at this step. The sourcemaps we publish + // are only for whitespace and symbol renaming; they don't map back to + // before Closure was applied. + needsMinifiedByClosure && + closure({ + compilation_level: 'SIMPLE', + language_in: 'ECMASCRIPT_2020', + language_out: + bundleType === NODE_ES2015 + ? 'ECMASCRIPT_2020' + : bundleType === BROWSER_SCRIPT + ? 'ECMASCRIPT5' + : 'ECMASCRIPT5_STRICT', + emit_use_strict: + bundleType !== BROWSER_SCRIPT && + bundleType !== ESM_PROD && + bundleType !== ESM_DEV, + env: 'CUSTOM', + warning_level: 'QUIET', + source_map_include_content: true, + use_types_for_optimization: false, + process_common_js_modules: false, + rewrite_polyfills: false, + inject_libraries: false, + allow_dynamic_import: true, + + // Don't let it create global variables in the browser. + // https://github.com/facebook/react/issues/10909 + assume_function_wrapper: true, + + // Don't rename symbols (variable names, functions, etc). We leave + // this up to the application to handle, if they want. Otherwise gzip + // takes care of it. + renaming: false, + }), + needsMinifiedByClosure && + // Add the whitespace back + prettier({ + parser: 'flow', + singleQuote: false, + trailingComma: 'none', + bracketSpacing: true, + }), + { + name: 'license-and-signature-header', + renderChunk(source) { + return Wrappers.wrapWithLicenseHeader( + source, + bundleType, + globalName, + filename, + moduleType + ); + }, + }, + // Record bundle size. + sizes({ + getSize: (size, gzip) => { + const currentSizes = Stats.currentBuildResults.bundleSizes; + const recordIndex = currentSizes.findIndex( + record => + record.filename === filename && record.bundleType === bundleType + ); + const index = recordIndex !== -1 ? recordIndex : currentSizes.length; + currentSizes[index] = { + filename, + bundleType, + packageName, + size, + gzip, + }; + }, + }), + ].filter(Boolean); + } catch (error) { + console.error( + chalk.red(`There was an error preparing plugins for entry "${entry}"`) + ); + throw error; + } +} + +function shouldSkipBundle(bundle, bundleType) { + const shouldSkipBundleType = bundle.bundleTypes.indexOf(bundleType) === -1; + if (shouldSkipBundleType) { + return true; + } + if (requestedBundleTypes.length > 0) { + const isAskingForDifferentType = requestedBundleTypes.some( + requestedType => !bundleType.includes(requestedType) + ); + if (isAskingForDifferentType) { + return true; + } + } + if (requestedBundleNames.length > 0) { + // If the name ends with `something/index` we only match if the + // entry ends in something. Such as `react-dom/index` only matches + // `react-dom` but not `react-dom/server`. Everything else is fuzzy + // search. + const entryLowerCase = bundle.entry.toLowerCase() + '/index.js'; + const isAskingForDifferentNames = requestedBundleNames.every( + requestedName => { + const matchEntry = entryLowerCase.indexOf(requestedName) !== -1; + if (!bundle.name) { + return !matchEntry; + } + const matchName = + bundle.name.toLowerCase().indexOf(requestedName) !== -1; + return !matchEntry && !matchName; + } + ); + if (isAskingForDifferentNames) { + return true; + } + } + return false; +} + +function resolveEntryFork(resolvedEntry, isFBBundle) { + // Pick which entry point fork to use: + // .modern.fb.js + // .classic.fb.js + // .fb.js + // .stable.js + // .experimental.js + // .js + // or any of those plus .development.js + + if (isFBBundle) { + const resolvedFBEntry = resolvedEntry.replace( + '.js', + __EXPERIMENTAL__ ? '.modern.fb.js' : '.classic.fb.js' + ); + const developmentFBEntry = resolvedFBEntry.replace( + '.js', + '.development.js' + ); + if (fs.existsSync(developmentFBEntry)) { + return developmentFBEntry; + } + if (fs.existsSync(resolvedFBEntry)) { + return resolvedFBEntry; + } + const resolvedGenericFBEntry = resolvedEntry.replace('.js', '.fb.js'); + const developmentGenericFBEntry = resolvedGenericFBEntry.replace( + '.js', + '.development.js' + ); + if (fs.existsSync(developmentGenericFBEntry)) { + return developmentGenericFBEntry; + } + if (fs.existsSync(resolvedGenericFBEntry)) { + return resolvedGenericFBEntry; + } + // Even if it's a FB bundle we fallthrough to pick stable or experimental if we don't have an FB fork. + } + const resolvedForkedEntry = resolvedEntry.replace( + '.js', + __EXPERIMENTAL__ ? '.experimental.js' : '.stable.js' + ); + const devForkedEntry = resolvedForkedEntry.replace('.js', '.development.js'); + if (fs.existsSync(devForkedEntry)) { + return devForkedEntry; + } + if (fs.existsSync(resolvedForkedEntry)) { + return resolvedForkedEntry; + } + // Just use the plain .js one. + return resolvedEntry; +} + +async function createBundle(bundle, bundleType) { + const filename = getFilename(bundle, bundleType); + const logKey = + chalk.white.bold(filename) + chalk.dim(` (${bundleType.toLowerCase()})`); + const format = getFormat(bundleType); + const packageName = Packaging.getPackageName(bundle.entry); + + const {isFBWWWBundle, isFBRNBundle} = getBundleTypeFlags(bundleType); + + let resolvedEntry = resolveEntryFork( + require.resolve(bundle.entry), + isFBWWWBundle || isFBRNBundle, + !isProductionBundleType(bundleType) + ); + + const peerGlobals = Modules.getPeerGlobals(bundle.externals, bundleType); + let externals = Object.keys(peerGlobals); + + const deps = Modules.getDependencies(bundleType, bundle.entry); + externals = externals.concat(deps); + + const importSideEffects = Modules.getImportSideEffects(); + const pureExternalModules = Object.keys(importSideEffects).filter( + module => !importSideEffects[module] + ); + + const rollupConfig = { + input: resolvedEntry, + treeshake: { + moduleSideEffects: (id, external) => + !(external && pureExternalModules.includes(id)), + propertyReadSideEffects: false, + }, + external(id) { + const containsThisModule = pkg => id === pkg || id.startsWith(pkg + '/'); + const isProvidedByDependency = externals.some(containsThisModule); + if (isProvidedByDependency) { + if (id.indexOf('/src/') !== -1) { + throw Error( + 'You are trying to import ' + + id + + ' but ' + + externals.find(containsThisModule) + + ' is one of npm dependencies, ' + + 'so it will not contain that source file. You probably want ' + + 'to create a new bundle entry point for it instead.' + ); + } + return true; + } + return !!peerGlobals[id]; + }, + onwarn: handleRollupWarning, + plugins: getPlugins( + bundle.entry, + externals, + bundle.babel, + filename, + packageName, + bundleType, + bundle.global, + bundle.moduleType, + pureExternalModules, + bundle + ), + output: { + externalLiveBindings: false, + freeze: false, + interop: getRollupInteropValue, + esModule: false, + }, + }; + const mainOutputPath = Packaging.getBundleOutputPath( + bundle, + bundleType, + filename, + packageName + ); + + const rollupOutputOptions = getRollupOutputOptions( + mainOutputPath, + format, + peerGlobals, + bundle.global, + bundleType + ); + + if (isWatchMode) { + rollupConfig.output = [rollupOutputOptions]; + const watcher = rollup.watch(rollupConfig); + watcher.on('event', async event => { + switch (event.code) { + case 'BUNDLE_START': + console.log(`${chalk.bgYellow.black(' BUILDING ')} ${logKey}`); + break; + case 'BUNDLE_END': + console.log(`${chalk.bgGreen.black(' COMPLETE ')} ${logKey}\n`); + break; + case 'ERROR': + case 'FATAL': + console.log(`${chalk.bgRed.black(' OH NOES! ')} ${logKey}\n`); + handleRollupError(event.error); + break; + } + }); + } else { + console.log(`${chalk.bgYellow.black(' BUILDING ')} ${logKey}`); + try { + const result = await rollup.rollup(rollupConfig); + await result.write(rollupOutputOptions); + } catch (error) { + console.log(`${chalk.bgRed.black(' OH NOES! ')} ${logKey}\n`); + handleRollupError(error); + throw error; + } + console.log(`${chalk.bgGreen.black(' COMPLETE ')} ${logKey}\n`); + } +} + +function handleRollupWarning(warning) { + if (warning.code === 'UNUSED_EXTERNAL_IMPORT') { + const match = warning.message.match(/external module "([^"]+)"/); + if (!match || typeof match[1] !== 'string') { + throw new Error( + 'Could not parse a Rollup warning. ' + 'Fix this method.' + ); + } + const importSideEffects = Modules.getImportSideEffects(); + const externalModule = match[1]; + if (typeof importSideEffects[externalModule] !== 'boolean') { + throw new Error( + 'An external module "' + + externalModule + + '" is used in a DEV-only code path ' + + 'but we do not know if it is safe to omit an unused require() to it in production. ' + + 'Please add it to the `importSideEffects` list in `scripts/rollup/modules.js`.' + ); + } + // Don't warn. We will remove side effectless require() in a later pass. + return; + } + + if (warning.code === 'CIRCULAR_DEPENDENCY') { + // Ignored + } else if (typeof warning.code === 'string') { + // This is a warning coming from Rollup itself. + // These tend to be important (e.g. clashes in namespaced exports) + // so we'll fail the build on any of them. + console.error(); + console.error(warning.message || warning); + console.error(); + process.exit(1); + } else { + // The warning is from one of the plugins. + // Maybe it's not important, so just print it. + console.warn(warning.message || warning); + } +} + +function handleRollupError(error) { + loggedErrors.add(error); + if (!error.code) { + console.error(error); + return; + } + console.error( + `\x1b[31m-- ${error.code}${error.plugin ? ` (${error.plugin})` : ''} --` + ); + console.error(error.stack); + if (error.loc && error.loc.file) { + const {file, line, column} = error.loc; + // This looks like an error from Rollup, e.g. missing export. + // We'll use the accurate line numbers provided by Rollup but + // use Babel code frame because it looks nicer. + const rawLines = fs.readFileSync(file, 'utf-8'); + // column + 1 is required due to rollup counting column start position from 0 + // whereas babel-code-frame counts from 1 + const frame = codeFrame(rawLines, line, column + 1, { + highlightCode: true, + }); + console.error(frame); + } else if (error.codeFrame) { + // This looks like an error from a plugin (e.g. Babel). + // In this case we'll resort to displaying the provided code frame + // because we can't be sure the reported location is accurate. + console.error(error.codeFrame); + } +} + +async function buildEverything(bundleTypeToBuild) { + if (!argv['unsafe-partial']) { + await asyncRimRaf('build'); + } + + // Run them serially for better console output + // and to avoid any potential race conditions. + + let bundles = []; + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const bundle of Bundles.bundles) { + bundles.push( + [bundle, NODE_ES2015], + [bundle, ESM_DEV], + [bundle, ESM_PROD], + [bundle, NODE_DEV], + [bundle, NODE_PROD], + [bundle, NODE_PROFILING], + [bundle, BUN_DEV], + [bundle, BUN_PROD], + [bundle, FB_WWW_DEV], + [bundle, FB_WWW_PROD], + [bundle, FB_WWW_PROFILING], + [bundle, RN_OSS_DEV], + [bundle, RN_OSS_PROD], + [bundle, RN_OSS_PROFILING], + [bundle, RN_FB_DEV], + [bundle, RN_FB_PROD], + [bundle, RN_FB_PROFILING], + [bundle, BROWSER_SCRIPT] + ); + } + + bundles = bundles.filter(([bundle, bundleType]) => { + return !shouldSkipBundle(bundle, bundleType); + }); + + // TODO: cleanup the rest of this function + bundles = bundles.filter( + ([, bundleType]) => bundleType === bundleTypeToBuild + ); + + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const [bundle, bundleType] of bundles) { + await createBundle(bundle, bundleType); + } + + await Packaging.copyAllShims(); + await Packaging.prepareNpmPackages(); + + if (syncFBSourcePath) { + await Sync.syncReactNative(syncFBSourcePath); + } else if (syncWWWPath) { + await Sync.syncReactDom('build/facebook-www', syncWWWPath); + } + + console.log(Stats.printResults()); + if (!forcePrettyOutput) { + Stats.saveResults(); + } +} + +module.exports = { + buildEverything, +}; From 0f258057b2d0ca3e938cce35cc7ddc31e021c24f Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 13:57:15 -0400 Subject: [PATCH 02/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 05125d812339f..46e6c18f848a6 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -19,7 +19,7 @@ jobs: id: define_bundle_types with: script: | - const {bundleTypes} = require('.scripts/rollup/bundles'); + const {bundleTypes} = require('./scripts/rollup/bundles'); return Object.values(bundleTypes); - uses: actions/github-script@v7 id: define_release_channels From 4e5b45e3e1fd5ee67b1007eb09005661326851a8 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 13:58:19 -0400 Subject: [PATCH 03/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 46e6c18f848a6..a270ba10a50b2 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -19,7 +19,7 @@ jobs: id: define_bundle_types with: script: | - const {bundleTypes} = require('./scripts/rollup/bundles'); + const {bundleTypes} = require('../scripts/rollup/bundles'); return Object.values(bundleTypes); - uses: actions/github-script@v7 id: define_release_channels From 4fc3526f23d158211585b78a28f0f585e46a8dc8 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 13:59:26 -0400 Subject: [PATCH 04/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index a270ba10a50b2..1768fce6f8001 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -15,6 +15,7 @@ jobs: bundle_type: ${{ steps.define_bundle_types.outputs.result }} release_channel: ${{ steps.define_release_channels.outputs.result }} steps: + - uses: actions/checkout@v4 - uses: actions/github-script@v7 id: define_bundle_types with: From 25a6144f37873d2c8ff95b302d8978bcbeb1ad5b Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 14:00:20 -0400 Subject: [PATCH 05/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 1768fce6f8001..1b3d4467635c0 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -20,7 +20,7 @@ jobs: id: define_bundle_types with: script: | - const {bundleTypes} = require('../scripts/rollup/bundles'); + const {bundleTypes} = require('./scripts/rollup/bundles'); return Object.values(bundleTypes); - uses: actions/github-script@v7 id: define_release_channels From 3b3a5c8bd678c2b256f77843064c549964f95e0f Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 14:03:42 -0400 Subject: [PATCH 06/20] Update [ghstack-poisoned] --- scripts/rollup/build-all-release-channels.js | 104 ++++++++++--------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 9c5951d5264c0..2dac6f7954d3f 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -80,61 +80,63 @@ const argv = yargs.wrap(yargs.terminalWidth()).options({ }, }).argv; -if (argv.ci === 'github') { - // ./scripts/rollup/build was being used by spawning a new process and passing via ENV variables - // so let's just preserve this for now and rewrite it later to just take a function arg - process.env.RELEASE_CHANNEL = argv.releaseChannel; - buildEverything(argv.bundleType); - switch (argv.releaseChannel) { - case 'stable': { - processStable('./build'); - break; +async function main() { + if (argv.ci === 'github') { + // ./scripts/rollup/build was being used by spawning a new process and passing via ENV variables + // so let's just preserve this for now and rewrite it later to just take a function arg + process.env.RELEASE_CHANNEL = argv.releaseChannel; + await buildEverything(argv.bundleType); + switch (argv.releaseChannel) { + case 'stable': { + processStable('./build'); + break; + } + case 'experimental': { + processExperimental('./build'); + break; + } + default: + throw new Error(`Unknown release channel ${argv.releaseChannel}`); } - case 'experimental': { + } else if (argv.ci === 'circleci') { + // In CI, we use multiple concurrent processes. Allocate half the processes to + // build the stable channel, and the other half for experimental. Override + // the environment variables to "trick" the underlying build script. + const total = parseInt(process.env.CIRCLE_NODE_TOTAL, 10); + const halfTotal = Math.floor(total / 2); + const index = parseInt(process.env.CIRCLE_NODE_INDEX, 10); + if (index < halfTotal) { + const nodeTotal = halfTotal; + const nodeIndex = index; + buildForChannel('stable', nodeTotal, nodeIndex); + processStable('./build'); + } else { + const nodeTotal = total - halfTotal; + const nodeIndex = index - halfTotal; + buildForChannel('experimental', nodeTotal, nodeIndex); processExperimental('./build'); - break; } - default: - throw new Error(`Unknown release channel ${argv.releaseChannel}`); - } -} else if (argv.ci === 'circleci') { - // In CI, we use multiple concurrent processes. Allocate half the processes to - // build the stable channel, and the other half for experimental. Override - // the environment variables to "trick" the underlying build script. - const total = parseInt(process.env.CIRCLE_NODE_TOTAL, 10); - const halfTotal = Math.floor(total / 2); - const index = parseInt(process.env.CIRCLE_NODE_INDEX, 10); - if (index < halfTotal) { - const nodeTotal = halfTotal; - const nodeIndex = index; - buildForChannel('stable', nodeTotal, nodeIndex); - processStable('./build'); } else { - const nodeTotal = total - halfTotal; - const nodeIndex = index - halfTotal; - buildForChannel('experimental', nodeTotal, nodeIndex); - processExperimental('./build'); + // Running locally, no concurrency. Move each channel's build artifacts into + // a temporary directory so that they don't conflict. + buildForChannel('stable', '', ''); + const stableDir = tmp.dirSync().name; + crossDeviceRenameSync('./build', stableDir); + processStable(stableDir); + buildForChannel('experimental', '', ''); + const experimentalDir = tmp.dirSync().name; + crossDeviceRenameSync('./build', experimentalDir); + processExperimental(experimentalDir); + + // Then merge the experimental folder into the stable one. processExperimental + // will have already removed conflicting files. + // + // In CI, merging is handled automatically by CircleCI's workspace feature. + mergeDirsSync(experimentalDir + '/', stableDir + '/'); + + // Now restore the combined directory back to its original name + crossDeviceRenameSync(stableDir, './build'); } -} else { - // Running locally, no concurrency. Move each channel's build artifacts into - // a temporary directory so that they don't conflict. - buildForChannel('stable', '', ''); - const stableDir = tmp.dirSync().name; - crossDeviceRenameSync('./build', stableDir); - processStable(stableDir); - buildForChannel('experimental', '', ''); - const experimentalDir = tmp.dirSync().name; - crossDeviceRenameSync('./build', experimentalDir); - processExperimental(experimentalDir); - - // Then merge the experimental folder into the stable one. processExperimental - // will have already removed conflicting files. - // - // In CI, merging is handled automatically by CircleCI's workspace feature. - mergeDirsSync(experimentalDir + '/', stableDir + '/'); - - // Now restore the combined directory back to its original name - crossDeviceRenameSync(stableDir, './build'); } function buildForChannel(channel, nodeTotal, nodeIndex) { @@ -501,3 +503,5 @@ function mergeDirsSync(source, destination) { } } } + +main(); From 0fd3ef54036c79c64446ba16e690794aa691cdc7 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 14:11:05 -0400 Subject: [PATCH 07/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 8 ++++++-- scripts/rollup/build-ghaction.js | 9 +++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 1b3d4467635c0..64715c267d51b 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -54,13 +54,17 @@ jobs: - name: Archive build uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.release_channel }}-${{ matrix.bundle_type }} + name: ${{ matrix.bundle_type }}-${{ matrix.release_channel }} path: | build/** lint_build: name: yarn lint-build needs: [define_build_params, build] + strategy: + matrix: + bundle_type: ${{ fromJSON(needs.define_build_params.outputs.bundle_type) }} + release_channel: ${{ fromJSON(needs.define_build_params.outputs.release_channel) }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -78,6 +82,6 @@ jobs: - name: Restore archived build uses: actions/download-artifact@v4 with: - name: build-${{ needs.define_build_params.outputs.release_channel }}-${{ needs.define_build_params.outputs.bundle_type }} + name: ${{ needs.define_build_params.outputs.bundle_type }}-${{ needs.define_build_params.outputs.release_channel }} - run: yarn install --frozen-lockfile - run: yarn lint-build diff --git a/scripts/rollup/build-ghaction.js b/scripts/rollup/build-ghaction.js index fa3effee4ddd7..60871e3e9208c 100644 --- a/scripts/rollup/build-ghaction.js +++ b/scripts/rollup/build-ghaction.js @@ -845,10 +845,11 @@ async function buildEverything(bundleTypeToBuild) { ([, bundleType]) => bundleType === bundleTypeToBuild ); - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (const [bundle, bundleType] of bundles) { - await createBundle(bundle, bundleType); - } + await Promise.all( + bundles.map(([bundle, bundleType]) => { + return createBundle(bundle, bundleType); + }) + ); await Packaging.copyAllShims(); await Packaging.prepareNpmPackages(); From 9b90600eae7f1b7e04b2dcb5dab7231a778e804e Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 14:12:41 -0400 Subject: [PATCH 08/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 64715c267d51b..a380c2c85c722 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -82,6 +82,6 @@ jobs: - name: Restore archived build uses: actions/download-artifact@v4 with: - name: ${{ needs.define_build_params.outputs.bundle_type }}-${{ needs.define_build_params.outputs.release_channel }} + name: ${{ matrix.bundle_type }}-${{ matrix.release_channel }} - run: yarn install --frozen-lockfile - run: yarn lint-build From d64589b4964a21bbc0673ddefb7757379e01da23 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 17:13:57 -0400 Subject: [PATCH 09/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index a380c2c85c722..ed3a7074230cc 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -26,7 +26,7 @@ jobs: id: define_release_channels with: script: | - return ['stable', 'experimental']; + return ["stable", "experimental"]; build: name: yarn build @@ -54,9 +54,9 @@ jobs: - name: Archive build uses: actions/upload-artifact@v4 with: - name: ${{ matrix.bundle_type }}-${{ matrix.release_channel }} + name: ${{ matrix.bundle_type }}_${{ matrix.release_channel }} path: | - build/** + build lint_build: name: yarn lint-build @@ -82,6 +82,6 @@ jobs: - name: Restore archived build uses: actions/download-artifact@v4 with: - name: ${{ matrix.bundle_type }}-${{ matrix.release_channel }} + name: ${{ matrix.bundle_type }}_${{ matrix.release_channel }} - run: yarn install --frozen-lockfile - run: yarn lint-build From 541d8167ab2cc74e9a93fa477f233b987c553264 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 17:23:25 -0400 Subject: [PATCH 10/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index ed3a7074230cc..444b433ac3f7e 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -51,6 +51,10 @@ jobs: key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn build --b=${{ matrix.bundle_type }} --r=${{ matrix.release_channel }} --ci=github + env: + CI: github + - name: Display structure of build + run: ls -R build - name: Archive build uses: actions/upload-artifact@v4 with: @@ -65,6 +69,7 @@ jobs: matrix: bundle_type: ${{ fromJSON(needs.define_build_params.outputs.bundle_type) }} release_channel: ${{ fromJSON(needs.define_build_params.outputs.release_channel) }} + continue-on-error: true runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -79,9 +84,12 @@ jobs: with: path: "**/node_modules" key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 with: name: ${{ matrix.bundle_type }}_${{ matrix.release_channel }} - - run: yarn install --frozen-lockfile + path: build + - name: Display structure of build + run: ls -R build - run: yarn lint-build From 01bd4ee8d2b44cb508379c450ed1c3d7c6ab0098 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 17:24:43 -0400 Subject: [PATCH 11/20] Update [ghstack-poisoned] --- scripts/rollup/stats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/rollup/stats.js b/scripts/rollup/stats.js index 5a5b376c8b1a2..b3fe94ef78eca 100644 --- a/scripts/rollup/stats.js +++ b/scripts/rollup/stats.js @@ -18,7 +18,7 @@ const currentBuildResults = { }; function saveResults() { - if (process.env.CIRCLE_NODE_TOTAL) { + if (process.env.CIRCLE_NODE_TOTAL || process.env.CI === 'github') { // In CI, write the bundle sizes to a subdirectory and append the node index // to the filename. A downstream job will consolidate these into a // single file. From 04ee542629a5995ff25bf613638a9a18c82f2b66 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Jun 2024 17:26:03 -0400 Subject: [PATCH 12/20] Update [ghstack-poisoned] --- scripts/rollup/build-ghaction.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/rollup/build-ghaction.js b/scripts/rollup/build-ghaction.js index 60871e3e9208c..ce2ee7addb878 100644 --- a/scripts/rollup/build-ghaction.js +++ b/scripts/rollup/build-ghaction.js @@ -846,9 +846,7 @@ async function buildEverything(bundleTypeToBuild) { ); await Promise.all( - bundles.map(([bundle, bundleType]) => { - return createBundle(bundle, bundleType); - }) + bundles.map(([bundle, bundleType]) => createBundle(bundle, bundleType)) ); await Packaging.copyAllShims(); From af0c260709907a26a299420098f8808fb29dc64e Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Tue, 9 Jul 2024 12:45:06 -0400 Subject: [PATCH 13/20] Update [ghstack-poisoned] --- scripts/rollup/build-ghaction.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/rollup/build-ghaction.js b/scripts/rollup/build-ghaction.js index d1338fdd26400..6dca3f8706528 100644 --- a/scripts/rollup/build-ghaction.js +++ b/scripts/rollup/build-ghaction.js @@ -844,9 +844,14 @@ async function buildEverything(index, total) { const nodeIndex = parseInt(index, 10); bundles = bundles.filter((_, i) => i % nodeTotal === nodeIndex); - await Promise.all( - bundles.map(([bundle, bundleType]) => createBundle(bundle, bundleType)) - ); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const [bundle, bundleType] of bundles) { + await createBundle(bundle, bundleType); + } + + // await Promise.all( + // bundles.map(([bundle, bundleType]) => createBundle(bundle, bundleType)) + // ); await Packaging.copyAllShims(); await Packaging.prepareNpmPackages(); From 88bd0717244f2d04f80c3e99bb671d52074b05a5 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Tue, 9 Jul 2024 13:03:05 -0400 Subject: [PATCH 14/20] Update [ghstack-poisoned] --- scripts/rollup/build-all-release-channels.js | 29 +++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 93c0b60ceda62..3570b94d58c5d 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -16,7 +16,6 @@ const { rcNumber, } = require('../../ReactVersions'); const yargs = require('yargs'); -const {buildEverything} = require('./build-ghaction'); // Runs the build script for both stable and experimental release channels, // by configuring an environment variable. @@ -86,18 +85,22 @@ const argv = yargs.wrap(yargs.terminalWidth()).options({ async function main() { if (argv.ci === 'github') { - await buildEverything(argv.index, argv.total); - switch (argv.releaseChannel) { - case 'stable': { - processStable('./build'); - break; - } - case 'experimental': { - processExperimental('./build'); - break; - } - default: - throw new Error(`Unknown release channel ${argv.releaseChannel}`); + // In CI, we use multiple concurrent processes. Allocate half the processes to + // build the stable channel, and the other half for experimental. Override + // the environment variables to "trick" the underlying build script. + const total = parseInt(argv.total, 10); + const halfTotal = Math.floor(total / 2); + const index = parseInt(argv.index, 10); + if (index < halfTotal) { + const nodeTotal = halfTotal; + const nodeIndex = index; + buildForChannel('stable', nodeTotal, nodeIndex); + processStable('./build'); + } else { + const nodeTotal = total - halfTotal; + const nodeIndex = index - halfTotal; + buildForChannel('experimental', nodeTotal, nodeIndex); + processExperimental('./build'); } } else if (argv.ci === 'circleci') { // In CI, we use multiple concurrent processes. Allocate half the processes to From 81de3c461c083df843c0816300c166ff652de2c1 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Tue, 9 Jul 2024 13:12:07 -0400 Subject: [PATCH 15/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 12 ++---------- scripts/rollup/build-all-release-channels.js | 8 -------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 14db3e9284a67..1f69b39782cc2 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -16,7 +16,6 @@ jobs: runs-on: ubuntu-latest outputs: worker_id: ${{ steps.define_worker_id.outputs.result }} - release_channel: ${{ steps.define_release_channels.outputs.result }} steps: - uses: actions/checkout@v4 - uses: actions/github-script@v7 @@ -31,11 +30,6 @@ jobs: return arr; } return range(0, process.env.WORKER_COUNT); - - uses: actions/github-script@v7 - id: define_release_channels - with: - script: | - return ["stable", "experimental"]; build: name: yarn build @@ -44,7 +38,6 @@ jobs: strategy: matrix: worker_id: ${{ fromJSON(needs.define_build_params.outputs.worker_id) }} - release_channel: ${{ fromJSON(needs.define_build_params.outputs.release_channel) }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -59,17 +52,16 @@ jobs: path: "**/node_modules" key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - - run: yarn build --index=${{ matrix.worker_id }} --total=${{ env.WORKER_COUNT }} --r=${{ matrix.release_channel }} --ci=github + - run: yarn build --index=${{ matrix.worker_id }} --total=${{ env.WORKER_COUNT }} --ci=github env: CI: github - RELEASE_CHANNEL: ${{ matrix.release_channel }} NODE_INDEX: ${{ matrix.worker_id }} - name: Display structure of build run: ls -R build - name: Archive build uses: actions/upload-artifact@v4 with: - name: build_${{ matrix.worker_id }}_${{ matrix.release_channel }} + name: build_${{ matrix.worker_id }} path: | build diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 3570b94d58c5d..352fbd6850a92 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -55,14 +55,6 @@ fs.writeFileSync( ); const argv = yargs.wrap(yargs.terminalWidth()).options({ - releaseChannel: { - alias: 'r', - describe: 'Build the given release channel.', - requiresArg: true, - type: 'string', - default: 'experimental', - choices: ['experimental', 'stable'], - }, index: { alias: 'i', describe: 'Worker id.', From 6ed52176cc5a241a10151b663ec4e2477809ebcb Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Tue, 9 Jul 2024 13:23:39 -0400 Subject: [PATCH 16/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 12 +++++-- scripts/rollup/build-all-release-channels.js | 37 +++++++++++--------- scripts/rollup/build-ghaction.js | 11 ++---- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 1f69b39782cc2..f6896c2850f17 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -16,6 +16,7 @@ jobs: runs-on: ubuntu-latest outputs: worker_id: ${{ steps.define_worker_id.outputs.result }} + release_channel: ${{ steps.define_release_channels.outputs.result }} steps: - uses: actions/checkout@v4 - uses: actions/github-script@v7 @@ -30,6 +31,11 @@ jobs: return arr; } return range(0, process.env.WORKER_COUNT); + - uses: actions/github-script@v7 + id: define_release_channels + with: + script: | + return ["stable", "experimental"]; build: name: yarn build @@ -38,6 +44,7 @@ jobs: strategy: matrix: worker_id: ${{ fromJSON(needs.define_build_params.outputs.worker_id) }} + release_channel: ${{ fromJSON(needs.define_build_params.outputs.release_channel) }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -52,16 +59,17 @@ jobs: path: "**/node_modules" key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - - run: yarn build --index=${{ matrix.worker_id }} --total=${{ env.WORKER_COUNT }} --ci=github + - run: yarn build --index=${{ matrix.worker_id }} --total=${{ env.WORKER_COUNT }} --r=${{ matrix.release_channel }} --ci=github env: CI: github + RELEASE_CHANNEL: ${{ matrix.release_channel }} NODE_INDEX: ${{ matrix.worker_id }} - name: Display structure of build run: ls -R build - name: Archive build uses: actions/upload-artifact@v4 with: - name: build_${{ matrix.worker_id }} + name: build_${{ matrix.worker_id }}_${{ matrix.release_channel }} path: | build diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 352fbd6850a92..93c0b60ceda62 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -16,6 +16,7 @@ const { rcNumber, } = require('../../ReactVersions'); const yargs = require('yargs'); +const {buildEverything} = require('./build-ghaction'); // Runs the build script for both stable and experimental release channels, // by configuring an environment variable. @@ -55,6 +56,14 @@ fs.writeFileSync( ); const argv = yargs.wrap(yargs.terminalWidth()).options({ + releaseChannel: { + alias: 'r', + describe: 'Build the given release channel.', + requiresArg: true, + type: 'string', + default: 'experimental', + choices: ['experimental', 'stable'], + }, index: { alias: 'i', describe: 'Worker id.', @@ -77,22 +86,18 @@ const argv = yargs.wrap(yargs.terminalWidth()).options({ async function main() { if (argv.ci === 'github') { - // In CI, we use multiple concurrent processes. Allocate half the processes to - // build the stable channel, and the other half for experimental. Override - // the environment variables to "trick" the underlying build script. - const total = parseInt(argv.total, 10); - const halfTotal = Math.floor(total / 2); - const index = parseInt(argv.index, 10); - if (index < halfTotal) { - const nodeTotal = halfTotal; - const nodeIndex = index; - buildForChannel('stable', nodeTotal, nodeIndex); - processStable('./build'); - } else { - const nodeTotal = total - halfTotal; - const nodeIndex = index - halfTotal; - buildForChannel('experimental', nodeTotal, nodeIndex); - processExperimental('./build'); + await buildEverything(argv.index, argv.total); + switch (argv.releaseChannel) { + case 'stable': { + processStable('./build'); + break; + } + case 'experimental': { + processExperimental('./build'); + break; + } + default: + throw new Error(`Unknown release channel ${argv.releaseChannel}`); } } else if (argv.ci === 'circleci') { // In CI, we use multiple concurrent processes. Allocate half the processes to diff --git a/scripts/rollup/build-ghaction.js b/scripts/rollup/build-ghaction.js index 6dca3f8706528..d1338fdd26400 100644 --- a/scripts/rollup/build-ghaction.js +++ b/scripts/rollup/build-ghaction.js @@ -844,14 +844,9 @@ async function buildEverything(index, total) { const nodeIndex = parseInt(index, 10); bundles = bundles.filter((_, i) => i % nodeTotal === nodeIndex); - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (const [bundle, bundleType] of bundles) { - await createBundle(bundle, bundleType); - } - - // await Promise.all( - // bundles.map(([bundle, bundleType]) => createBundle(bundle, bundleType)) - // ); + await Promise.all( + bundles.map(([bundle, bundleType]) => createBundle(bundle, bundleType)) + ); await Packaging.copyAllShims(); await Packaging.prepareNpmPackages(); From dbcf0891cf9e965022ecedd3da1f286b2e5a811b Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Tue, 9 Jul 2024 15:26:13 -0400 Subject: [PATCH 17/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index f6896c2850f17..34714f0888f04 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -94,8 +94,8 @@ jobs: - name: Restore archived build uses: actions/download-artifact@v4 with: - path: build - merge-multiple: true + path: artifacts + - run: mkdir -p build && rsync -av --ignore-existing artifacts/* build/ - name: Display structure of build run: ls -R build - run: yarn lint-build From 41e0bf4f853a3218c5f8dfed14b396ccc6fc09de Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Tue, 9 Jul 2024 15:53:34 -0400 Subject: [PATCH 18/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 34714f0888f04..17bcbea708938 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -95,7 +95,10 @@ jobs: uses: actions/download-artifact@v4 with: path: artifacts - - run: mkdir -p build && rsync -av --ignore-existing artifacts/* build/ + - run: | + mkdir -p build + rsync -av --ignore-existing artifacts/* build/ + mv build/* build - name: Display structure of build run: ls -R build - run: yarn lint-build From 4ffcfcbda7f5474b1834758d43f21f6731b430f6 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Wed, 10 Jul 2024 11:38:07 -0400 Subject: [PATCH 19/20] Update [ghstack-poisoned] --- .github/workflows/runtime_build.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/runtime_build.yml b/.github/workflows/runtime_build.yml index 889b7b41ae515..c37345a9283c9 100644 --- a/.github/workflows/runtime_build.yml +++ b/.github/workflows/runtime_build.yml @@ -94,12 +94,8 @@ jobs: - name: Restore archived build uses: actions/download-artifact@v4 with: - path: artifacts - - run: | - mkdir -p build - rsync -av --ignore-existing artifacts/* build/ - cd build - mv */* . + path: build + - run: cd build && mv */* . - name: Display structure of build run: ls -R build - run: yarn lint-build From d4edb3fdd0d7afbaaa7144040f0bbc0ef52815d6 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Wed, 10 Jul 2024 15:02:33 -0400 Subject: [PATCH 20/20] Update [ghstack-poisoned] --- scripts/rollup/build-all-release-channels.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 93c0b60ceda62..9027f87f56124 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -61,7 +61,6 @@ const argv = yargs.wrap(yargs.terminalWidth()).options({ describe: 'Build the given release channel.', requiresArg: true, type: 'string', - default: 'experimental', choices: ['experimental', 'stable'], }, index: {