Polyfill service
Makes web development less frustrating by selectively polyfilling just what the browser needs. Use it on your own site, or as a service.
For usage information see the hosted service, which formats and displays the service API documentation located in the docs folder.
Table Of Contents
Requirements
Running Origami Build Service requires a few tools:
* Git: For downloading the source code
* Node.js 6.x and npm 3.x: For installing the dependencies and running the application (npm is installed with Node.js)
* Grunt 0.1.x: Used for automating tasks such as testing
Running Locally
Clone the project to your system:
git clone git@github.com:Financial-Times/polyfill-service.git
Change into the project directory:
cd polyfill-service
Install the dependencies:
npm install
Build the polyfill sources and start the server, rebuiling and restarting whenever any changes are made to the project:
grunt dev
Configuration
You can configure the Polyfill service using environment variables. In development, configurations are set in .env
. In production, these are set through Heroku config.
* `PORT`: The port on which to listen for HTTP requests (default 3000).
* `NODE_ENV`: Name of environment. `dev`, `prod`, `ci` or `qa`. Just used for logging.
* `FASTLY_SERVICE_ID`, `FASTLY_SERVICE_ID_QA`, `FASTLY_API_KEY`: Used to fetch and render cache hit stats on the [usage] page of the hosted documentation, and to deploy VCL. If not specified, no stats will be shown and VCL deploy will fail.
* `PINGDOM_CHECK_ID`, `PINGDOM_API_KEY`, `PINGDOM_ACCOUNT`, `PINGDOM_USERNAME`, `PINGDOM_PASSWORD`: Used to fetch and render uptime and response time stats on the [usage] page of the hosted documentation. If not specified, no stats will be shown.
* `GRAPHITE_HOST`: Host to which to send Carbon metrics. If not set, no metrics will be sent.
* `GRAPHITE_PORT`: Port on the `GRAPHITE_HOST` to which to send Carbon metrics (default 2002).
* `SAUCE_USER_NAME` and `SAUCE_API_KEY`: [Sauce Labs][sauce] credentials for grunt test tasks (not used by the service itself)
* `ENABLE_ACCESS_LOG`: Any truthy value will enable writing an HTTP access log from Node. Useful if you are not running node behind a routing layer like nginx or heroku.
Testing
The tests are split into tests for the service and tests for the polyfills. The polyfill tests require SAUCE_USER_NAME
and SAUCE_API_KEY
to be configured, view the configuration section for more information.
grunt test
grunt simplemocha
grunt ci
We run the tests on CircleCI. grunt ci
must pass before we merge a pull request.
Release Process
- The release candidate is tested with the full grunt compatgen task to generate an updated compatibility table.
- The commit is tagged vX.Y.Z-rcN where N is initially 1
- Deploy to QA
- Announce the release on twitter
- Wait some number of days for feedback (usually 7 days). If necessary, make fixes, increment N, and return to step 1
- Update package.json version and github tag with vX.Y.Z
- Publish to npm
- Push to cdn.polyfill.io
Deployment
The production and QA applications run on Heroku. The library is published to the public npm registry.
Before creating a new deployment, update the compatability table:
grunt compatgen && git commit docs/assets/compat.json -m 'update compat.json'
We use Semantic Versioning to tag releases. Only tagged releases should hit production, which ensures that the /__about
endpoint is informative. To tag a new release, use one of the following (this is the only time we allow a commit directly to master
):
npm version major
npm version minor
npm version patch
Now you can push to GitHub:
git push && git push --tags
After pushing to Github, you can deploy to QA:
npm run deploy
When it is time to promote from QA to production:
npm run promote
Publishing
To publish to the public npm registry, you need to be logged in to the NPM CLI.
Check if you are already logged in to NPM via the CLI:
npm whoami
If you are not logged in, log in to NPM:
npm login
Publish a new version of the package:
npm publish
Monitoring
We use Graphite and Grafana to keep track of application metrics. You can view requests, bundle build duration, cache hit ratios, and memory usage. It's important after a deploy to make sure we haven't unexpectedly had an impact on these.
We also use Pingdom to track uptime. You should get notifications if you're a member of the Origami team.
Library API Reference
Using as a library
The Polyfill service can also be used as a library in NodeJS projects. To do this:
- Add this repo as a dependency in your package.json
e.g.
npm install polyfill-service --save
- Rebuild your project using
npm install
- Use the API from your code
getPolyfillString(options)
(method)
Returns a promise of a polyfill bundle string. Options is an object with the following keys:
uaString
: String, required. The user agent to evaluate for polyfills that should be included conditionallyminify
: Boolean, optional. Whether to minify the bundlefeatures
: Object, optional. An object with the features that are to be considered for polyfill inclusion. If not supplied, no features will be considered and the output will be blank. To load the default feature set, set features to {default:{}}
. Each feature must be an entry in the features object with the key corresponding to the name of the feature and the value an object with the following properties:
flags
: Array, optional. Array of flags to apply to this feature (see below)
excludes
: Array, optional. Array of features to exclude from the final bundle.unknown
: String, optional. What to do when the user agent is not recognised. Set to polyfill
to return polyfills for all qualifying features, ignore
to return nothing. Defaults to ignore
.
Flags that may be applied to polyfills are:
gated
: Wrap this polyfill in a feature-detect, to avoid overwriting the native implementationalways
: Include this polyfill regardless of the user-agent
Example:
require('polyfill-service').getPolyfillString({
uaString: 'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)',
minify: true,
features: {
'Element.prototype.matches': { flags: ['always', 'gated'] },
'modernizr:es5array': {}
}
}).then(function(bundleString) {
console.log(bundleString);
});
getPolyfills(options)
(method)
Returns a promise of a set of features which are configured to be applied in browsers with the specified user agent string.
Options is an object with the following keys:
uaString
: String, required. The user agent to evaluate for features that should be included conditionallyfeatures
: Object, optional. An object with the features that are to be considered for polyfill inclusion. If not supplied, all default features will be considered. Each feature must be an entry in the features object with the key corresponding to the name of the feature and the value an object with the following properties:
flags
: Array, optional. Array of flags to apply to this feature (see below)
excludes
: Array, optional. Array of features to exclude from the final bundle.
Example:
require('polyfill-service').getPolyfills({
uaString: 'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)',
features: {
'Element.prototype.matches': { flags: ['always', 'gated'] },
'modernizr:es5array': {}
}
}).then(function(polyfillSet) {
console.log(polyfillSet);
});
listAllPolyfills()
(method)
Return a promise of an array all the polyfills as an array of strings. This list corresponds to directories and subdirectories in the /polyfills
directory.
Example:
require('polyfill-service').listAllPolyfills();
License
Except where indicated in selected polyfill config files, the polyfill service codebase is licensed under the terms of the MIT license. Contributors must accept our contribution terms.