mattcg / cjsdelivery
Deliver CommonJS-syntax JavaScript modules to clients as a single file.
This package's canonical repository appears to be gone and the package has been frozen as a result.
Installs: 4 519
Dependents: 0
Suggesters: 0
Security: 0
Stars: 7
Watchers: 3
Forks: 1
Open Issues: 3
Requires
- php: >=5.4.0
- aura/signal: 1.0.*
This package is not auto-updated.
Last update: 2023-06-10 07:32:16 UTC
README
A CommonJS compiler written in PHP
cjsDelivery allows you to deliver CommonJS-syntax JavaScript modules to clients as a single file. Any modules you add will have dependencies resolved statically. This typically means you only have to point cjsDelivery to your entry module and all dependencies will be magically resolved.
The output is designed to have as little overhead over your module code as possible. In all, only 13 short lines of code will be added by the compiler.
Installation
Install globally by running this one-line command in your bash terminal:
bash <(curl -s https://raw.github.com/mattcg/cjsdelivery/go/install)
Per-project install using composer
Get composer and install cjsDelivery to your project by adding it as a requirement to composer.json
.
cd myproject/
touch composer.json
composer require mattcg/cjsdelivery:0.4.2
As cjsDelivery is PSR-0 compatible, composer will automatically generate vendor/autoload.php
, which you can require
in your code to have the cjsDelivery classes autoloaded when they're needed.
Usage
On the command-line
The bin/delivery
executable is provided for command-line use. Run the following example to compiled the bundled example fruit
application:
delivery --main_module='./examples/fruit/modules/main'
For the full list of options, run delivery -h
.
From PHP
Instances can be created using the provided factory class.
use MattCG\cjsDelivery as cjsDelivery; require '/path/to/cjsDelivery.php'; $includes = array('../mycompany/javascript', '../othercompany/modules'); $delivery = cjsDelivery\Delivery::create(array('includes' => $includes)); $delivery->addModule('./path/to/module'); echo $delivery->getOutput();
The factory method accepts a single parameter, which is a hashmap of options:
minifyIdentifiers
(boolean, defaultfalse
) to turn on identifier minificationsendSignals
(boolean, defaultfalse
) to force the signal manager to be onglobals
(array) to add global modulesincludes
(array) to add include pathsparsePragmas
(boolean, defaultfalse
) to enable pragma parsingpragmaFormat
(string) to specify the pragma formatpragmas
(array) to specify enabled pragmas
Symfony
Use cjsDeliveryBundle instead.
Features
Include paths
If you have many dependencies in folders external to your project, then it's worth setting an include path to avoid having long, absolute paths in your require statements.
If your company's standard modules are in /projects/mycompany/javascript
and your project is in /projects/myproject
, then you can require a standard module using require('standardmodule')
instead of require('/projects/mycompany/javascript/standardmodule')
by adding the include path /projects/mycompany/javascript
.
cd /projects/myproject delivery --main_module='./main' --include='../mycompany/javascript:../othercompany/modules'
Multiple paths can be specified in a colon-separated list.
In PHP, include directory paths can be passed to the factory method in the options hashmap by setting the value of the includes
key to an array of paths.
$includes = array('../mycompany/javascript', '../othercompany/modules'); $delivery = cjsDelivery\Delivery::create(array('includes' => $includes)); $mainmodule = './main'; $delivery->addModule($mainmodule); $delivery->setMainModule($mainmodule);
For external components
Suppose that as part of your project build process, you use bower to install external components to a components/
directory in your project:
cd myproject/lib/javascript
bower install
You could then add myproject/lib/javascript/components
to your cjsDelivery include path.
For internal components
An include path can be useful even with internal dependencies. Suppose your project has the following directory structure:
- myproject
|- moduleA
|-|- version1
|-|- version2
|- moduleB
|-|- version1
If you want to avoid having to type require('../../moduleB/version1')
from within moduleA/version1/index.js
then you could set myproject
to be an include path. Then you would type require('moduleB/version1')
.
Pragmas
Use pragmas to include or exclude pieces of code from the final output.
When passed to the delivery
executable, the -p
option will turn on the manager and any code contained between undefined pragmas will be 'compiled out'.
The bundled example module in examples/fruit/modules/main.js
includes the following lines:
// ifdef BANANA log.print(require('banana').message); // endif BANANA
Run the following example command to compile the fruit
application without the banana
module:
delivery --main_module='./examples/fruit/modules/main' -p
Now try the opposite:
delivery --main_module='./examples/fruit/modules/main' -p='BANANA'
In PHP, instantiate a PragmaManager
and use it to turn pragmas on. By default, all pragmas are off unless explicitly set using setPragma
or setPragmas
, but changes can be undone using unsetPragma
.
$delivery = cjsDelivery\Delivery::create(array('sendSignals' => true)); $pragmamanager = new PragmaManager($delivery->getSignalManager(), $delivery->getDependencyResolver()); $pragmamanager->setPragma('BANANA'); $mainmodule = './examples/fruit/modules/main'; $delivery->addModule($mainmodule); $delivery->setMainModule($mainmodule);
Signals
The PragmaManager
uses signals sent by an Arua.Signal signal manager to process code from added modules. Using pragmas will enable the signal manager even if sendSignals
is set to false
in the options hashmap.
Minified identifiers
By default, cjsDelivery will flatten the module tree internally, rewriting path/to/module
as module
, for example. In a production environment it makes sense to use non-mnemonic identifiers to save space. If enabled, cjsDelivery will rewrite path/to/module
as A
, path/to/othermodule
as B
and so on.
Try this example:
delivery --main_module='./examples/fruit/modules/main' --minify_identifiers
In PHP, set minifyIdentifiers
to true
when instantiating using the factory class.
$delivery = cjsDelivery\Delivery::create(array('minifyIdentifiers' => true)); $mainmodule = './examples/fruit/modules/main'; $delivery->addModule($mainmodule); $delivery->setMainModule($mainmodule);
Globals
You might have a globals.js
or utilities.js
file (or both!) as part of your project, each containing variables or helper functions that you want to have available across all modules. To save you having to require
these in your other modules, you can compile them in as globals.
delivery --main_module='./examples/globals/main' -g 'examples/globals/utilities' -g 'examples/globals/globals'
Global files have require
within their scope and are parsed for dependencies.
In PHP, global file paths can be passed to the factory method in the options hashmap by setting the value of the globals
key to an array of paths.
$globals = array('examples/globals/utilities', 'examples/globals/globals'); $delivery = cjsDelivery\Delivery::create(array('globals' => $globals)); $mainmodule = './examples/globals/main'; $delivery->addModule($mainmodule); $delivery->setMainModule($mainmodule);
How dependencies are resolved
Code is always parsed statically, meaning statements like require(pathVariable + '/mymodule')
will not be handled. You should use only a string literal as the argument to require
.
The .js
or .json
extensions may not be added to module paths in require statements. Doing so will result in an E_USER_NOTICE
level error being triggered, although the error is not fatal and operation will continue.
The following algorithm is used when resolving the given path to a dependency:
- if
path
does not start with.
or/
- for each include path, append
path
and go to 2.
- for each include path, append
- if a file is at
path
- add the file at
path
to the list of dependencies
- add the file at
- if a directory is at
path
- check for for the file
index.js
in directorypath
and if positive, appendindex.js
to path and go to 2. - check
package.json
in path and if themain
property exists setpath
to its value and go to 2. - check for a file with the same as the directory and if positive, append to
path
and go to 2. - check whether the directory only contains one file and if positive, append to
path
and go to 2.
- check for for the file
- throw an exception
Changelog
Please see the closed milestones.
Credits and license
cjsDelivery is copyright © 2012 Matthew Caruana Galizia, licensed under an MIT license.
CommonJS is copyright © 2009 - Kevin Dangoor and many CommonJS contributors, licensed under an MIT license.