This document describes a convention for a file-system structure and URL scheme to support the distribution and delivery of static front-end assets, such as Javascript and CSS files, as components of a vendored (e.g. Composer) package.
Static assets are a fundamental component of web-applications. Such assets are commonly a dependency of controllers, middleware, front-controllers, and other server-side components, and therefore should have a consistent file-system structure. Such assets are also commonly a dependency of other client-side components, and therefore also need to have a predictable, consistent URL scheme.
The scheme defined by this specification aims to be simple enough that it can be supported, with minimal effort, either with or without a framework, under any server daemon, including Apache, NGINX, and the simple HTTP-server that is built into the CLI version of PHP.
The creation of static assets from from other resources (such as SASS, LESS, TypeScript or ES6 scripts being transpiled to ES5, etc.) is beyond the scope of this specification, which deals strictly with the delivery, not the creation, of static assets.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
In the examples below, for the sake of discussion, we will assume a typical Composer project structure as follows:
composer.json
webroot/
index.php
vendor/
a/
b/
In this typical structure, vendor packages are installed (per Composer defaults) into a
vendor
folder in the root of the project, with packages such as b
grouped into parent
folders by vendor names such as a
.
As is typical of most projects, a folder has been named and designated as webroot
, from
which the index.php
script, by means of server configuration, has been routed as the
front-controller; e.g. a script that gets dispatched for any requested URL for which the
path could not be mapped directly to a file in the webroot
folder.
Components following this specification MUST NOT make any assumptions about the name or location of a public, web-accessible web-root folder, only that a designated web-root folder exists.
Likewise, components MUST NOT make any assumptions about the structure of a vendor-folder or about the package installation paths - only that, for any given vendor and package name pair, a designated package installation folder exists.
A package a/b
, which provides one or more static assets, MUST confine all of these
assets to a single folder, assets
, at the root of the package.
For example:
composer.json
assets/
css/
main.css
js/
main.js
A package MAY organize it's assets into any hierarchy of subfolders, grouped as found necessary or appropriate by the package vendor.
A package such as this, when installed by a project using the default Composer settings, might result in a directory structure such as:
composer.json
webroot/
index.php
vendor/
a/
b/
assets/
css/
main.css
js/
main.js
Again, this is an example only - in practice, the package installation paths may vary, depending on, for example, Composer installers or other installation scripts.
A project that contains a designated web-root folder SHOULD NOT contain a sub-folder
named assets
, UNLESS such a folder is used exclusively for symbolic links to
vendor-supplied assets
folders, e.g. created by an installation script, and if so,
MUST use a physical directory structure matching the URL Scheme described below.
A project that delivers vendor-supplied assets in response to HTTP requests MUST reserve
the URL path prefix /assets/{vendor}/{package}/
exclusively for the delivery of static
assets of any given package
provided by any given vendor
.
Delivery of assets for an installed package a/b
, per the example above, would therefore
effectively result in the following valid URL paths:
/assets/a/b/js/main.js
/assets/a/b/css/main.css
This specification does not stipulate how this is implemented. Examples include: proprietary web-server configuration files, e.g. Apache, NGINX, or other web-server software, front controllers, middleware, symbolic links created by installation scripts, or any other means.
A component responsible for the delivery of vendor-supplied assets:
-
MUST respond with the correct MIME-type for all common asset file-types according to media-types defined by IANA.
-
MUST respond with a 3xx success status code for any applicable
GET
orHEAD
request, such as302 Found
or304 Not Modified
, as appropriate. -
MUST respond with a
405 Method Not Allowed
status code for requests with an applicable path and any HTTP method other thanGET
orHEAD
.
A component responsible for the delivery of vendor-supplied assets SHOULD respond with the
appropriate cache-headers, such as ETag
or Last-Modified
, e.g. in accordance with
RFC2616 section 13.
A: Because it's simpler. A map would require more than a standard - it would require at least a configuration file format specification, and/or at least interfaces, possibly even an implementation and/or directions detailed enough that they would basically be pseudo-code.
From using a similar approach at work for a while, we learned that that being able to symlink vendored asset folders into the project's public asset folder is really useful, for a couple of reasons:
-
It enables you to run an installation script once, and the continue to add more files to the vendor packages, since every file in the symlinked folder becomes automatically available.
-
A map cannot be interpreted or resolved at design-time, by the browser, or by an IDE (things like source-maps of relative paths fall apart, since the relative public URLs do not map directly to physical files - having to run a build/deploy/install script after every change is cumbersome.)
-
The length or appearance of asset URLs is typically completely irrelevant - about as irrelevant as the physical file-system structure is to Composer packages. For the most part, no person will ever see the URL of your CSS or JS files - shorter or neater URLs have no practical value. Having a simple, predictable URL structure that prevents collissions, has great value.
A: Create of static assets is beyond the scope of this specification, which deals solely with the delivery of static assets.
Your (SASS, LESS, CoffeeScript, etc.) source files assets aren't "static assets" in the context of this specification - they require tools for processing, compilation, minification, and so on, which, in the context of this specification, makes them "dynamic assets".
Build tools, compilers and other complex pipelines (such as Grunt, WebPack, etc.) deal with the creation of static assets - the subject of this specification is limited to the delivery of static assets created with or without such tools.
A: This specification deals only with the delivery of public, static assets.
Locating other server-side resources, such as templates or configuration-files, is an entirely different problem - even for resources with the same file-type, such as images, some images (such as CSS dependencies) may be public and static, while others (such as photos being resized on-the-fly) may be private resources requiring some form of server-side processing; the latter is outside the scope of this specification.
The directory structure reminds me of the Solar packaging scheme. See A.6.4. at the end: http://solarphp.com/manual/appendix-standards.system