awonderphp / notreallypsrresourcemanager
A Proposal for a web application JS/CSS resouce manager
Requires
- php: ~7.1.0 || ~7.2.0
Requires (Dev)
- squizlabs/php_codesniffer: 3.*
- vimeo/psalm: ^0
This package is not auto-updated.
Last update: 2024-11-27 06:40:55 UTC
README
This is a set of interfaces that PHP libraries can use to provide sane management of third party JavaScript and CSS resources uses by the web applications.
The current namespace \AWonderPHP\NotReallyPsrResourceManager
sucks and will
change. It was never intended as permanent. I was hoping a standards body would
want to take this idea and create some standard interfaces with fancy lingo
that includes RFC 2119.
While not strictly required, it is highly recommended that classes that
implement these interfaces extend the abstract classes within the
\AwonderPHP\FileResource
namespace.
That allows the resulting objects to be served by any class that understands
how to serve a FileResource
object.
It is also intended that the JavaScriptResource and CssResource objects be generated from JSON configuration files as described in this document.
FileResource Methods
JavaScriptResource Interface Methods
CssResource Interface Methods
ResourceManager Interface
JSON Configuration File
JavaScript JSON
CSS JSON
File System and Config File Naming
Wrapper Script
FileResource Methods
These methods are specified in both the JavaScriptResource
and CssResource
interfaces and are identical to the methods of the same name in the abstract
\AwonderPHP\FileResource\FileResource
class:
-
public function getMimeType()
Returns the$mime
property. -
public function getChecksum()
Returns the$checksum
property. -
public function getCrossOrigin()
Returns the$crossorigin
property. -
public function getFilePath()
Returns the$filepath
property. -
public function validateFile()
If the$checksum
property is set and the$filepath
property is set and the file exists, returnstrue
if the file matches the checksum andfalse
if it does not. -
public function getSrcAttribute($prefix = null)
Builds the contents of thesrc
orhref
attribute needed to embed the resource in a web page. Note that this will returnnull
if the$urlscheme
property ishttp
and the file does not have a$checksum
property that uses an algorithm in the$validIntegrityAlgo
property. The optional parameter$prefix
is a file system path to put in front of the$urlpath
property, useful for web applications using a wrapper to serve the file. -
public function getIntegrityAttribute()
Builds the contents of anintegrity
attribute, if the$checksum
property uses a suitable algorithm. -
public function getTimestamp()
If the$lastmode
property is not null, returns a UNIX time stamp (seconds from UNIX epoch).
JavaScriptResource Interface Methods
These methods are in the JavaScriptResource interface but are not defined in
the previously mentioned FileResource
abstract class.
-
getTypeAttribute()
What goes into thetype
attribute of a<script>
node. Usually the MIME type but not always. -
getAsyncAttribute()
Whether or not the Booleanasync
attribute should be present. -
getDeferAttribute();
Whether or not the Booleandefer
attribute should be present. -
getNoModuleAttribute()
Whether or not the Booleannomodule
attribute should be present. -
generateScriptDomNode($dom, $nonce = null)
Creates a\DOMNode
<script>
node, with an optional nonce. -
generateScriptString(bool $xml = false, $nonce = null)
Creates a string, either HTML or XHTML, for the script node with an optional nonce. If the$xml
parameter istrue
, a string that is XML compliant should be returned (every attribute is akey="value"
pair, Boolean attributes are usually justkey="key"
but it does not really matter. Script node is self-closing). When the$xml
parameters isfalse
, the default, an HTML compliant string is generated (boolean attributes may just bekey
and are not required to have an="value"
and a self-closing script tags are not recognized as closed, so a closing</script>
is required).
Both the generateScriptDomNode()
and generateScriptString()
methods should
call the getSrcAttribute()
method, so the constructor of an implementing
class should have a property for the $prefix
that is null
by default but
can be set by the constructor.
CssResource Interface Methods
-
getTypeAttribute()
What goes into thetype
attribute of a CSS<link>
node. This should ALWAYS returntext/css
-
getMediaAttribute()
Returns what goes into themedia
attribute of a CSS<link>
node. This is rarely used, but it is very powerful and should be used more often IMHO as it can reduce the bandwidth the client needs to have to successfully use a web application. -
getHreflangAttribute()
Returns what goes into ahreflang
attribute. When not null, it MUST be a BCP47 string. -
getReferrerPolicyAttribute()
Returns what goes into areferrerpolicy
attribute of a CSS<link>
node. I suspect it will not be used much, but it is there. -
getRelAttribute()
The contents of therel
attribute, should returnstylesheet
.
ResourceManager Interface
This is the interface that defines how web applications will interact get the
JavaScriptResource
and CssResource
objects that they need.
It describes two public methods:
-
getJavaScript(string $vendor, string $product, string $name, $version, $variant = null);
-
getCSS(string $vendor, string $product, string $name, $version, $variant = null);
The web application calls those methods which will either return null
if the
implementing class can not create the object, or it returns eith a
JavaScriptResource
or CssResource
implementing object, depending upon which
of the methods were called.
The Parameters:
-
$vendor
String:
Lower case vendor string for who packaged the JavaScript or CSS, similar to the first level namespace in PSR-4 PHP classes but lower case. In Composer terms, it would be the top level directory within the Composer createdvendor
directory of your web application. -
$product
String:
Lower case product string for the package the JavaScript or CSS is part of, similar to the second level namespace in PSR-4 PHP classes but lower case. In Composer terms, it would be the directory within the previously mentioned directory. -
$name
String:
The name of the JavaScript or CSS sans version and other info, e.g.jquery
orjquery-ui
ornormalize
. -
$version
String or Integer:
The version needed, e.g.3.3.1
to specifically ask for jQuery 3.3.1 or3.3
to specifically ask for latest in3.3
branch or simply3
to ask for the latest in 3 branch. -
$variant
String or Null:
The variant of the JavaScript needed, e.g.min
for minified orslim
orslim.min
.
With that information, the ResourceManager
implementing class would be able
to find the JSON file describing the object and load it into an object.
The constructor for an implementing class should define the Base
directory
directory resources are installed into so the methods can find the needed
configuration files and also the $prefix
to use with the getSrcAttribute()
method.
Example Usage:
$base = "/whatever/path";
$RM = new \namespace\whatever\ImplementingClass($base);
$jsObj = $RM->getJavaScript('flossjs', 'jquery', 'jquery', 3, "min");
Then from $jsObj
the web application can create the <script>
node needed.
JSON Configuration File
The ResourceManager will hunt for a JSON configuration file that matches the resource the web application requests and then create the object to return from the JSON file. That needs a standard JSON file format.
Common JSON Elements to JavaScript and CSS
name
String, required:
The name of the script or css, sans version and variant, e.g.jquery
.homepage
String, not strictly required:
The URL homepage of the projectversion
String, required:
The version of the script being described.license
Array, required:
An array containing one or more applicable license for the script. Each element of the array should contain license name and a URL for the license.
Those fields are not utilized by the classes but are metadata that is useful to a system administrator. Other fields common to both JS and CSS:
mime
String, required:
The MIME type that should be used when serving the file.checksum
String, recommended:
Thealgo:checksum
described in theFileResource
abstract class.filepath
String, optional:
If the file is present on the server, the file system path to the file.lastmod
String, recommended:
A string that can be parsed bystrtotime()
to create a UNIX time stamp indicating when the file was last modified. For many projects, this is specified in a comment header of the file itself, and in those cases, that string should be used.srcurl
String, required:
What should go in thesrc
orhref
attribute. Must be parseable by theparse_url
function and internationalized domains should be in punycode.minified
Boolean, optional:
Use of this field may be used by some implementations but is not required. It defines whether the JS/CSS in the file is minified.
JavaScript JSON
A sample of what a JavaScript JSON might look like:
{
"name": "jquery",
"homepage": "https://jquery.com/",
"version": "3.3.1",
"license": [
{
"name": "MIT",
"url": "https://jquery.org/license/"
}
],
"mime": "application/javascript",
"checksum": "sha256:160a426ff2894252cd7cebbdd6d6b7da8fcd319c65b70468f10b6690c45d02ef",
"filepath": "flossjs/jquery/js/jquery-3.3.1.min.js",
"lastmod": "2018-01-20T17:24Z",
"minified": true,
"srcurl": "/js/jquery-3.3.1.min.js"
}
JavaScript Specific Fields:
async
Boolean, optional:
Only needed if it is desired to have that attribute, then set totrue
.defer
Boolean, optional:
Only needed if it is desired to have that attribute, then set totrue
.nomodule
Boolean, optional:
Only needed if it is desired to have that attribute, then set totrue
.- ??
type
?? Needs Exploration:
In most cases, thetype
attribute is set to the MIME type, but it may be necessary to set it tomodular
for ES6 modular feature, I still need to learn about that.
CSS JSON
A sample of what a CSS JSON might look like needs to be written.
CSS Specific Fields:
media
Array, optional:
An array containing the media tyes the CSS file applies to when it does not apply to everyone (browsers assumeall
when not specified)hreflang
String, optional:
The BCP47 language string that applies to the CSS file.referrerpolicy
String, optional:
When present, must be one ofno-referrer
,no-referrer-when-downgrade
,origin
,origin-when-cross-origin
,unsafe-url
-- browsers assumeno-referrer-when-downgrade
which is almost always the best policy for CSS style sheets. It is my opinion thatunsafe-url
should never be used as it can leak information. It only has meaning when the remote server does not use TLS but your web application uses TLS and that scenario should be blocked by browsers anyway.
File System and Config File Naming
All scripts should be installed with a hierarchy of
$base/VendorName/ProductName
where VendorName
and ProductName
are lower
case, as is Composer convention for PHP libraries.
In the case of Composer install of JS/CSS libraries, the Composer vendor
directory would be the $base
directory.
Within the ProductName
directory, an etc
directory MUST exist that has
the JSON configuration files, and it is RECOMMENDED that the actual
JavaScript files reside in a js
directory and CSS files reside in a css
directory.
An example of what this would look like is at AliceWonderMiscreations/CommonJS
Default configuration files would be named using:
ScriptName-Version-Variant.json.dist
Where ScriptName is the name of the script (e.g. jquery
), Version is the
version of the script (e.g. 3.3.1
), and if present, Variant would be the
script variant (e.g. min
or slim
or slim.min
).
The default configuration should have the srcurl
point to a local URL, e.g.
"srcurl": "/js/jquery-3.3.1.min.js",
When a system administrator wants to customize what is in the configuration,
they simply copy the file so that it no longer ends in .dist
and then they
can modify it (e.g. to set srcurl
to a CDN).
The ResourceManager MUST give priority to the configuration file without
the .dist
if it is found.
With the major.minor.point
versioning scheme, a configuration file should
exist for both major.minor
and major
that are identical to the default
configuration file for the most recent major.minor.point
that match.
Wrapper Script
Web Applications that implement this MUST be able to handle requests to the
default /js/
and /css/
locations.
This can be accomplished by a wrapper script. An abstract class that extends
the FileWrapper class
to work for this has been written, that abstract class is part of the
AWonderPHP\FileResource
namespace.
An interface exists in this namespace that can be used to define a class that
extends the class that serves FileResource
objects described above.
EOF