Asset Management v3 [5.3.0-B1]
We've made several attempts to deal with assets (e.g. JS/CSS files) management in past.
First Attempt
Use JS/CSS files as is.
Pros:
no coding needed because all just works
cache invalidation is done by browser itself on JS/CSS file change
Cons:
slows down page load, because JS/CSS files can't be loaded in parallel
Second Attempt (current)
Create ad-hoc file groups via <inp2:m_Compress/> tag.
Pros:
network friendly, because all resources are combined into large files
combined resource files can be minified
combined filename contains CRC of it's contents to auto-invalidate by browser on content change
Cons:
combine resource files are huge
single resource change would invalidate combine file, which needs to be redownloaded from scratch
no way to determine which old combined files needs to be deleted because we only have new combined filename
ad-hoc combined file creation - no way to pre-compile resources at deployment
Solution
Idea:
each module has "
/modules/<module-name>/install/assets.json" fileeach theme has: "
/themes/<theme-name>/_install/assets.json" file (one theme can have several files for each module sub-folder, e.g. "/themes/<theme-name>/in-link/_install/assets.json")example contents of "assets.json" file (all path are relative to theme/module):
{ "example-package.js": { "engine": "yui", "files": [ "assets/js/lib/enquire.js", "assets/js/lib/slick.js" ] }, "example-package.css": { "files": [ "assets/css/style.css" ] } }the asset content can be specified in these forms (all exception "@refrerence" are already supported by "m_Compress" tag):
"
path/to/asset.ext" - asset within module, where "assets.json" is located"
{module_path}/path/to/asset.ext" - asset from each moduleother formats supported by "m_Compress" tag currently
"
@reference" format - asset name, defined in any of "assets.json" files
Plan:
modify "MinifyHelper::CompressScriptTag" method (powers "m_Compress" tag) to have 4 modes (current behavior to always recreate asset in debug mode stays):
"auto" - if asset file is missing, then create it and return it's url (as now, by default)
"require" - if asset file is missing, then throw an exception otherwise immediately return it's url (don't even try to create it)
"force" - always create asset file regardless of the fact, that it might already be present
create "AssetResolver" class that will:
when invoked from Front-End handle assets from all front-end themes; when invoked from admin console handle its assets
collect data from "
assets.json" files
add "AssetResolver::add($asset_name, array $configuration)" method to dynamic asset adding from events below
have "AssetResolver::resolve($asset_name)" method, that will:
call "
adm:OnResolveAssets" event to allow dynamic asset addingiterate through asset configuration and resolve all asset references (in "@reference" format)
cache resolved asset configuration somewhere under /system/cache/assets/ folder (not cached in debug mode & reset when cached assets are reset)
return it
have "AssetResolver::dump($asset_name)" method that would:
call "resolve" method to get asset configuration
call the "
MinifyHelper::CompressScriptTag" with that data + mode=force (see above) to produce actual asset
have "AssetResolver::url($asset_name)" method, that would:
call "resolve" method to get asset configuration
call the "
MinifyHelper::CompressScriptTag" with that data + mode=require (see above) to get url of the asset
have "AssetResolver::dumpAll()" method, that would:
iterate through all registered assets (somehow don't call "adm:OnResolveAssets" event multiple times)
call "dump" method on each of them
create
<inp2:m_Asset name="..."/>tag, that will:be used as alternative to the
<inp2:m_Compress .../>tagcall "AssetResolver::url" method for given asset name
on deploy we'll build all asset caches according to "
assets.json" filesadd the "
asset:compile" command to compile assets manually
P.S.
Assetic can also compile LESS/SASS into CSS and minify JS using YUI compressor or Google Closure Compiler. So we no longer need to setup tricky tasks for PhpStorm or commit compiled CSS anymore.
More ideas to be incorporated into the plan:
instead of real-time asset mapping resolving generate JS file (maybe "/system/Gruntfile.js"), that:
will contain asset mapping
can be executed at any time without working database to rebuild assets
should support asset watching (source JS/CSS file change causes rebuild of connected files)
should support SASS with custom options
should support LESS with custom options
should support optional asset compression/minification
perform above file generation as a standalone step (not on deploy)
by default only combine JS/CSS files together without compression/minification (current Java/PHP-based are very outdated)
add new system setting, that would allow to enable compression/minification and also verify working NodeJS installation to do that
have a "package.json" and "package-lock.json" ready with all needed dependencies for all cases