mirror of
https://github.com/zebrajr/react.git
synced 2025-12-07 12:20:38 +01:00
The bindings upstream in Relay has been removed so we don't need these builds anymore. The idea is to revisit an FB integration of Flight but it wouldn't use the Relay specific bindings. It's a bit unclear how it would look but likely more like the OSS version so not worth keeping these around. The `dom-relay` name also included the FB specific Fizz implementation of the streaming config so I renamed that to `dom-fb`. There's no Fizz implementation for Native yet so I just removed `native-relay`. We created a configurable fork for how to encode the output of Flight and the Relay implementation encoded it as JSON objects instead of strings/streams. The new implementation would likely be more stream-like and just encode it directly as string/binary chunks. So I removed those indirections so that this can just be declared inline in ReactFlightServer/Client.
295 lines
8.6 KiB
JavaScript
295 lines
8.6 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
existsSync,
|
|
readdirSync,
|
|
unlinkSync,
|
|
readFileSync,
|
|
writeFileSync,
|
|
} = require('fs');
|
|
const path = require('path');
|
|
const Bundles = require('./bundles');
|
|
const {
|
|
asyncCopyTo,
|
|
asyncExecuteCommand,
|
|
asyncExtractTar,
|
|
asyncRimRaf,
|
|
} = require('./utils');
|
|
const {getSigningToken, signFile} = require('signedsource');
|
|
|
|
const {
|
|
NODE_ES2015,
|
|
ESM_DEV,
|
|
ESM_PROD,
|
|
UMD_DEV,
|
|
UMD_PROD,
|
|
UMD_PROFILING,
|
|
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;
|
|
|
|
function getPackageName(name) {
|
|
if (name.indexOf('/') !== -1) {
|
|
return name.split('/')[0];
|
|
}
|
|
return name;
|
|
}
|
|
|
|
function getBundleOutputPath(bundle, bundleType, filename, packageName) {
|
|
switch (bundleType) {
|
|
case NODE_ES2015:
|
|
return `build/node_modules/${packageName}/cjs/${filename}`;
|
|
case ESM_DEV:
|
|
case ESM_PROD:
|
|
return `build/node_modules/${packageName}/esm/${filename}`;
|
|
case BUN_DEV:
|
|
case BUN_PROD:
|
|
return `build/node_modules/${packageName}/cjs/${filename}`;
|
|
case NODE_DEV:
|
|
case NODE_PROD:
|
|
case NODE_PROFILING:
|
|
return `build/node_modules/${packageName}/cjs/${filename}`;
|
|
case UMD_DEV:
|
|
case UMD_PROD:
|
|
case UMD_PROFILING:
|
|
return `build/node_modules/${packageName}/umd/${filename}`;
|
|
case FB_WWW_DEV:
|
|
case FB_WWW_PROD:
|
|
case FB_WWW_PROFILING:
|
|
return `build/facebook-www/${filename}`;
|
|
case RN_OSS_DEV:
|
|
case RN_OSS_PROD:
|
|
case RN_OSS_PROFILING:
|
|
switch (packageName) {
|
|
case 'react-native-renderer':
|
|
return `build/react-native/implementations/${filename}`;
|
|
default:
|
|
throw new Error('Unknown RN package.');
|
|
}
|
|
case RN_FB_DEV:
|
|
case RN_FB_PROD:
|
|
case RN_FB_PROFILING:
|
|
switch (packageName) {
|
|
case 'scheduler':
|
|
case 'react':
|
|
case 'react-is':
|
|
case 'react-test-renderer':
|
|
return `build/facebook-react-native/${packageName}/cjs/${filename}`;
|
|
case 'react-native-renderer':
|
|
return `build/react-native/implementations/${filename.replace(
|
|
/\.js$/,
|
|
'.fb.js'
|
|
)}`;
|
|
default:
|
|
throw new Error('Unknown RN package.');
|
|
}
|
|
case BROWSER_SCRIPT: {
|
|
// Bundles that are served as browser scripts need to be able to be sent
|
|
// straight to the browser with any additional bundling. We shouldn't use
|
|
// a module to re-export. Depending on how they are served, they also may
|
|
// not go through package.json module resolution, so we shouldn't rely on
|
|
// that either. We should consider the output path as part of the public
|
|
// contract, and explicitly specify its location within the package's
|
|
// directory structure.
|
|
const outputPath = bundle.outputPath;
|
|
if (!outputPath) {
|
|
throw new Error(
|
|
'Bundles with type BROWSER_SCRIPT must specific an explicit ' +
|
|
'output path.'
|
|
);
|
|
}
|
|
return `build/node_modules/${packageName}/${outputPath}`;
|
|
}
|
|
default:
|
|
throw new Error('Unknown bundle type.');
|
|
}
|
|
}
|
|
|
|
async function copyWWWShims() {
|
|
await asyncCopyTo(
|
|
`${__dirname}/shims/facebook-www`,
|
|
'build/facebook-www/shims'
|
|
);
|
|
}
|
|
|
|
async function copyRNShims() {
|
|
await asyncCopyTo(
|
|
`${__dirname}/shims/react-native`,
|
|
'build/react-native/shims'
|
|
);
|
|
await asyncCopyTo(
|
|
require.resolve('react-native-renderer/src/ReactNativeTypes.js'),
|
|
'build/react-native/shims/ReactNativeTypes.js'
|
|
);
|
|
processGenerated('build/react-native/shims');
|
|
}
|
|
|
|
function processGenerated(directory) {
|
|
const files = readdirSync(directory)
|
|
.filter(dir => dir.endsWith('.js'))
|
|
.map(file => path.join(directory, file));
|
|
|
|
files.forEach(file => {
|
|
const originalContents = readFileSync(file, 'utf8');
|
|
const contents = originalContents
|
|
// Replace {@}format with {@}noformat
|
|
.replace(/(\r?\n\s*\*\s*)@format\b.*(\n)/, '$1@noformat$2')
|
|
// Add {@}nolint and {@}generated
|
|
.replace(/(\r?\n\s*\*)\//, `$1 @nolint$1 ${getSigningToken()}$1/`);
|
|
const signedContents = signFile(contents);
|
|
writeFileSync(file, signedContents, 'utf8');
|
|
});
|
|
}
|
|
|
|
async function copyAllShims() {
|
|
await Promise.all([copyWWWShims(), copyRNShims()]);
|
|
}
|
|
|
|
function getTarOptions(tgzName, packageName) {
|
|
// Files inside the `npm pack`ed archive start
|
|
// with "package/" in their paths. We'll undo
|
|
// this during extraction.
|
|
const CONTENTS_FOLDER = 'package';
|
|
return {
|
|
src: tgzName,
|
|
dest: `build/node_modules/${packageName}`,
|
|
tar: {
|
|
entries: [CONTENTS_FOLDER],
|
|
map(header) {
|
|
if (header.name.indexOf(CONTENTS_FOLDER + '/') === 0) {
|
|
header.name = header.name.slice(CONTENTS_FOLDER.length + 1);
|
|
}
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
let entryPointsToHasBundle = new Map();
|
|
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
|
|
for (const bundle of Bundles.bundles) {
|
|
let hasBundle = entryPointsToHasBundle.get(bundle.entry);
|
|
if (!hasBundle) {
|
|
const hasNonFBBundleTypes = bundle.bundleTypes.some(
|
|
type =>
|
|
type !== FB_WWW_DEV && type !== FB_WWW_PROD && type !== FB_WWW_PROFILING
|
|
);
|
|
entryPointsToHasBundle.set(bundle.entry, hasNonFBBundleTypes);
|
|
}
|
|
}
|
|
|
|
function filterOutEntrypoints(name) {
|
|
// Remove entry point files that are not built in this configuration.
|
|
let jsonPath = `build/node_modules/${name}/package.json`;
|
|
let packageJSON = JSON.parse(readFileSync(jsonPath));
|
|
let files = packageJSON.files;
|
|
let exportsJSON = packageJSON.exports;
|
|
let browserJSON = packageJSON.browser;
|
|
if (!Array.isArray(files)) {
|
|
throw new Error('expected all package.json files to contain a files field');
|
|
}
|
|
let changed = false;
|
|
for (let i = 0; i < files.length; i++) {
|
|
let filename = files[i];
|
|
let entry =
|
|
filename === 'index.js'
|
|
? name
|
|
: name + '/' + filename.replace(/\.js$/, '');
|
|
let hasBundle = entryPointsToHasBundle.get(entry);
|
|
if (hasBundle === undefined) {
|
|
// This entry doesn't exist in the bundles. Check if something similar exists.
|
|
hasBundle =
|
|
entryPointsToHasBundle.get(entry + '.node') ||
|
|
entryPointsToHasBundle.get(entry + '.browser');
|
|
}
|
|
if (hasBundle === undefined) {
|
|
// This doesn't exist in the bundles. It's an extra file.
|
|
} else if (hasBundle === true) {
|
|
// This is built in this release channel.
|
|
} else {
|
|
// This doesn't have any bundleTypes in this release channel.
|
|
// Let's remove it.
|
|
files.splice(i, 1);
|
|
i--;
|
|
unlinkSync(`build/node_modules/${name}/${filename}`);
|
|
changed = true;
|
|
// Remove it from the exports field too if it exists.
|
|
if (exportsJSON) {
|
|
if (filename === 'index.js') {
|
|
delete exportsJSON['.'];
|
|
} else {
|
|
delete exportsJSON['./' + filename.replace(/\.js$/, '')];
|
|
}
|
|
}
|
|
if (browserJSON) {
|
|
delete browserJSON['./' + filename];
|
|
}
|
|
}
|
|
|
|
// We only export the source directory so Jest and Rollup can access them
|
|
// during local development and at build time. The files don't exist in the
|
|
// public builds, so we don't need the export entry, either.
|
|
const sourceWildcardExport = './src/*';
|
|
if (exportsJSON && exportsJSON[sourceWildcardExport]) {
|
|
delete exportsJSON[sourceWildcardExport];
|
|
changed = true;
|
|
}
|
|
}
|
|
if (changed) {
|
|
let newJSON = JSON.stringify(packageJSON, null, ' ');
|
|
writeFileSync(jsonPath, newJSON);
|
|
}
|
|
}
|
|
|
|
async function prepareNpmPackage(name) {
|
|
await Promise.all([
|
|
asyncCopyTo('LICENSE', `build/node_modules/${name}/LICENSE`),
|
|
asyncCopyTo(
|
|
`packages/${name}/package.json`,
|
|
`build/node_modules/${name}/package.json`
|
|
),
|
|
asyncCopyTo(
|
|
`packages/${name}/README.md`,
|
|
`build/node_modules/${name}/README.md`
|
|
),
|
|
asyncCopyTo(`packages/${name}/npm`, `build/node_modules/${name}`),
|
|
]);
|
|
filterOutEntrypoints(name);
|
|
const tgzName = (
|
|
await asyncExecuteCommand(`npm pack build/node_modules/${name}`)
|
|
).trim();
|
|
await asyncRimRaf(`build/node_modules/${name}`);
|
|
await asyncExtractTar(getTarOptions(tgzName, name));
|
|
unlinkSync(tgzName);
|
|
}
|
|
|
|
async function prepareNpmPackages() {
|
|
if (!existsSync('build/node_modules')) {
|
|
// We didn't build any npm packages.
|
|
return;
|
|
}
|
|
const builtPackageFolders = readdirSync('build/node_modules').filter(
|
|
dir => dir.charAt(0) !== '.'
|
|
);
|
|
await Promise.all(builtPackageFolders.map(prepareNpmPackage));
|
|
}
|
|
|
|
module.exports = {
|
|
copyAllShims,
|
|
getPackageName,
|
|
getBundleOutputPath,
|
|
prepareNpmPackages,
|
|
};
|