Skip to content

Commit 46dea7d

Browse files
authored
HMR condition argument and widget player fix (#4794)
1 parent 6b7c1dc commit 46dea7d

File tree

3 files changed

+42
-16
lines changed

3 files changed

+42
-16
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
### Fixes
66

77
* Extra bundle detection when using external build module works properly now.
8+
* Widget players are now properly invoked when they arrive later in the page load process.
89
* Fix permission grid tooltip display.
910

11+
### Adds
12+
13+
* It's possible now to target the HMR build when registering via `template.append` and `template.prepend`. Use `when: 'hmr:public'` or `when: 'hmr:apos'` that will be evaluated against the current asset `options.hmr` configuration.
14+
1015
## 4.9.0 (2024-10-31)
1116

1217
### Adds

modules/@apostrophecms/template/index.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ module.exports = {
864864
// apos.template.prepend({
865865
// component: 'module-name:async-component-name',
866866
// where: 'head',
867-
// when: 'hmr, // or e.g. ['hmr', 'dev'], logical AND
867+
// when: 'hmr', // or e.g. ['hmr', 'dev'], logical AND
868868
// bundler: 'vite',
869869
// });
870870
// OR
@@ -909,7 +909,7 @@ module.exports = {
909909
// apos.template.append({
910910
// component: 'module-name:async-component-name',
911911
// where: 'head',
912-
// when: 'hmr, // or e.g. ['hmr', 'dev'], logical AND
912+
// when: 'hmr', // or e.g. ['hmr', 'dev'], logical AND
913913
// bundler: 'vite',
914914
// });
915915
// OR
@@ -938,6 +938,8 @@ module.exports = {
938938
// - `when`: (optional) string or array of strings, the conditions to be met to insert the component.
939939
// When an array, a logical AND is applied. One match against the injected `when` data is required.
940940
// Currently supported values are `hmr`, `dev`, `prod`. See `getInjectConditionHandlers()` for more info.
941+
// The `when` value can include an argument separated by `:`. E.g. `hmr:apos`, `hmr:public`. If the condition
942+
// handler does not support arguments, it's ignored.
941943
// - `bundler`: (optional) string, the alias of the currently registered asset external build module.
942944
// The bundler condition is not parth of the actual inject data. It's evaluated just on the registration
943945
// data.
@@ -975,7 +977,7 @@ module.exports = {
975977
conditions.when = conditions.when ? [ conditions.when ] : [];
976978
}
977979
// Both sides `when` should match
978-
if (data.when && !conditions.when.includes(data.when)) {
980+
if (data.when && !conditions.when.map(s => s.split(':')[0]).includes(data.when)) {
979981
return;
980982
}
981983
if (!data.when && conditions.when.length) {
@@ -990,11 +992,12 @@ module.exports = {
990992
// `when` being an object same as the schema `if`, supporting
991993
// the same logical operators. But it's too much for now.
992994
const conditionMet = when.every(val => {
993-
if (!handlers[val]) {
995+
const [ fn, arg ] = val.split(':');
996+
if (!handlers[fn]) {
994997
self.apos.util.error(`Invalid inject condition: ${when}`);
995998
return false;
996999
}
997-
return handlers[when](data);
1000+
return handlers[fn](arg, data);
9981001
});
9991002

10001003
if (bundler) {
@@ -1020,11 +1023,16 @@ module.exports = {
10201023
// Simple conditions handling for `when` injects. It can be extended to support
10211024
// custom conditions in the future - registered by modules similar to
10221025
// `helpers`.
1023-
// Every condition function receives the nunjucks `data` (`when`, `where`, etc)
1024-
// object as an argument.
1026+
// Every condition function receives an argument if available and the nunjucks
1027+
// data object. For example `when: hmr:apos` will call `hmr('apos', data)`.
1028+
// The function should return a boolean.
10251029
getInjectConditionHandlers() {
10261030
return {
1027-
hmr() {
1031+
hmr(kind) {
1032+
if (kind) {
1033+
return self.apos.asset.hasHMR() &&
1034+
self.apos.asset.getBuildOptions().devServer === kind;
1035+
}
10281036
return self.apos.asset.hasHMR();
10291037
},
10301038
dev() {

modules/@apostrophecms/util/ui/src/util.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,20 @@ export default () => {
128128
// THAT ONE WIDGET and NO OTHER. Don't worry about finding the
129129
// others, we will do that for you and we guarantee only one call per widget.
130130

131-
apos.util.widgetPlayers = {};
131+
const widgetPlayersConfig = {
132+
list: {},
133+
initialized: false
134+
};
135+
apos.util.widgetPlayers = new Proxy(widgetPlayersConfig.list, {
136+
set(target, prop, value) {
137+
target[prop] = value;
138+
// run the player if we missed the initial run
139+
if (widgetPlayersConfig.initialized) {
140+
apos.util.runPlayers();
141+
}
142+
return true;
143+
}
144+
});
132145

133146
// Run the given function whenever the DOM has new changes that
134147
// may require attention. The passed function will be
@@ -183,25 +196,24 @@ export default () => {
183196
// Your player is guaranteed to run only once per widget. Hint:
184197
// DON'T try to find all the widgets. DO just enhance `el`.
185198
// This is a computer science principle known as "separation of concerns."
186-
187-
apos.util.runPlayers = function(el) {
199+
apos.util.runPlayers = function (el) {
188200
const players = apos.util.widgetPlayers;
189201
const playerList = Object.keys(players);
190202

191203
for (let i = 0; i < playerList.length; i++) {
192204
const playerOpts = players[playerList[i]];
193205
const playerEls = (el || document).querySelectorAll(playerOpts.selector);
194206

195-
playerEls.forEach(function (el) {
196-
if (el.aposWidgetPlayed) {
207+
playerEls.forEach(function (playerEl) {
208+
if (playerEl.aposWidgetPlayed) {
197209
return;
198210
}
199211
// Use an actual property, not a DOM attribute or
200212
// "data" prefix property, to avoid the problem of
201213
// elements cloned from innerHTML appearing to have
202214
// been played too
203-
el.aposWidgetPlayed = true;
204-
playerOpts.player(el);
215+
playerEl.aposWidgetPlayed = true;
216+
playerOpts.player(playerEl);
205217
});
206218
}
207219
};
@@ -210,7 +222,8 @@ export default () => {
210222
// when the page is partially refreshed by the editor.
211223

212224
if (!apos.bus) {
213-
apos.util.onReadyAndRefresh(function() {
225+
apos.util.onReady(function () {
226+
widgetPlayersConfig.initialized = true;
214227
apos.util.runPlayers();
215228
});
216229
}

0 commit comments

Comments
 (0)