Rollup build script --unsafe-partial flag is broken
bvaughn opened this issue · comments
The following example command sequence will fail:
# Grab the latest build artifacts from CI
scripts/release/download-experimental-build.js --commit=main
# Rebuild only the local NODE bundle from the source of react-dom
# Leave all other artifacts untouched
yarn build --unsafe-partial --type=NODE_DEV react-dom/index
# Throws
The above sequence should work but instead fails with one of the two errors below:
Error: ENOENT: no such file or directory
Error: SyntaxError: Unexpected end of JSON input
This leaves the repo in a broken state (tests won't run, DevTools test shell will crash, etc).
These errors are thrown because this function prematurely resolves:
Lines 10 to 24 in 67222f0
Either before the package.json
file has been copied, or after it has been copied (but while its contents are still empty).
This causes the subsequent read of package.json
to throw:
react/scripts/rollup/packaging.js
Lines 145 to 148 in 67222f0
The error above can be verified by adding logging to the asyncTopyTo
method:
function asyncCopyTo(from, to) {
return asyncMkDirP(path.dirname(to)).then(
() =>
new Promise((resolve, reject) => {
ncp(from, to, error => {
if (error) {
// Wrap to have a useful stack trace.
reject(new Error(error));
return;
}
if (to.includes('package.json')){
console.log(`asyncCopyTo() -> ncp("${from}", "${to}") -> resolve`);
// This line will either throw (no file) or print an empty string in many cases:
console.log(require('fs').readFileSync(to).toString());
}
resolve();
});
})
);
}
I'm able to "fix" this issue by introducing a small amount of delay, e.g.
diff --git a/scripts/rollup/packaging.js b/scripts/rollup/packaging.js
index eaf78959a6..5844d9116f 100644
--- a/scripts/rollup/packaging.js
+++ b/scripts/rollup/packaging.js
@@ -196,6 +196,10 @@ async function prepareNpmPackage(name) {
),
asyncCopyTo(`packages/${name}/npm`, `build/node_modules/${name}`),
]);
+
+ // Wait for copied files to exist; asyncCopyTo() completes prematurely.
+ await new Promise(resolve => setTimeout(resolve, 100));
+
filterOutEntrypoints(name);
const tgzName = (
await asyncExecuteCommand(`npm pack build/node_modules/${name}`)
But this feels pretty hacky and fragile.
Seems like this is perhaps related to AvianFlu/ncp#127