apache / apache/cordova-lib

Plugin hook execution order is unspecified (fast-glob readdir order), while install order is deterministic since #933

Open
#1,010 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
231
Forks
242
Avg merge
2h 51m
Merged PRs (30d)
7

Description

### Bug Report

**Problem**

Plugin hook execution order is unspecified, so a plugin whose hook depends on another plugin's hook having already run works or fails depending on the filesystem. Nothing in the project surfaces the order, and the failure is silent: the hook reports success and its work is discarded a moment later by the other plugin.

`getAllPluginsHookScriptFiles` in `src/hooks/scriptsFinder.js` enumerates plugins like this:

```js
const plugins = (new PluginInfoProvider()).getAllWithinSearchPath(path.join(opts.projectRoot, 'plugins'));
plugins.forEach(function (pluginInfo) { /* collect that plugin's hook scripts */ });
```

and `getAllWithinSearchPath` (cordova-common, `PluginInfo/PluginInfoProvider.js`) resolves to:

```js
const pluginXmlPaths = fastGlob.sync('{,@*/}*/plugin.xml', { fs, cwd: absPath, onlyFiles: true, absolute: true })
```

`fast-glob` does not sort, so this is `readdir` order for `plugins/`.

**What that looks like in practice**

Measured on a project with 57 installed plugins, macOS/APFS, cordova 13.0.0:

- the glob order is **not** the sorted order overall
- but the five plugins that mattered came back sorted anyway: `cordova-plugin-firebasex-analytics`, `...-core`, `...-crashlytics`, `...-messaging`, `...-performance`

That combination is the awkward part. `cordova-plugin-firebasex-core`'s `after_prepare` **copies** `GoogleService-Info.plist` from the project root over the platform copy, and its sibling modules write configuration keys into that same file from their own `after_prepare` hooks. On this machine `...-analytics` ran before `...-core`, so all six keys it wrote were reported as written and the file ended up with none of them, while `...-crashlytics` and `...-performance` — landing after `core` — kept theirs. On a filesystem that returns those directories in a different order the same project would behave differently, and the plugin author's `after_prepare` would appear to work.

So the plugin bug is the plugin's to fix (it moved to `before_compile`), but the reason it was a coin flip rather than a decision is here.

**Why this looks like an oversight rather than a design choice**

Installation order was made deterministic in #933, from `package.json` as the source of truth:

```js
// If package.json includes the plugins, we use that for proper sort order
const pkgJson = readPackageJsonIfExists(projectRoot);
if (pkgJson?.cordova?.plugins) {
const pkgPluginIDs = Object.keys(pkgJson.cordova.plugins);
plugins = plugins.sort((a, b) => pkgPluginIDs.indexOf(a) - pkgPluginIDs.indexOf(b));
}
```

Hook enumeration was not brought along, so the two now disagree: plugins are installed in a defined order and their hooks run in whatever order the filesystem hands back.

**What I would expect**

Either of these would remove the coin flip, and the first keeps the two paths consistent:

1. `getAllPluginsHookScriptFiles` orders plugins the same way `platform/addHelper.js` does — `package.json`'s `cordova.plugins` first, falling back to a plain sort when it is absent.
2. Failing that, document the order as undefined, so plugin authors know that a hook which depends on another plugin's hook needs a phase that cannot race (`before_compile` after `after_prepare`, for instance) rather than an ordering assumption.

Happy to open a PR for option 1 if that is the direction you would take.

**Environment**

- cordova 13.0.0, cordova-lib 13.0.0, cordova-common as bundled
- macOS, APFS
- reproduced with real plugins rather than a fixture; the ordering itself is visible from any project with two plugins whose hooks touch one file

Contributor guide

Open the contributing guide

Research direction

Start in src/hooks/scriptsFinder.js at getAllPluginsHookScriptFiles, then compare its plugin discovery with platform/addHelper.js and the package.json ordering logic described in the issue. Confirm the project's chosen behavior for absent package metadata and verify that hook enumeration is deterministic or explicitly documented as undefined.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.