Customizing Packages
The Problem with Packages
How can you control what files are installed and to where?
Currently, packages use different conventions for what files are included in the package distribution and where files will be installed. For example: some packages distribute CSS files, while others provide Less or Sass stylesheets. Some packages distribute raw source, others provide only minified versions versions of source, and yet others provide minfied source with map files. There is no consistent approach.
However, we need to be able to install a package and customize how it integrates into our application. Currently, we have to manually copy required files out of installed packages. Each time the package is reinstalled or upgraded, this manual process must be repeated. It can be automated by custom Gulp tasks, but there is no uniform solution for all applications.
Pak addresses this problem by allowing each application to override how a package is installed. Pak does this by adding an automated export step to the installation process.
Exporting Pak Contents
When a package is installed, Pak will first store the package contents locally under the paks directory. This is a complete copy of the package distribution from the package repository. This typically includes many more files than you need in your application, but the files are all there, incase you need them.
Next, Pak will selectively export a subset of the package files from the paks directory to the lib. How does Pak select which files to export and where to export to? There are several methods for how you can customize what is exported. These alternatives are examined in the following order:
- Use export override instructions in your application's pak.json file.
- Use export override instructions from a package override file in your ~/.pak/override directory.
- Use export override instructions from the Pak catalog.
- Use export instructions in the package's pak.json or pak.json file.
- Export all the files under the dist directory [default].
Some packages create a dist directory with a subset of common package files. If this subset is exactly the set of files that you want, then the contents of the dist directory will be exported. This is the default if no export instructions are specified.
However, if you want to override how a third party package is installed, you can override the package by adding export instructions for the package in your application's pak.json file, or you can create a package override file in the ~/.pak/override directory or create an override package.
If you are a developer of a package, you can add export instructions to your package's pak.json file to export the most common subset of files.
Export Overrides
When you cannot modify a third-party package, you can create overrides to provide the export instructions. Pak supports overriding exports in your application's pak.json file and also via special override packages. For more details please read Overide Packages in the Developers Guide.
The syntax to override exports in your application's pak.json file is via a override.PACKAGE.export definition, where PACKAGE is the name of the package. For example:
"override": { "jquery": { "export": "dist/jquery.js" } } }
This example overrides the default jquery exporting of the dist directory, and exports just the dist/jquery.js file. It does this by overriding the jquery pak.json export details.
Override Files
For details on creating a local override file, please see Overide Files in the Developers Guide.
Export Instructions
Export instructions in a pak.json file may be specified two ways:
- Export properties
- Export scripts
Export properties provide a simple, and flexible means of selecting and remapping the files to export. You specify the file patterns to export, the destination directory and other optional processing instructions. For example:
"export": { "from": [ "src/js/**", "src/css/**", ], "to": "lib", trim: 1 }
This copies the files under src/js and src/css to the lib/PACKAGE directory after trimmming one segment off the path. i.e. this trims the src segment from the filenames. The result will be the directories lib/PACKAGE/js and lib/PACKAGE/css.
If you are exporting a full path to the /lib/PACKAGE directory, you may use conventient abbreviated short forms. For example:
"export": "*.js" "export": [ "*.js", "**.css" ]
The export property can be set to a string, an array of strings or to object instructions. In the example above, the **.css selects all CSS files in any subdirectory. If the package already has an export definition in its own pak.json file, then use =export "assign" this export definition and replace any previous definition.
The full set of export properties are:
Property | Description |
---|---|
from | Filename patterns to copy. May be a string or array of strings. May include wild-cards. |
overwrite | If false, then files will only be exported once if they do not already exist. This prevents upgrades from overwriting files. |
to | Optional target directory for the files. Defaults to lib/PACKAGE where PACKAGE is the name of the package. Use ${TOP} for the application's top directory and ${LIB} for the application's export lib directory. |
trim | Number of directory components to trim from filenames when exporting. |
Wild Cards
The from property value (or the export property if it is set to a simple string) may contain wild cards. The following wild cards are supported.
- The wildcard ? matches any single character.
- * matches zero or more characters in a filename or directory.
- ** matches zero or more files or directories and matches recursively in a directory tree.
- ! Negates pattern. This removes matching patterns from the set. These are applied after all source patterns have been processed.
Scripted Export
If you have export needs that go beyond what can be expressed via export properties, you can also use the full scripting power of Ejscript to create custom export scripts. For example:
"export": { "script": ` let path = Path('paks/jquery') for each (file in path.files(['**/*.js'])) { if (file.contains('min.js')) { continue } path.copy('lib/jquery/' + file.basename) } ` }
Pak supports an extended JSON syntax where multi-line strings can be used. Strings can be delimited by single, double or back quote characters. Also, property names do not need to be quoted.
For example:
"export": { "script": "load('export.js')" }
Disabling Exports
The exporting of package contents is globally enabled or disabled for an application via the import property. Setting the import property to false in your application's pak.json file, will disable exporting contents from any package. This property defaults to false, so the absense of this property will disable exporting of package contents. When Pak creates a pak.json file, it will include a "import": true definition to enable package exports for all subsequently installed packages.
Customizing the Export Directory
The export directory can be customized in your pak.json directories properties. By default it is set to lib. To modify, update the lib directory property. For example:
directories: { "lib": "www/lib" }