Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: bump deps, fix expected test result for core-js #4300

Merged
merged 1 commit into from Dec 17, 2021

Conversation

dnalborczyk
Copy link
Contributor

This PR contains:

  • bugfix
  • feature
  • refactor
  • documentation
  • other

Are tests included?

  • yes (bugfixes and features will not be merged without tests)
  • no

Breaking Changes?

  • yes (breaking changes will not be merged unless absolutely necessary)
  • no

List any relevant issue numbers:

Description

just a left-over from: #4293

I thought at the time core-js was halting the ci run, so I left it out, but now I'm not really sure if I remember correctly. 😕

@codecov
Copy link

codecov bot commented Dec 13, 2021

Codecov Report

Merging #4300 (4f0a409) into master (2e91c85) will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #4300   +/-   ##
=======================================
  Coverage   98.45%   98.45%           
=======================================
  Files         205      205           
  Lines        7311     7311           
  Branches     2082     2082           
=======================================
  Hits         7198     7198           
  Misses         55       55           
  Partials       58       58           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2e91c85...4f0a409. Read the comment docs.

@lukastaegert lukastaegert merged commit 28cc198 into rollup:master Dec 17, 2021
@dnalborczyk dnalborczyk deleted the bump-deps-core-js branch December 17, 2021 16:34
@kzc
Copy link
Contributor

kzc commented Dec 17, 2021

@lukastaegert I noticed that 28cc198 and all commits starting from dbcf24a have been randomly failing the watch tests with timeouts on my Mac - irrespective of NodeJS version (v12.x, v14.x, v16.x):

However, when I revert this single package and run npm ci then npm test will run successfully with no errors:

$ git diff -U0
diff --git a/package-lock.json b/package-lock.json
index 116e472..6591429 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -484,3 +484,3 @@
-      "version": "21.0.1",
-      "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz",
-      "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==",
+      "version": "20.0.0",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-20.0.0.tgz",
+      "integrity": "sha512-5K0g5W2Ol8hAcTHqcTBHiA7M58tfmYi1o9KxeJuuRNpGaTa5iLjcyemBitCBcKXaHamOBBEH2dGom6v6Unmqjg==",
diff --git a/package.json b/package.json
index 2784a12..ee80f3b 100644
--- a/package.json
+++ b/package.json
@@ -63 +63 @@
-    "@rollup/plugin-commonjs": "^21.0.1",
+    "@rollup/plugin-commonjs": "^20.0.0",

This took hours to isolate and frankly does not make any sense. The usual suspects - chokidar and fsevents - remained the same. Perhaps the file system usage pattern changed and that version of the commonjs plugin was the unwitting victim of a watch bug.

The 5 to 12 not-so-random @rollup/plugin-commonjs@21.0.1 watch test failures each looked like this:

  1) rollup.watch
       watches a file and triggers reruns if necessary:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/opt/rollup/rollup/test/watch/index.js)
      at listOnTimeout (node:internal/timers:557:17)
      at processTimers (node:internal/timers:500:7)

Upgrading to @rollup/plugin-commonjs@22.0.0-4 with no other package changes also causes the watch tests to pass. The core-js tests naturally fail due to commonjs code gen differences, but that is expected.

I personally don't use rollup watch, so it doesn't affect me. I was just putting the finishing touches on a patch to report unfulfilled hook actions to stderr upon abrupt rollup exit and noticed it during testing.

@dnalborczyk
Copy link
Contributor Author

dnalborczyk commented Dec 17, 2021

interesting. I don't re-call having seen any test timeouts on my box. 🤔 and if I did, I did a bunch of other things at the same time (building node, building deno etc.) thinking there likely wasn't enough processing power and/or memory available. I'll keep an eye out tho.

that said, just noticed, I think we should add a macOS build to the ci matrix.

have been randomly failing the watch tests with timeouts on my Mac

are they failing all the time, or only sometimes?

@kzc
Copy link
Contributor

kzc commented Dec 17, 2021

100% locally reproducible.

I found the problem. I wasn't going crazy after all.

It's a genuine bug in @rollup/plugin-commonjs@21.0.1 when used to bundle rollup itself:

--- rollup-dist-built-with-commonjs-20.0.0/shared/rollup.js	2021-12-17 14:23:52.000000000 -0500
+++ rollup-dist-built-with-commonjs-21.0.1/shared/rollup.js	2021-12-17 14:22:47.000000000 -0500
@@ -1,7 +1,7 @@
 /*
   @license
 	Rollup.js v2.61.1
-	Fri, 17 Dec 2021 19:23:44 GMT - commit 28cc1988bdb39fb47d3a6c24f90cb34e0c9c39ca
+	Fri, 17 Dec 2021 19:22:38 GMT - commit 28cc1988bdb39fb47d3a6c24f90cb34e0c9c39ca
 
 
 	https://github.com/rollup/rollup
@@ -592,36 +592,9 @@
         fsEventsImportError = err;
     });
 }
-// A call to this function will be injected into the chokidar code
-function getFsEvents() {
-    if (fsEventsImportError)
-        throw fsEventsImportError;
-    return fsEvents;
-}
-
-const fseventsImporter = {
-  __proto__: null,
-  loadFsEvents,
-  getFsEvents
-};
 
 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
 
-function getAugmentedNamespace(n) {
-	if (n.__esModule) return n;
-	var a = Object.defineProperty({}, '__esModule', {value: true});
-	Object.keys(n).forEach(function (k) {
-		var d = Object.getOwnPropertyDescriptor(n, k);
-		Object.defineProperty(a, k, d.get ? d : {
-			enumerable: true,
-			get: function () {
-				return n[k];
-			}
-		});
-	});
-	return a;
-}
-
 var charToInteger = {};
 var chars$1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
 for (var i = 0; i < chars$1.length; i++) {
@@ -23611,10 +23584,8 @@
 exports.defineConfig = defineConfig;
 exports.ensureArray = ensureArray$1;
 exports.error = error;
-exports.fseventsImporter = fseventsImporter;
 exports.generatedCodePresets = generatedCodePresets;
 exports.getAliasName = getAliasName;
-exports.getAugmentedNamespace = getAugmentedNamespace;
 exports.getOrCreate = getOrCreate;
 exports.loadFsEvents = loadFsEvents;
 exports.objectifyOptionWithPresets = objectifyOptionWithPresets;

Notice that function getFsEvents is absent in the rollup dist built with @rollup/plugin-commonjs@21.0.1.

@kzc
Copy link
Contributor

kzc commented Dec 17, 2021

Based on the finding above I recommend to apply the patch in #4300 (comment) to revert the commonjs plugin rollup is built with.

@dnalborczyk
Copy link
Contributor Author

dnalborczyk commented Dec 17, 2021

nice find @kzc !

just got the macos ci to fail, but only on node v17: https://github.com/rollup/rollup/runs/4564688779?check_suite_focus=true

then on v12 the next run: https://github.com/rollup/rollup/runs/4564828157?check_suite_focus=true

@dnalborczyk
Copy link
Contributor Author

dnalborczyk commented Dec 17, 2021

do you know if v21.0.0 or v21.0.1 introduced this?

edit: it seems 21.0.0 does not fail (which might not mean anything)

edit: nm, it's v21.0.0, just did a build diff myself.

@kzc
Copy link
Contributor

kzc commented Dec 18, 2021

Please hold off on #4308. I was on the right track, but the reversion of the commonjs plugin works for the wrong reason. Ironically, rollup built with @rollup/plugin-commonjs@21.0.1 is failing watch tests on Mac because it's working as designed.

In the diff below rollup-dist-built-with-commonjs-20.0.0 passes all tests, and rollup-dist-built-with-commonjs-21.0.1 randomly fails the watch tests:

--- rollup-dist-built-with-commonjs-20.0.0/shared/index.js
+++ rollup-dist-built-with-commonjs-21.0.1/shared/index.js
@@ -3056,15 +3056,13 @@

 var fseventsHandler = {exports: {}};

-const require$$3 = /*@__PURE__*/rollup.getAugmentedNamespace(rollup.fseventsImporter);
-
 const fs$1 = fs$4;
 const sysPath$1 = path$1;
 const { promisify: promisify$1 } = require$$2;

 let fsevents;
 try {
-  fsevents = require$$3.getFsEvents();
+  fsevents = require('../../../src/watch/fsevents-importer').getFsEvents();
 } catch (error) {
   if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error);
 }

Notice that the failing rollup-dist-built-with-commonjs-21.0.1 has the effects of the plugin build-plugins/conditional-fsevents-import.ts.

After some experimentation I noticed that the commonjs plugins that pass all watch tests on Mac, namely @rollup/plugin-commonjs@20.0.0 and @rollup/plugin-commonjs@22.0.0-4, both lack the effects of build-plugins/conditional-fsevents-import.ts.

After the following patch is applied to 28cc198 (which uses @rollup/plugin-commonjs@21.0.1) it passes npm test including all watch tests on Mac:

--- a/rollup.config.ts
+++ b/rollup.config.ts
@@ -11,3 +11,2 @@ import { terser } from 'rollup-plugin-terser';
 import addCliEntry from './build-plugins/add-cli-entry';
-import conditionalFsEventsImport from './build-plugins/conditional-fsevents-import';
 import emitModulePackageFile from './build-plugins/emit-module-package-file';
@@ -70,3 +69,2 @@ const nodePlugins = [
        json(),
-       conditionalFsEventsImport(),
        string({ include: '**/*.md' }),

@kzc
Copy link
Contributor

kzc commented Dec 18, 2021

So the outstanding questions are:

  1. Should a rollup release installed via npm contain the following?
$ node_modules/.bin/rollup -v
rollup v2.61.1

$ grep fsevents-importer node_modules/rollup/dist/shared/index.js 
  fsevents = require('../../../src/watch/fsevents-importer').getFsEvents();

Shouldn't that require() pointing to a path within the rollup src tree have been bundled inline?

  1. If the plugin conditionalFsEventsImport is removed from rollup.config.ts will it then run npm test successfully on Linux and Windows as it does on Mac?

@dnalborczyk
Copy link
Contributor Author

dnalborczyk commented Dec 21, 2021

fsevents = require('../../../src/watch/fsevents-importer').getFsEvents();

that's weird, I'm guessing this never worked (as intended)? 🤔 unless rollup was published with the transpiled src.

edit: nm, you are saying that the v20 cjs build had a different output.

@lukastaegert
Copy link
Member

Actually it used to work well, and I understand now why it broke. This require was meant to be internal, and it was actually injected into fsevents by a build plugin. The reason it failed to work is because the require is inside a try-catch, and with the last major, the default auf the ignoreTryCatch option was unfortunately changed to true, ignoring ALL require expressions in try blocks. The commonjs beta plugin fixes this by only ignoring external requires.
The simple fix for now would be to pass ignoreTryCatch: false to the commonjs plugin in our rollup.config.js. I do not think a test is needed, though, as the problem is very specific and will pass away entirely with the next version of the commonjs plugin anyway.

@kzc
Copy link
Contributor

kzc commented Dec 21, 2021

The real question is whether conditionalFsEventsImport is needed at all. When it is removed npm test runs successfully.

@dnalborczyk
Copy link
Contributor Author

The real question is whether conditionalFsEventsImport is needed at all. When it is removed npm test runs successfully.

@kzc just a bad guess: the try/catch require('fsevents') call fails, and chokidar uses the fallback (kqueue) on macos.

@dnalborczyk dnalborczyk mentioned this pull request Dec 21, 2021
9 tasks
@kzc
Copy link
Contributor

kzc commented Dec 21, 2021

I'm not talking about needing conditionalFsEventsImport on Mac specifically. The last few rollup releases had require('../../../src/watch/fsevents-importer').getFsEvents(); in the code and no one noticed/complained about watch on any platform. I can only assume from this that the conditionalFsEventsImport plugin is not needed on any platform.

Side note: the clear screen for CLI use of rollup --watch effectively hid the error:

let fsevents;
try {
  fsevents = require('../../../src/watch/fsevents-importer').getFsEvents();
} catch (error) {
  if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error);
}

so no users could observe it. I recommend to remove the initial clear screen from watch.

@lukastaegert
Copy link
Member

The fsevents plugin very much improves watch mode reliability and performance for large projects on Mac. We are lucky nobody complained, but the symptoms would be hard to diagnose correctly anyway.

@dnalborczyk
Copy link
Contributor Author

ok, my bad, should have clarified: 😃

just a bad guess: the try/catch require('fsevents') call fails, and chokidar uses the fallback (kqueue) on macos.
just a bad guess: the try/catch require('../../../src/watch/fsevents-importer') call fails, and chokidar uses the fallback (kqueue) on macos.

@kzc
Copy link
Contributor

kzc commented Dec 21, 2021

I do not think a test is needed, though, as the problem is very specific and will pass away entirely with the next version of the commonjs plugin anyway.

If it happened once, it could happen again. This is very difficult to diagnose and debug and wasted hours of time.

@dnalborczyk
Copy link
Contributor Author

will pass away entirely with the next version of the commonjs plugin anyway

curious: how? is the ignore-try/catch-option going away?

@dnalborczyk
Copy link
Contributor Author

If it happened once, it could happen again. This is very difficult to diagnose and debug and wasted hours of time.

the only simple way to test this is possibly to check if fsevents have been successfully imported. believe it's exported (and accessible) by the current (fixed) build. I assume that test would need to run on macos ci only.

@kzc
Copy link
Contributor

kzc commented Dec 21, 2021

I assume that test would need to run on macos ci only.

This PR would be sufficient: #4307

@lukastaegert
Copy link
Member

If it happened once, it could happen again. This is very difficult to diagnose and debug and wasted hours of time.

True, but if we are specifying the option explicitly, even another change in default values should not have an effect. We should definitely add the Mac pipeline, and that one becomes at least flaky if we do not use fsevents (which alone should be a testament to its usefulness), but I think this should be enough of a test.

But reading your last comment sounds to me like that is what you meant.

curious: how? is the ignore-try/catch-option going away?

It is not going away, but one of the changes of the beta version is that ignore-try-catch will never ignore internal imports, only external ones. And this is an internal import.

@dnalborczyk
Copy link
Contributor Author

dnalborczyk commented Dec 22, 2021

curious: how? is the ignore-try/catch-option going away?

It is not going away, but one of the changes of the beta version is that ignore-try-catch will never ignore internal imports, only external ones. And this is an internal import.

ah, thanks!

I was just wondering, is it not possible to e.g. declare fsevents (as required from chokidar) as external and have a cjs and esm build? I noticed the require remains untouched when specified as external, as opposed to be a e.g. dynamic import() for the esm build instead. would there be a problem with top level await for the esm build, since it's unfortunately not (yet) supported everywhere?

I guess I gotta play with the settings a bit 😄 I usually try to avoid native modules if in any way possible.

@lukastaegert
Copy link
Member

The problem is that without the extra logic, the conditional require is converted to an actual import of a native module, which fails miserably.

@dnalborczyk
Copy link
Contributor Author

The problem is that without the extra logic, the conditional require is converted to an actual import of a native module, which fails miserably.

that makes sense. what I meant tho, if one currently marks fsevents e.g. as external, I believe rollup (or the cjs plugin) leaves the require untouched, instead of potentially converting it to e.g. a dynamic import for an esm build, which in turn would be top-level-await.

another potential avenue could be to use createRequire, but the problem is that this would only work for building for node.js.

@dnalborczyk
Copy link
Contributor Author

dnalborczyk commented Dec 23, 2021

it seems the macos watch tests are flaky on master :/ fsevents is being loaded tho, just checked.

@kzc
Copy link
Contributor

kzc commented Dec 23, 2021

I see 3 watch flakes for node12/mac and 1 flake for node14/linux on master. So it's not specific to Mac.

The problem appears to be a race condition in the way the tests are written.

Here's an expanded version of the rollup output for the failing node14/linux test case test/cli/samples/watch/watch-config-no-update/_config.js:

https://github.com/rollup/rollup/runs/4615040404?check_suite_focus=true

rollup v2.61.1
bundles main.js → _actual/main.js...
created _actual/main.js in 6ms

Reloading updated config...
[!] Error: Config file must export an options object, or an array of options objects
https://rollupjs.org/guide/en/#configuration-files
Error: Config file must export an options object, or an array of options objects
    at Object.error (/home/runner/work/rollup/rollup/src/utils/error.ts:15:53)
    at getConfigList (/home/runner/work/rollup/rollup/cli/run/loadConfigFile.ts:140:10)

bundles main.js → _actual/main.js...
created _actual/main.js in 4ms

What I think is going on in these failures is that updated config is being reloaded mid-write and as result rollup is failing to parse the incomplete config file.

Let's test the regexp against the test output.

If one were to change the watch test regexp in question from:

$ node -p '/^rollup v\d+\.\d+\.\d+(-\d+)?\nbundles main.js → _actual[\\/]main.js...\ncreated _actual[\\/]main.js in \d+ms\n$/.test("rollup v2.61.1\nbundles main.js → _actual/main.js...\ncreated _actual/main.js in 6ms\n\nReloading updated config...\n[!] Error: Config file must export an options object, or an array of options objects\nhttps://rollupjs.org/guide/en/#configuration-files\nError: Config file must export an options object, or an array of options objects\n    at Object.error (/home/runner/work/rollup/rollup/src/utils/error.ts:15:53)\n    at getConfigList (/home/runner/work/rollup/rollup/cli/run/loadConfigFile.ts:140:10)\n\nbundles main.js → _actual/main.js...\ncreated _actual/main.js in 4ms\n")'
false

to:

$ node -p '/^rollup v\d+\.\d+\.\d+(-\d+)?\n.*bundles main.js → _actual[\\/]main.js...\ncreated _actual[\\/]main.js in \d+ms\n$/m.test("rollup v2.61.1\nbundles main.js → _actual/main.js...\ncreated _actual/main.js in 6ms\n\nReloading updated config...\n[!] Error: Config file must export an options object, or an array of options objects\nhttps://rollupjs.org/guide/en/#configuration-files\nError: Config file must export an options object, or an array of options objects\n    at Object.error (/home/runner/work/rollup/rollup/src/utils/error.ts:15:53)\n    at getConfigList (/home/runner/work/rollup/rollup/cli/run/loadConfigFile.ts:140:10)\n\nbundles main.js → _actual/main.js...\ncreated _actual/main.js in 4ms\n")'
true

that might be an adequate workaround. It would ignore the half-written rollup config file parse error in the middle.

@lukastaegert
Copy link
Member

if one currently marks fsevents e.g. as external, I believe rollup (or the cjs plugin) leaves the require untouched, instead of potentially converting it to e.g. a dynamic import for an esm build, which in turn would be top-level-await.

The cjs plugin could leave a require expression, but that would also remain a require expression for the ESM build as well, or rather a non-existing global variable call. The current solution works correctly for all output formats.

@kzc
Copy link
Contributor

kzc commented Dec 23, 2021

The other flaky watch tests are also due to race conditions in the tests themselves. When github CI is overloaded (which is the norm these days) the watch failures tend to appear more frequently in these flaky tests. If I have time over the holiday I'll see if I can make these tests more robust. The biggest obstacle is not so much the test fixes themselves, but understanding what they are trying to do.

@kzc
Copy link
Contributor

kzc commented Dec 24, 2021

I briefly looked at the watch failures in recent commits for macos and linux and put together this patch which I think could help reduce some flakiness:

diff --git a/test/cli/samples/watch/watch-config-early-update/_config.js b/test/cli/samples/watch/watch-config-early-update/_config.js
index c13c269..7a6061e 100644
--- a/test/cli/samples/watch/watch-config-early-update/_config.js
+++ b/test/cli/samples/watch/watch-config-early-update/_config.js
@@ -23,7 +23,7 @@ module.exports = {
                 format: 'es'
               }
             }),
-          1000
+          2000
         );
       });
                `
diff --git a/test/cli/samples/watch/watch-config-no-update/_config.js b/test/cli/samples/watch/watch-config-no-update/_config.js
index 635d77d..a0e31d5 100644
--- a/test/cli/samples/watch/watch-config-no-update/_config.js
+++ b/test/cli/samples/watch/watch-config-no-update/_config.js
@@ -16,14 +16,14 @@ module.exports = {
        command: 'rollup -cw',
        before() {
                configFile = path.resolve(__dirname, 'rollup.config.js');
-               fs.writeFileSync(configFile, configContent);
+               atomicWriteFileSync(configFile, configContent);
        },
        after() {
                fs.unlinkSync(configFile);
        },
        abortOnStderr(data) {
                if (data.includes('created _actual/main.js')) {
-                       fs.writeFileSync(configFile, configContent);
+                       atomicWriteFileSync(configFile, configContent);
                        return new Promise(resolve => setTimeout(() => resolve(true), 500));
                }
        },
@@ -37,3 +37,12 @@ module.exports = {
                }
        }
 };
+
+// Workaround a race condition in fs.writeFileSync that temporarily creates
+// an empty file for a brief moment which may be read by rollup watch - even
+// if the content being overwritten is identical.
+function atomicWriteFileSync(filePath, contents) {
+       const stagingPath = filePath + "_";
+       fs.writeFileSync(stagingPath, contents);
+       fs.renameSync(stagingPath, filePath);
+}
diff --git a/test/watch/index.js b/test/watch/index.js
index f7d9124..853a7ce 100644
--- a/test/watch/index.js
+++ b/test/watch/index.js
@@ -311,7 +311,7 @@ describe('rollup.watch', () => {
                const MAIN_ID = path.resolve('test/_tmp/input/main.js');
                let lastEvent = null;
                await sander.copydir('test/watch/samples/watch-files').to('test/_tmp/input');
-               await wait(100);
+               await wait(200);
                watcher = rollup.watch({
                        input: 'test/_tmp/input/main.js',
                        output: {

I believe the lack of an atomic file write was the cause of the rare failure in test/cli/samples/watch/watch-config-no-update, as only an empty config file (or perhaps a config file consisting only of comments) could have produced the failure Error: Config file must export an options object, or an array of options objects seen in the github CI log. Rollup would have produced an acorn parse error had a config file with JS code been partially written at the time of the read. function atomicWriteFileSync probably should be put into a util file for reuse in other tests. (Side note: sander.writeFileSync used in other tests might have the same atomicity issue.)

Unfortunately for the other two flaky failing tests, all I could offer was to further game the race in favor of passing on overloaded machines, as those tests are quite elaborate and are above my pay grade.

github CI machine load variability has been quite high lately. Tests with race conditions will continue to randomly fail from time to time, and the failures will tend to cluster together depending on when the job is run. But it's only significant if a given test consistently fails on a specific platform for several days.

@lukastaegert lukastaegert mentioned this pull request Dec 25, 2021
9 tasks
@lukastaegert
Copy link
Member

I have created #4318 to investigate these ideas and look into the other watch tests. Discussion should probably continue there. Thanks for the work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants