Skip to content

Commit

Permalink
HMR condition argument and widget player fix (#4794)
Browse files Browse the repository at this point in the history
  • Loading branch information
myovchev authored Nov 7, 2024
1 parent 6b7c1dc commit 46dea7d
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 16 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
### Fixes

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

### Adds

* 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.

## 4.9.0 (2024-10-31)

### Adds
Expand Down
24 changes: 16 additions & 8 deletions modules/@apostrophecms/template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ module.exports = {
// apos.template.prepend({
// component: 'module-name:async-component-name',
// where: 'head',
// when: 'hmr, // or e.g. ['hmr', 'dev'], logical AND
// when: 'hmr', // or e.g. ['hmr', 'dev'], logical AND
// bundler: 'vite',
// });
// OR
Expand Down Expand Up @@ -909,7 +909,7 @@ module.exports = {
// apos.template.append({
// component: 'module-name:async-component-name',
// where: 'head',
// when: 'hmr, // or e.g. ['hmr', 'dev'], logical AND
// when: 'hmr', // or e.g. ['hmr', 'dev'], logical AND
// bundler: 'vite',
// });
// OR
Expand Down Expand Up @@ -938,6 +938,8 @@ module.exports = {
// - `when`: (optional) string or array of strings, the conditions to be met to insert the component.
// When an array, a logical AND is applied. One match against the injected `when` data is required.
// Currently supported values are `hmr`, `dev`, `prod`. See `getInjectConditionHandlers()` for more info.
// The `when` value can include an argument separated by `:`. E.g. `hmr:apos`, `hmr:public`. If the condition
// handler does not support arguments, it's ignored.
// - `bundler`: (optional) string, the alias of the currently registered asset external build module.
// The bundler condition is not parth of the actual inject data. It's evaluated just on the registration
// data.
Expand Down Expand Up @@ -975,7 +977,7 @@ module.exports = {
conditions.when = conditions.when ? [ conditions.when ] : [];
}
// Both sides `when` should match
if (data.when && !conditions.when.includes(data.when)) {
if (data.when && !conditions.when.map(s => s.split(':')[0]).includes(data.when)) {
return;
}
if (!data.when && conditions.when.length) {
Expand All @@ -990,11 +992,12 @@ module.exports = {
// `when` being an object same as the schema `if`, supporting
// the same logical operators. But it's too much for now.
const conditionMet = when.every(val => {
if (!handlers[val]) {
const [ fn, arg ] = val.split(':');
if (!handlers[fn]) {
self.apos.util.error(`Invalid inject condition: ${when}`);
return false;
}
return handlers[when](data);
return handlers[fn](arg, data);
});

if (bundler) {
Expand All @@ -1020,11 +1023,16 @@ module.exports = {
// Simple conditions handling for `when` injects. It can be extended to support
// custom conditions in the future - registered by modules similar to
// `helpers`.
// Every condition function receives the nunjucks `data` (`when`, `where`, etc)
// object as an argument.
// Every condition function receives an argument if available and the nunjucks
// data object. For example `when: hmr:apos` will call `hmr('apos', data)`.
// The function should return a boolean.
getInjectConditionHandlers() {
return {
hmr() {
hmr(kind) {
if (kind) {
return self.apos.asset.hasHMR() &&
self.apos.asset.getBuildOptions().devServer === kind;
}
return self.apos.asset.hasHMR();
},
dev() {
Expand Down
29 changes: 21 additions & 8 deletions modules/@apostrophecms/util/ui/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,20 @@ export default () => {
// THAT ONE WIDGET and NO OTHER. Don't worry about finding the
// others, we will do that for you and we guarantee only one call per widget.

apos.util.widgetPlayers = {};
const widgetPlayersConfig = {
list: {},
initialized: false
};
apos.util.widgetPlayers = new Proxy(widgetPlayersConfig.list, {
set(target, prop, value) {
target[prop] = value;
// run the player if we missed the initial run
if (widgetPlayersConfig.initialized) {
apos.util.runPlayers();
}
return true;
}
});

// Run the given function whenever the DOM has new changes that
// may require attention. The passed function will be
Expand Down Expand Up @@ -183,25 +196,24 @@ export default () => {
// Your player is guaranteed to run only once per widget. Hint:
// DON'T try to find all the widgets. DO just enhance `el`.
// This is a computer science principle known as "separation of concerns."

apos.util.runPlayers = function(el) {
apos.util.runPlayers = function (el) {
const players = apos.util.widgetPlayers;
const playerList = Object.keys(players);

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

playerEls.forEach(function (el) {
if (el.aposWidgetPlayed) {
playerEls.forEach(function (playerEl) {
if (playerEl.aposWidgetPlayed) {
return;
}
// Use an actual property, not a DOM attribute or
// "data" prefix property, to avoid the problem of
// elements cloned from innerHTML appearing to have
// been played too
el.aposWidgetPlayed = true;
playerOpts.player(el);
playerEl.aposWidgetPlayed = true;
playerOpts.player(playerEl);
});
}
};
Expand All @@ -210,7 +222,8 @@ export default () => {
// when the page is partially refreshed by the editor.

if (!apos.bus) {
apos.util.onReadyAndRefresh(function() {
apos.util.onReady(function () {
widgetPlayersConfig.initialized = true;
apos.util.runPlayers();
});
}
Expand Down

0 comments on commit 46dea7d

Please sign in to comment.