From 9542d9726187d1f16bcf68ca077e9cf3962faaae Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 29 Jul 2024 15:38:25 -0400 Subject: [PATCH 1/7] Update [ghstack-poisoned] --- .../workflows/devtools_regression_tests.yml | 2 +- .github/workflows/runtime_build_and_test.yml | 2 +- .../workflows/runtime_commit_artifacts.yml | 2 +- .../download-experimental-build-ghaction.js | 59 -- .../release/download-experimental-build.js | 69 +- scripts/release/prepare-release-from-ci.js | 2 +- .../download-build-artifacts-ghaction.js | 136 --- .../download-build-artifacts.js | 117 ++- scripts/rollup/build-all-release-channels.js | 2 +- scripts/rollup/build-ghaction.js | 875 ------------------ scripts/rollup/build.js | 31 +- 11 files changed, 155 insertions(+), 1142 deletions(-) delete mode 100755 scripts/release/download-experimental-build-ghaction.js delete mode 100644 scripts/release/shared-commands/download-build-artifacts-ghaction.js delete mode 100644 scripts/rollup/build-ghaction.js diff --git a/.github/workflows/devtools_regression_tests.yml b/.github/workflows/devtools_regression_tests.yml index 72b82f6b71449..48c1ca35b36bd 100644 --- a/.github/workflows/devtools_regression_tests.yml +++ b/.github/workflows/devtools_regression_tests.yml @@ -35,7 +35,7 @@ jobs: - name: Download react-devtools artifacts for base revision run: | git fetch origin main - GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build-ghaction.js --commit=$(git rev-parse origin/main) + GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=$(git rev-parse origin/main) - name: Display structure of build run: ls -R build - name: Archive build diff --git a/.github/workflows/runtime_build_and_test.yml b/.github/workflows/runtime_build_and_test.yml index 2cf5011a0012a..42e44542523c3 100644 --- a/.github/workflows/runtime_build_and_test.yml +++ b/.github/workflows/runtime_build_and_test.yml @@ -547,7 +547,7 @@ jobs: - name: Download artifacts for base revision run: | git fetch origin main - GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build-ghaction.js --commit=$(git rev-parse origin/main) + GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=$(git rev-parse origin/main) mv ./build ./base-build # TODO: The `download-experimental-build` script copies the npm # packages into the `node_modules` directory. This is a historical diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index c0a6874119094..d1038a7537fe2 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -70,7 +70,7 @@ jobs: working-directory: scripts/release - name: Download artifacts for base revision run: | - GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build-ghaction.js --commit=${{ github.event.workflow_run.head_sha }} + GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ github.event.workflow_run.head_sha }} - name: Display structure of build run: ls -R build - name: Strip @license from eslint plugin and react-refresh diff --git a/scripts/release/download-experimental-build-ghaction.js b/scripts/release/download-experimental-build-ghaction.js deleted file mode 100755 index a30555cc8c7c5..0000000000000 --- a/scripts/release/download-experimental-build-ghaction.js +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -const {join, relative} = require('path'); -const {handleError} = require('./utils'); -const yargs = require('yargs'); -const clear = require('clear'); -const theme = require('./theme'); -const { - downloadBuildArtifacts, -} = require('./shared-commands/download-build-artifacts-ghaction'); - -const argv = yargs.wrap(yargs.terminalWidth()).options({ - releaseChannel: { - alias: 'r', - describe: 'Download the given release channel.', - requiresArg: true, - type: 'string', - choices: ['experimental', 'stable'], - default: 'experimental', - }, - commit: { - alias: 'c', - describe: 'Commit hash to download.', - requiresArg: true, - demandOption: true, - type: 'string', - }, -}).argv; - -function printSummary(commit) { - const commandPath = relative( - process.env.PWD, - join(__dirname, '../download-experimental-build-ghaction.js') - ); - - clear(); - - const message = theme` - {caution An experimental build has been downloaded!} - - You can download this build again by running: - {path ${commandPath}} --commit={commit ${commit}} - `; - - console.log(message.replace(/\n +/g, '\n').trim()); -} - -const main = async () => { - try { - await downloadBuildArtifacts(argv.commit, argv.releaseChannel); - printSummary(argv.commit); - } catch (error) { - handleError(error); - } -}; - -main(); diff --git a/scripts/release/download-experimental-build.js b/scripts/release/download-experimental-build.js index c57ec4f1bf664..a698ad00cb00c 100755 --- a/scripts/release/download-experimental-build.js +++ b/scripts/release/download-experimental-build.js @@ -2,31 +2,58 @@ 'use strict'; -const {join} = require('path'); +const {join, relative} = require('path'); +const {handleError} = require('./utils'); +const yargs = require('yargs'); +const clear = require('clear'); +const theme = require('./theme'); const { - addDefaultParamValue, - getPublicPackages, - handleError, -} = require('./utils'); - -const downloadBuildArtifacts = require('./shared-commands/download-build-artifacts'); -const parseParams = require('./shared-commands/parse-params'); -const printSummary = require('./download-experimental-build-commands/print-summary'); - -const run = async () => { + downloadBuildArtifacts, +} = require('./shared-commands/download-build-artifacts'); + +const argv = yargs.wrap(yargs.terminalWidth()).options({ + releaseChannel: { + alias: 'r', + describe: 'Download the given release channel.', + requiresArg: true, + type: 'string', + choices: ['experimental', 'stable'], + default: 'experimental', + }, + commit: { + alias: 'c', + describe: 'Commit hash to download.', + requiresArg: true, + demandOption: true, + type: 'string', + }, +}).argv; + +function printSummary(commit) { + const commandPath = relative( + process.env.PWD, + join(__dirname, '../download-experimental-build.js') + ); + + clear(); + + const message = theme` + {caution An experimental build has been downloaded!} + + You can download this build again by running: + {path ${commandPath}} --commit={commit ${commit}} + `; + + console.log(message.replace(/\n +/g, '\n').trim()); +} + +const main = async () => { try { - addDefaultParamValue('-r', '--releaseChannel', 'experimental'); - - const params = await parseParams(); - params.cwd = join(__dirname, '..', '..'); - params.packages = await getPublicPackages(true); - - await downloadBuildArtifacts(params); - - printSummary(params); + await downloadBuildArtifacts(argv.commit, argv.releaseChannel); + printSummary(argv.commit); } catch (error) { handleError(error); } }; -run(); +main(); diff --git a/scripts/release/prepare-release-from-ci.js b/scripts/release/prepare-release-from-ci.js index 5657760ecde59..344c1d665e18c 100755 --- a/scripts/release/prepare-release-from-ci.js +++ b/scripts/release/prepare-release-from-ci.js @@ -7,7 +7,7 @@ const {addDefaultParamValue, handleError} = require('./utils'); const { downloadBuildArtifacts, -} = require('./shared-commands/download-build-artifacts-ghaction'); +} = require('./shared-commands/download-build-artifacts'); const parseParams = require('./shared-commands/parse-params'); const printPrereleaseSummary = require('./shared-commands/print-prerelease-summary'); const testPackagingFixture = require('./shared-commands/test-packaging-fixture'); diff --git a/scripts/release/shared-commands/download-build-artifacts-ghaction.js b/scripts/release/shared-commands/download-build-artifacts-ghaction.js deleted file mode 100644 index 81472b40b071c..0000000000000 --- a/scripts/release/shared-commands/download-build-artifacts-ghaction.js +++ /dev/null @@ -1,136 +0,0 @@ -'use strict'; - -const {join} = require('path'); -const theme = require('../theme'); -const {exec} = require('child-process-promise'); -const {existsSync} = require('fs'); -const {logPromise} = require('../utils'); - -if (process.env.GH_TOKEN == null) { - console.log( - theme`{error Expected GH_TOKEN to be provided as an env variable}` - ); - process.exit(1); -} - -const OWNER = 'facebook'; -const REPO = 'react'; -const WORKFLOW_ID = 'runtime_build_and_test.yml'; -const GITHUB_HEADERS = ` - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${process.env.GH_TOKEN}" \ - -H "X-GitHub-Api-Version: 2022-11-28"`.trim(); - -function getWorkflowId() { - if ( - existsSync(join(__dirname, `../../../.github/workflows/${WORKFLOW_ID}`)) - ) { - return WORKFLOW_ID; - } else { - throw new Error( - `Incorrect workflow ID: .github/workflows/${WORKFLOW_ID} does not exist. Please check the name of the workflow being downloaded from.` - ); - } -} - -async function getWorkflowRunId(commit) { - const res = await exec( - `curl -L ${GITHUB_HEADERS} https://api.github.com/repos/${OWNER}/${REPO}/actions/workflows/${getWorkflowId()}/runs?head_sha=${commit}&branch=main&exclude_pull_requests=true` - ); - - const json = JSON.parse(res.stdout); - let workflowRun; - if (json.total_count === 1) { - workflowRun = json.workflow_runs[0]; - } else { - workflowRun = json.workflow_runs.find( - run => run.head_sha === commit && run.head_branch === 'main' - ); - } - - if (workflowRun == null || workflowRun.id == null) { - console.log( - theme`{error The workflow run for the specified commit (${commit}) could not be found.}` - ); - process.exit(1); - } - - return workflowRun.id; -} - -async function getArtifact(workflowRunId, artifactName) { - const res = await exec( - `curl -L ${GITHUB_HEADERS} https://api.github.com/repos/${OWNER}/${REPO}/actions/runs/${workflowRunId}/artifacts?per_page=100&name=${artifactName}` - ); - - const json = JSON.parse(res.stdout); - let artifact; - if (json.total_count === 1) { - artifact = json.artifacts[0]; - } else { - artifact = json.artifacts.find( - _artifact => _artifact.name === artifactName - ); - } - - if (artifact == null) { - console.log( - theme`{error The specified workflow run (${workflowRunId}) does not contain any build artifacts.}` - ); - process.exit(1); - } - - return artifact; -} - -async function downloadArtifactsFromGitHub(commit, releaseChannel) { - const workflowRunId = await getWorkflowRunId(commit); - const artifact = await getArtifact(workflowRunId, 'artifacts_combined'); - - // Download and extract artifact - const cwd = join(__dirname, '..', '..', '..'); - await exec(`rm -rf ./build`, {cwd}); - await exec( - `curl -L ${GITHUB_HEADERS} ${artifact.archive_download_url} \ - > a.zip && unzip a.zip -d . && rm a.zip build2.tgz && tar -xvzf build.tgz && rm build.tgz`, - { - cwd, - } - ); - - // Copy to staging directory - // TODO: Consider staging the release in a different directory from the CI - // build artifacts: `./build/node_modules` -> `./staged-releases` - if (!existsSync(join(cwd, 'build'))) { - await exec(`mkdir ./build`, {cwd}); - } else { - await exec(`rm -rf ./build/node_modules`, {cwd}); - } - let sourceDir; - // TODO: Rename release channel to `next` - if (releaseChannel === 'stable') { - sourceDir = 'oss-stable'; - } else if (releaseChannel === 'experimental') { - sourceDir = 'oss-experimental'; - } else if (releaseChannel === 'rc') { - sourceDir = 'oss-stable-rc'; - } else if (releaseChannel === 'latest') { - sourceDir = 'oss-stable-semver'; - } else { - console.error('Internal error: Invalid release channel: ' + releaseChannel); - process.exit(releaseChannel); - } - await exec(`cp -r ./build/${sourceDir} ./build/node_modules`, {cwd}); -} - -async function downloadBuildArtifacts(commit, releaseChannel) { - const label = theme`commit {commit ${commit}})`; - return logPromise( - downloadArtifactsFromGitHub(commit, releaseChannel), - theme`Downloading artifacts from GitHub for ${label}` - ); -} - -module.exports = { - downloadBuildArtifacts, -}; diff --git a/scripts/release/shared-commands/download-build-artifacts.js b/scripts/release/shared-commands/download-build-artifacts.js index 2539abd6a6294..81472b40b071c 100644 --- a/scripts/release/shared-commands/download-build-artifacts.js +++ b/scripts/release/shared-commands/download-build-artifacts.js @@ -1,36 +1,98 @@ -#!/usr/bin/env node - 'use strict'; -const {exec} = require('child-process-promise'); -const {existsSync} = require('fs'); const {join} = require('path'); -const {getArtifactsList, logPromise} = require('../utils'); const theme = require('../theme'); +const {exec} = require('child-process-promise'); +const {existsSync} = require('fs'); +const {logPromise} = require('../utils'); + +if (process.env.GH_TOKEN == null) { + console.log( + theme`{error Expected GH_TOKEN to be provided as an env variable}` + ); + process.exit(1); +} + +const OWNER = 'facebook'; +const REPO = 'react'; +const WORKFLOW_ID = 'runtime_build_and_test.yml'; +const GITHUB_HEADERS = ` + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${process.env.GH_TOKEN}" \ + -H "X-GitHub-Api-Version: 2022-11-28"`.trim(); + +function getWorkflowId() { + if ( + existsSync(join(__dirname, `../../../.github/workflows/${WORKFLOW_ID}`)) + ) { + return WORKFLOW_ID; + } else { + throw new Error( + `Incorrect workflow ID: .github/workflows/${WORKFLOW_ID} does not exist. Please check the name of the workflow being downloaded from.` + ); + } +} -const run = async ({build, cwd, releaseChannel}) => { - const artifacts = await getArtifactsList(build); - const buildArtifacts = artifacts.find(entry => - entry.path.endsWith('build.tgz') +async function getWorkflowRunId(commit) { + const res = await exec( + `curl -L ${GITHUB_HEADERS} https://api.github.com/repos/${OWNER}/${REPO}/actions/workflows/${getWorkflowId()}/runs?head_sha=${commit}&branch=main&exclude_pull_requests=true` ); - if (!buildArtifacts) { + const json = JSON.parse(res.stdout); + let workflowRun; + if (json.total_count === 1) { + workflowRun = json.workflow_runs[0]; + } else { + workflowRun = json.workflow_runs.find( + run => run.head_sha === commit && run.head_branch === 'main' + ); + } + + if (workflowRun == null || workflowRun.id == null) { console.log( - theme`{error The specified build (${build}) does not contain any build artifacts.}` + theme`{error The workflow run for the specified commit (${commit}) could not be found.}` ); process.exit(1); } - // Download and extract artifact - const {CIRCLE_CI_API_TOKEN} = process.env; - let header = ''; - // Add Circle CI API token to request header if available. - if (CIRCLE_CI_API_TOKEN != null) { - header = '-H "Circle-Token: ${CIRCLE_CI_API_TOKEN}" '; + return workflowRun.id; +} + +async function getArtifact(workflowRunId, artifactName) { + const res = await exec( + `curl -L ${GITHUB_HEADERS} https://api.github.com/repos/${OWNER}/${REPO}/actions/runs/${workflowRunId}/artifacts?per_page=100&name=${artifactName}` + ); + + const json = JSON.parse(res.stdout); + let artifact; + if (json.total_count === 1) { + artifact = json.artifacts[0]; + } else { + artifact = json.artifacts.find( + _artifact => _artifact.name === artifactName + ); + } + + if (artifact == null) { + console.log( + theme`{error The specified workflow run (${workflowRunId}) does not contain any build artifacts.}` + ); + process.exit(1); } + + return artifact; +} + +async function downloadArtifactsFromGitHub(commit, releaseChannel) { + const workflowRunId = await getWorkflowRunId(commit); + const artifact = await getArtifact(workflowRunId, 'artifacts_combined'); + + // Download and extract artifact + const cwd = join(__dirname, '..', '..', '..'); await exec(`rm -rf ./build`, {cwd}); await exec( - `curl -L $(fwdproxy-config curl) ${buildArtifacts.url} ${header}| tar -xvz`, + `curl -L ${GITHUB_HEADERS} ${artifact.archive_download_url} \ + > a.zip && unzip a.zip -d . && rm a.zip build2.tgz && tar -xvzf build.tgz && rm build.tgz`, { cwd, } @@ -59,17 +121,16 @@ const run = async ({build, cwd, releaseChannel}) => { process.exit(releaseChannel); } await exec(`cp -r ./build/${sourceDir} ./build/node_modules`, {cwd}); -}; +} -module.exports = async ({build, commit, cwd, releaseChannel}) => { - let buildLabel; - if (commit !== null) { - buildLabel = theme`commit {commit ${commit}} (build {build ${build}})`; - } else { - buildLabel = theme`build {build ${build}}`; - } +async function downloadBuildArtifacts(commit, releaseChannel) { + const label = theme`commit {commit ${commit}})`; return logPromise( - run({build, cwd, releaseChannel}), - theme`Downloading artifacts from Circle CI for ${buildLabel}` + downloadArtifactsFromGitHub(commit, releaseChannel), + theme`Downloading artifacts from GitHub for ${label}` ); +} + +module.exports = { + downloadBuildArtifacts, }; diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 4ded1b952a902..2d2ca9c03691d 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -16,7 +16,7 @@ const { rcNumber, } = require('../../ReactVersions'); const yargs = require('yargs'); -const {buildEverything} = require('./build-ghaction'); +const {buildEverything} = require('./build'); const Bundles = require('./bundles'); // Runs the build script for both stable and experimental release channels, diff --git a/scripts/rollup/build-ghaction.js b/scripts/rollup/build-ghaction.js deleted file mode 100644 index cddab9fa7e170..0000000000000 --- a/scripts/rollup/build-ghaction.js +++ /dev/null @@ -1,875 +0,0 @@ -'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); - if ( - bundleType === FB_WWW_DEV || - bundleType === RN_OSS_DEV || - bundleType === RN_FB_DEV - ) { - options.plugins.push( - // 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(index, total) { - 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); - }); - - const nodeTotal = parseInt(total, 10); - 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 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, -}; diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 50e1b1750e477..cddab9fa7e170 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -84,17 +84,13 @@ function parseRequestedNames(names, toCase) { } return result; } + const argvType = Array.isArray(argv.type) ? argv.type : [argv.type]; -const requestedBundleTypes = parseRequestedNames( - argv.type ? argvType : [], - 'uppercase' -); - -const names = argv._; -const requestedBundleNames = parseRequestedNames( - names ? names : [], - 'lowercase' -); +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']; @@ -813,7 +809,7 @@ function handleRollupError(error) { } } -async function buildEverything() { +async function buildEverything(index, total) { if (!argv['unsafe-partial']) { await asyncRimRaf('build'); } @@ -850,12 +846,9 @@ async function buildEverything() { return !shouldSkipBundle(bundle, bundleType); }); - if (process.env.CIRCLE_NODE_TOTAL) { - // In CI, parallelize bundles across multiple tasks. - const nodeTotal = parseInt(process.env.CIRCLE_NODE_TOTAL, 10); - const nodeIndex = parseInt(process.env.CIRCLE_NODE_INDEX, 10); - bundles = bundles.filter((_, i) => i % nodeTotal === nodeIndex); - } + const nodeTotal = parseInt(total, 10); + 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) { @@ -877,4 +870,6 @@ async function buildEverything() { } } -buildEverything(); +module.exports = { + buildEverything, +}; From fda8387c3cdcdc6c88c95fa8ab1dbf66604fbf23 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 29 Jul 2024 17:35:13 -0400 Subject: [PATCH 2/7] Update [ghstack-poisoned] --- scripts/rollup/build-all-release-channels.js | 4 ++-- scripts/rollup/build.js | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 2d2ca9c03691d..275c38bba3452 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -127,11 +127,11 @@ async function main() { } else { // Running locally, no concurrency. Move each channel's build artifacts into // a temporary directory so that they don't conflict. - buildForChannel('stable', '', ''); + buildForChannel('stable'); const stableDir = tmp.dirSync().name; crossDeviceRenameSync('./build', stableDir); processStable(stableDir); - buildForChannel('experimental', '', ''); + buildForChannel('experimental'); const experimentalDir = tmp.dirSync().name; crossDeviceRenameSync('./build', experimentalDir); processExperimental(experimentalDir); diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index cddab9fa7e170..5eaaf503e2a65 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -84,13 +84,17 @@ function parseRequestedNames(names, toCase) { } 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 requestedBundleTypes = parseRequestedNames( + argv.type ? argvType : [], + 'uppercase' +); + +const names = argv._; +const requestedBundleNames = parseRequestedNames( + names ? names : [], + 'lowercase' +); const forcePrettyOutput = argv.pretty; const isWatchMode = argv.watch; const syncFBSourcePath = argv['sync-fbsource']; From 0d8c88c934394cfc0b55c9c90235d7aa1943c86a Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 29 Jul 2024 17:57:12 -0400 Subject: [PATCH 3/7] Update [ghstack-poisoned] --- scripts/rollup/build-all-release-channels.js | 25 ++--------- scripts/rollup/build.js | 44 ++++++++++---------- 2 files changed, 26 insertions(+), 43 deletions(-) diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index 275c38bba3452..ceb6467bba7ea 100644 --- a/scripts/rollup/build-all-release-channels.js +++ b/scripts/rollup/build-all-release-channels.js @@ -111,7 +111,7 @@ const argv = yargs.wrap(yargs.terminalWidth()).options({ async function main() { if (argv.ci === 'github') { - await buildEverything(argv.index, argv.total); + await buildEverything(argv.releaseChannel, argv.index, argv.total); switch (argv.releaseChannel) { case 'stable': { processStable('./build'); @@ -127,11 +127,11 @@ async function main() { } else { // Running locally, no concurrency. Move each channel's build artifacts into // a temporary directory so that they don't conflict. - buildForChannel('stable'); + await buildEverything('stable'); const stableDir = tmp.dirSync().name; crossDeviceRenameSync('./build', stableDir); processStable(stableDir); - buildForChannel('experimental'); + await buildEverything('experimental'); const experimentalDir = tmp.dirSync().name; crossDeviceRenameSync('./build', experimentalDir); processExperimental(experimentalDir); @@ -147,25 +147,6 @@ async function main() { } } -function buildForChannel(channel) { - const {status} = spawnSync( - 'node', - ['./scripts/rollup/build.js', ...process.argv.slice(2)], - { - stdio: ['pipe', process.stdout, process.stderr], - env: { - ...process.env, - RELEASE_CHANNEL: channel, - }, - } - ); - - if (status !== 0) { - // Error of spawned process is already piped to this stderr - process.exit(status); - } -} - function processStable(buildDir) { if (fs.existsSync(buildDir + '/node_modules')) { // Identical to `oss-stable` but with real, semver versions. This is what diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 5eaaf503e2a65..8a0ee99eda39f 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -23,15 +23,6 @@ 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 => { @@ -366,7 +357,8 @@ function getPlugins( globalName, moduleType, pureExternalModules, - bundle + bundle, + isExperimental ) { try { const forks = Modules.getForks(bundleType, entry, moduleType, bundle); @@ -428,7 +420,7 @@ function getPlugins( 'process.env.NODE_ENV': isProduction ? "'production'" : "'development'", - __EXPERIMENTAL__, + __EXPERIMENTAL__: isExperimental, }, }), { @@ -571,7 +563,7 @@ function shouldSkipBundle(bundle, bundleType) { return false; } -function resolveEntryFork(resolvedEntry, isFBBundle) { +function resolveEntryFork(resolvedEntry, isFBBundle, isExperimental) { // Pick which entry point fork to use: // .modern.fb.js // .classic.fb.js @@ -584,7 +576,7 @@ function resolveEntryFork(resolvedEntry, isFBBundle) { if (isFBBundle) { const resolvedFBEntry = resolvedEntry.replace( '.js', - __EXPERIMENTAL__ ? '.modern.fb.js' : '.classic.fb.js' + isExperimental ? '.modern.fb.js' : '.classic.fb.js' ); const developmentFBEntry = resolvedFBEntry.replace( '.js', @@ -611,7 +603,7 @@ function resolveEntryFork(resolvedEntry, isFBBundle) { } const resolvedForkedEntry = resolvedEntry.replace( '.js', - __EXPERIMENTAL__ ? '.experimental.js' : '.stable.js' + isExperimental ? '.experimental.js' : '.stable.js' ); const devForkedEntry = resolvedForkedEntry.replace('.js', '.development.js'); if (fs.existsSync(devForkedEntry)) { @@ -624,7 +616,7 @@ function resolveEntryFork(resolvedEntry, isFBBundle) { return resolvedEntry; } -async function createBundle(bundle, bundleType) { +async function createBundle(bundle, bundleType, isExperimental) { const filename = getFilename(bundle, bundleType); const logKey = chalk.white.bold(filename) + chalk.dim(` (${bundleType.toLowerCase()})`); @@ -636,7 +628,8 @@ async function createBundle(bundle, bundleType) { let resolvedEntry = resolveEntryFork( require.resolve(bundle.entry), isFBWWWBundle || isFBRNBundle, - !isProductionBundleType(bundleType) + !isProductionBundleType(bundleType), + isExperimental ); const peerGlobals = Modules.getPeerGlobals(bundle.externals, bundleType); @@ -813,7 +806,14 @@ function handleRollupError(error) { } } -async function buildEverything(index, total) { +async function buildEverything(releaseChannel, index, total) { + // Default to building in experimental mode. If the release channel is set via + // an environment variable, then check if it's "experimental". + const isExperimental = + typeof releaseChannel === 'string' + ? releaseChannel === 'experimental' + : true; + if (!argv['unsafe-partial']) { await asyncRimRaf('build'); } @@ -850,13 +850,15 @@ async function buildEverything(index, total) { return !shouldSkipBundle(bundle, bundleType); }); - const nodeTotal = parseInt(total, 10); - const nodeIndex = parseInt(index, 10); - bundles = bundles.filter((_, i) => i % nodeTotal === nodeIndex); + if (index != null && total != null) { + const nodeTotal = parseInt(total, 10); + 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 createBundle(bundle, bundleType, isExperimental); } await Packaging.copyAllShims(); From d18e5b8854cad85f4019d6bc959383e393844c32 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 29 Jul 2024 18:11:20 -0400 Subject: [PATCH 4/7] Update [ghstack-poisoned] --- scripts/rollup/build.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 8a0ee99eda39f..ab02392426533 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -680,7 +680,8 @@ async function createBundle(bundle, bundleType, isExperimental) { bundle.global, bundle.moduleType, pureExternalModules, - bundle + bundle, + isExperimental ), output: { externalLiveBindings: false, From 33a36745645f8bfee153a3a04edb1bc4069a6643 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 29 Jul 2024 18:44:15 -0400 Subject: [PATCH 5/7] Update [ghstack-poisoned] --- scripts/rollup/build-all-release-channels.js | 28 ++++++++++-- scripts/rollup/build.js | 48 ++++++++++---------- 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/scripts/rollup/build-all-release-channels.js b/scripts/rollup/build-all-release-channels.js index ceb6467bba7ea..5615b5949c73e 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'); const Bundles = require('./bundles'); // Runs the build script for both stable and experimental release channels, @@ -111,7 +110,7 @@ const argv = yargs.wrap(yargs.terminalWidth()).options({ async function main() { if (argv.ci === 'github') { - await buildEverything(argv.releaseChannel, argv.index, argv.total); + buildForChannel(argv.releaseChannel, argv.total, argv.index); switch (argv.releaseChannel) { case 'stable': { processStable('./build'); @@ -127,11 +126,11 @@ async function main() { } else { // Running locally, no concurrency. Move each channel's build artifacts into // a temporary directory so that they don't conflict. - await buildEverything('stable'); + buildForChannel('stable', '', ''); const stableDir = tmp.dirSync().name; crossDeviceRenameSync('./build', stableDir); processStable(stableDir); - await buildEverything('experimental'); + buildForChannel('experimental', '', ''); const experimentalDir = tmp.dirSync().name; crossDeviceRenameSync('./build', experimentalDir); processExperimental(experimentalDir); @@ -147,6 +146,27 @@ async function main() { } } +function buildForChannel(channel, total, index) { + const {status} = spawnSync( + 'node', + ['./scripts/rollup/build.js', ...process.argv.slice(2)], + { + stdio: ['pipe', process.stdout, process.stderr], + env: { + ...process.env, + RELEASE_CHANNEL: channel, + CI_TOTAL: total, + CI_INDEX: index, + }, + } + ); + + if (status !== 0) { + // Error of spawned process is already piped to this stderr + process.exit(status); + } +} + function processStable(buildDir) { if (fs.existsSync(buildDir + '/node_modules')) { // Identical to `oss-stable` but with real, semver versions. This is what diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index ab02392426533..5a709b5979ae1 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -23,6 +23,15 @@ 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 => { @@ -357,8 +366,7 @@ function getPlugins( globalName, moduleType, pureExternalModules, - bundle, - isExperimental + bundle ) { try { const forks = Modules.getForks(bundleType, entry, moduleType, bundle); @@ -420,7 +428,7 @@ function getPlugins( 'process.env.NODE_ENV': isProduction ? "'production'" : "'development'", - __EXPERIMENTAL__: isExperimental, + __EXPERIMENTAL__, }, }), { @@ -563,7 +571,7 @@ function shouldSkipBundle(bundle, bundleType) { return false; } -function resolveEntryFork(resolvedEntry, isFBBundle, isExperimental) { +function resolveEntryFork(resolvedEntry, isFBBundle) { // Pick which entry point fork to use: // .modern.fb.js // .classic.fb.js @@ -576,7 +584,7 @@ function resolveEntryFork(resolvedEntry, isFBBundle, isExperimental) { if (isFBBundle) { const resolvedFBEntry = resolvedEntry.replace( '.js', - isExperimental ? '.modern.fb.js' : '.classic.fb.js' + __EXPERIMENTAL__ ? '.modern.fb.js' : '.classic.fb.js' ); const developmentFBEntry = resolvedFBEntry.replace( '.js', @@ -603,7 +611,7 @@ function resolveEntryFork(resolvedEntry, isFBBundle, isExperimental) { } const resolvedForkedEntry = resolvedEntry.replace( '.js', - isExperimental ? '.experimental.js' : '.stable.js' + __EXPERIMENTAL__ ? '.experimental.js' : '.stable.js' ); const devForkedEntry = resolvedForkedEntry.replace('.js', '.development.js'); if (fs.existsSync(devForkedEntry)) { @@ -616,7 +624,7 @@ function resolveEntryFork(resolvedEntry, isFBBundle, isExperimental) { return resolvedEntry; } -async function createBundle(bundle, bundleType, isExperimental) { +async function createBundle(bundle, bundleType) { const filename = getFilename(bundle, bundleType); const logKey = chalk.white.bold(filename) + chalk.dim(` (${bundleType.toLowerCase()})`); @@ -629,7 +637,7 @@ async function createBundle(bundle, bundleType, isExperimental) { require.resolve(bundle.entry), isFBWWWBundle || isFBRNBundle, !isProductionBundleType(bundleType), - isExperimental + __EXPERIMENTAL__ ); const peerGlobals = Modules.getPeerGlobals(bundle.externals, bundleType); @@ -680,8 +688,7 @@ async function createBundle(bundle, bundleType, isExperimental) { bundle.global, bundle.moduleType, pureExternalModules, - bundle, - isExperimental + bundle ), output: { externalLiveBindings: false, @@ -807,14 +814,7 @@ function handleRollupError(error) { } } -async function buildEverything(releaseChannel, index, total) { - // Default to building in experimental mode. If the release channel is set via - // an environment variable, then check if it's "experimental". - const isExperimental = - typeof releaseChannel === 'string' - ? releaseChannel === 'experimental' - : true; - +async function buildEverything(index, total) { if (!argv['unsafe-partial']) { await asyncRimRaf('build'); } @@ -851,15 +851,15 @@ async function buildEverything(releaseChannel, index, total) { return !shouldSkipBundle(bundle, bundleType); }); - if (index != null && total != null) { - const nodeTotal = parseInt(total, 10); - const nodeIndex = parseInt(index, 10); + if (process.env.CI_TOTAL != null && process.env.CI_INDEX != null) { + const nodeTotal = parseInt(process.env.CI_TOTAL, 10); + const nodeIndex = parseInt(process.env.CI_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, isExperimental); + await createBundle(bundle, bundleType); } await Packaging.copyAllShims(); @@ -877,6 +877,4 @@ async function buildEverything(releaseChannel, index, total) { } } -module.exports = { - buildEverything, -}; +buildEverything(); From 331ff46458670d4559307add283b100491dcf706 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 29 Jul 2024 18:45:48 -0400 Subject: [PATCH 6/7] Update [ghstack-poisoned] --- scripts/rollup/build.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 5a709b5979ae1..4d35bb2afe4cd 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -636,8 +636,7 @@ async function createBundle(bundle, bundleType) { let resolvedEntry = resolveEntryFork( require.resolve(bundle.entry), isFBWWWBundle || isFBRNBundle, - !isProductionBundleType(bundleType), - __EXPERIMENTAL__ + !isProductionBundleType(bundleType) ); const peerGlobals = Modules.getPeerGlobals(bundle.externals, bundleType); From 4103c12dadc2ad987b9ca5643fdd52ecb88db9ed Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 29 Jul 2024 18:51:17 -0400 Subject: [PATCH 7/7] Update [ghstack-poisoned] --- scripts/rollup/build.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 4d35bb2afe4cd..7bafa8d76b54e 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -813,7 +813,7 @@ function handleRollupError(error) { } } -async function buildEverything(index, total) { +async function buildEverything() { if (!argv['unsafe-partial']) { await asyncRimRaf('build'); } @@ -850,7 +850,7 @@ async function buildEverything(index, total) { return !shouldSkipBundle(bundle, bundleType); }); - if (process.env.CI_TOTAL != null && process.env.CI_INDEX != null) { + if (process.env.CI_TOTAL && process.env.CI_INDEX) { const nodeTotal = parseInt(process.env.CI_TOTAL, 10); const nodeIndex = parseInt(process.env.CI_INDEX, 10); bundles = bundles.filter((_, i) => i % nodeTotal === nodeIndex);