? ? Pending

User tests: Successful: Unsuccessful:

avatar Fedik
Fedik
30 Sep 2018

Pull Request for Issue #12402, improved version of #8913 .

Summary of Changes

The patch introduce new class WebAssetRegistry to manage the assets, and it's dependencies.
The assets - > read as CSS/JS library.

How it works

All registry information stored in a registry file, a simple json file called joomla.asset.json.
I made an example for media/vendor/joomla.asset.json, media/system/joomla.asset.json, and for each template atum/joomla.asset.json, cassiopeia/joomla.asset.json.

The Registry file are for:

  • The registry file contain an information about provided assets.
  • Each asset provide dependencies, and js/css files which be attached to the Document on header rendering event.
  • Each asset can be overridden by another registry file (take a look in atum/joomla.asset.json where overridden bootstrap.css, and font-awesome).

To add your registry file:

Factory::getContainer()->get('webasset')
  ->addRegistryFile('media/blabla/path/joomla.asset.json')

How to use, enable/disable assets:

/** @var Joomla\CMS\WebAsset\WebAssetRegistry $wa */
$wa = Factory::getContainer()->get('webasset');

// Enable Core asset
$wa->enableAsset('core');
// If the asset do not exists, then Exception will be thrown

// Disable Bootstrap CSS
$wa->disableAsset('bootstrap.css'); 
// bootstrap.css - is an asset name, not a file name !!!
// look in media/vendor/joomla.asset.json to see why

NOTE: Method enableAsset() / disableAsset() do NOT add anything to the document. It just change the asset state. The files of all active assets will be attached to the Document on before header rendering.

By default WebAssetRegistry use a "lazy loading" of assets.
The registry file parsed only when WebAssetRegistry requested for new asset.
All dependencies will be resolved while attaching WebAssetRegistry to the document. See WebAssetRegistry::attach()

Also I have made an example in behavior.core, bootstrap.framework.

Further changes/ideas

Allow custom class per asset, that can handle stuff like in 'behavior.core':

function onBeforeAtach() {
  $doc->addScriptOptions('system.paths', [
	'root' => Uri::root(true),
	'rootFull' => Uri::root(),
	'base' => Uri::base(true),
  ]);
}

In theory, this allow to clean up JHtml from adding a scripts.

For now feedback are welcome! :neckbeard:

Documentation Changes Required

yes, if it will be accepted

ping @wilsonge @mbabker @dgrammatiko @C-Lodder @laoneo
also everyone else who doing frondend stuff

avatar Fedik Fedik - open - 30 Sep 2018
avatar Fedik Fedik - change - 30 Sep 2018
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 30 Sep 2018
Category Administration Templates (admin) Repository JavaScript Libraries Front End Templates (site)
avatar Fedik Fedik - change - 30 Sep 2018
Labels Added: ? ?
c4d03bc 30 Sep 2018 avatar Fedik phpcs
3b05879 30 Sep 2018 avatar Fedik phpcs
avatar ggppdk
ggppdk - comment - 30 Sep 2018

Looks very nice,

is there some debugging (implemented already) ? or can such debugging be added ?

  • what the following call will register to be added to the document (later by WebAssetRegistry::attach()) ?
$wa->enableAsset('template.atum.' . ($this->direction === 'rtl' ? 'rtl' : 'ltr'));
  • what has already been registered for added by some previous call and by who

i mean without looking and figuring out ourselves dependencies out of the json files
but also to help verify what we put inside the json file is correct

avatar Fedik
Fedik - comment - 30 Sep 2018

is there some debugging (implemented already) ? or can such debugging be added ?

sure, WebAssetRegistry::getActiveAssets(), WebAssetRegistry::getAssetsByState()
and small debuging method I made for temporary WebAssetRegistry::debugAssets()

also can do:

$asset = $WebAssetRegistry->getAsset('blabla');
if ($asset && $asset->isActive())
{
  echo "it alive!!! (:";
}

what has already been registered for added by some previous call and by who

you cannot check "by who", but can check where the asset comes from.
The asset object has assetSource property which holds reference to the registry file,
so can use var_dump($asset) to see from where it come from.

hmm, currently there nothing like WebAssetRegistry::getAllAvailableAssets()

avatar brianteeman
brianteeman - comment - 30 Sep 2018

There appears to be inconsistent use of the minified files

avatar Fedik
Fedik - comment - 30 Sep 2018

There appears to be inconsistent use of the minified files

where the inconsistent?

avatar brianteeman
brianteeman - comment - 30 Sep 2018

in build/build-modules-js/settings.json
I assume they should all be minified - they're not

avatar mbabker
mbabker - comment - 30 Sep 2018

Personally, I'd rather all new events have their own Event subclasses versus everything being dispatched with the generic event class.

public function onWebAssetStateChanged(Event $event): void
{
    $asset = $event->getArgument('asset');
}

versus

public function onWebAssetStateChanged(WebAssetStateChangedEvent $event): void
{
    $asset = $event->getAsset();
}

You get a better self-documenting API versus having to find the triggering source code to see exactly what arguments are available.

avatar dgrammatiko
dgrammatiko - comment - 30 Sep 2018

@Fedik nice to see that you're pushing this idea (I was always counting that you will come up with such a PR, thus I never actually deleted the assets lines in the build tools 😉 ).

There are some consideration that the production team should consider here:

  • Everything in the Javascript world is becoming a module, so I guess there should be a way to manage modules along the old es5 scripts. (small explanation here: if you have a <script type="module" src="blabla.js"> by default this script is deferred and scoped differently than a normal es6 script. This obviously imposes some challenges with jQuery scripts and the order of execution but it's another talk altogether).

  • I would expect J4 to be able to handle critical/lazy-loaded assets, at the end of the day these are the current best practices...

  • If you keep JHtml::script, JHtml::stylesheet, addScript, addStylesheet (also some bright minds are using the addCustomTag to inject css or js), then there will be way too many options to handle assets which obviously will make the dev life more complicated instead of simplifying things. So the question (this goes to the production team) is: are you willing to break the current status quo?

avatar mbabker
mbabker - comment - 1 Oct 2018

The problem is not with require.js or any of that tooling. The problem is you are in an environment where there is an end user facing feature for runtime resolution of assets that enables end users to create overrides. You aren't working in a purely compiled environment, you aren't working in an environment where all the paths are going to be static.

If the JavaScript and browser tooling reach a point where the capabilities that Joomla has can be emulated in a way other than what JHtml does to resolve paths at runtime, that can be considered. Until then, talking down on the project because it doesn't push for a compiled build environment that only "real" developers can use does nothing but make people feel alienated.

avatar dgrammatiko
dgrammatiko - comment - 1 Oct 2018

you aren't working in an environment where all the paths are going to be static

require.js can handle this in the same manner script tags are appended in the html.

talking down on the project because it doesn't push for a compiled build environment

You got me wrong, all I said was that you should try to ease the path for modules (by forcing defer) not actually implement it right now (yes till dynamic imports are supported everywhere there's no point even trying to do it)

avatar Fedik
Fedik - comment - 1 Oct 2018

The problem is you are in an environment where there is an end user facing feature for runtime resolution of assets that enables end users to create overrides.

After some tweaks WebAssetRegistry allow to generate a config for require.js, which can be used as script/module loader.

but all this not in current PR

avatar Fedik
Fedik - comment - 2 Oct 2018

@mbabker Here another example about what is doing enable/disable and add/remove methods:

// Empty asset registry
$wa = new WebAssetRegistry;

// Add some assets
$wa->addAsset(new WebAssetItem("🍻"));
$wa->addAsset(new WebAssetItem("🐘"));

// At this point we have 2 asset in registry, with STATE_INACTIVE
// So nothing will be added to Document
$wa->attachActiveAssetsToDocument($document); // Will do nothing, because all assets is inactive

// Enable asset
$wa->enableAsset("🐘");

// At this ponit we still have 2 assets, but only 1 is Active
$wa->attachActiveAssetsToDocument($document); // Will add files from "🐘" asset to Document

// Try to enable not-existing asset
$wa->enableAsset("🐛"); // Will throw Exception

And use of RegistryFile just doing addAsset() for you, all you need is just enable/disable existing.
Of course you still can do $wa->addAsset(new WebAssetItem("🍪"))->enableAsset("🍪"), if need.

avatar wilsonge wilsonge - change - 14 Oct 2018
Status Pending Fixed in Code Base
Closed_Date 0000-00-00 00:00:00 2018-10-14 21:49:35
Closed_By wilsonge
avatar wilsonge wilsonge - close - 14 Oct 2018
avatar wilsonge wilsonge - merge - 14 Oct 2018
avatar wilsonge
wilsonge - comment - 14 Oct 2018

Let's take this as a first pass. I'm pretty sure there's some improvements to be made here - but I'm happy with this as the base concept

avatar Fedik
Fedik - comment - 15 Oct 2018

oh, that was fast 😄

for note, one issue left:

@mbabker : If I enable an asset with dependencies I expect the dependencies to be enabled as well.

This might be a case of trying to be too lazy. It's fine to defer parsing the JSON files until you actually start adding WebAssetItem entries to the internal store, but once you start populating WebAssetRegistry::$assets with objects it should always contain the full resource tree. It really shouldn't be a partial snapshot.

I think it is pretty important.
I will try to fix it, in one of next pull request.

avatar wilsonge
wilsonge - comment - 19 Mar 2019

I've started working on docs for this feature https://docs.joomla.org/J4.x:Web_Assets Any help is always appreciated!

Add a Comment

Login with GitHub to post a comment