# Overview

Editions is [a backwards compatible standard](#defining-editions) for describing the ways in which your project has been produced to accelerate manual consumption, as well as automatic consumption through [Ecosystem Tooling](https://editions.bevry.me/ecosystem).

{% embed url="<https://youtu.be/IAB8_UlcNWI>" %}
Watch the 2016 introductory talk to the Editions ecosystem.
{% endembed %}

## Why use Editions?

JavaScript production and consumption has gotten difficult over the years.

Production use to be as easy as publishing your source code, which worked across all environments, with a few minor tweaks. Consumption was as easy as including the package, and you are done.

However, these days, code may be run anywhere, in all sorts of browsers, desktop environments, and devices, of varying capabilities, not always known by the producer. JavaScript has also evolved, incorporating a lot of modern features that save developers time, but not supported across all possible environments - either requiring abstinence of time saving features, or eliminating environment support, or compilation on either the producer or consumer side - [this is all complex and difficult to manage](https://editions.bevry.me/comparisons/alternative-approaches).

Editions comes in to solve this problem, elegantly, and [in a standardised way](#how-do-i-define-an-edition), that works with current environments and development setups. Producers are able to produce their packages in their ideal configurations, then publish the package with multiple editions for the consumers to consume at their digression. Consumers are made aware of this through [automated README updates](#documenting-editions), and can [select the exact edition that meets their exact needs](#manually-require-a-specific-edition) - and by default, [the best edition for the environment can be automatically loaded](#best-edition-for-the-environment). All the complexity of modern JavaScript publishing is solved, for the consumer and publisher.

If you wish to delve further, refer to the [Alternative Approaches](https://editions.bevry.me/comparisons/alternative-approaches) document for a complete understanding of the problem space and why editions is a superior solution in it.

{% content-ref url="comparisons/alternative-approaches" %}
[alternative-approaches](https://editions.bevry.me/comparisons/alternative-approaches)
{% endcontent-ref %}

## Defining Editions

An edition is each variation of your code. Usually this comes in the form of your source edition, as well as compiled editions for each environment you wish to support.

### How do I define an Edition?

Practically, editions are specified in descending order of preference in the `editions` field of your `package.json` , with each edition being composed of the following fields:

* a `description` field to describe the edition
* a `directory` field for where the edition is located
* a `entry` field for the default file inside the `directory` to be loaded
* an optional `tags` field for [common keywords](https://editions.bevry.me/tags) to describe the edition that tooling can utilise

You can find the full technical specification here:

{% content-ref url="specification" %}
[specification](https://editions.bevry.me/specification)
{% endcontent-ref %}

### Example Editions Definition

For a project that has a source edition written in ESNext using `require('some-package')` syntax, with a compiled edition for the default browsers, as well as a compiled edition for older node versions, then a compatible editions definition for it would look like so:

{% code title="package.json" %}

```javascript
{
  "editions": [
    {
      "description": "esnext source code with require for modules",
      "directory": "source",
      "entry": "index.js",
      "tags": [
        "javascript",
        "esnext",
        "require"
      ],
      "engines": {
        "node": ">=6",
        "browsers": false
      }
    },
    {
      "description": "esnext compiled for browsers with require for modules",
      "directory": "edition-browsers",
      "entry": "index.js",
      "tags": [
        "javascript",
        "require"
      ],
      "engines": {
        "node": false,
        "browsers": "defaults"
      }
    },
    {
      "description": "esnext compiled for node.js >=0.8 with require for modules",
      "directory": "edition-node-0.8",
      "entry": "index.js",
      "tags": [
        "javascript",
        "require"
      ],
      "engines": {
        "node": ">=0.8",
        "browsers": false
      }
    }
  ]
}
```

{% endcode %}

### Automatic Creation of Editions

Tools like [Boundation](https://github.com/bevry/boundation) can automatically create for you the editions definition as well as the editions themselves.

{% embed url="<https://github.com/bevry/boundation>" %}
Automatically create your Editions with Boundation
{% endembed %}

## Consuming Editions

Editions can be consumed in multiple ways, here are the options:

### A Specified Edition

For producers who only want one edition to be used by default, they can specify the default edition to be loaded via the standard `main` property of the `package.json` file:

{% code title="package.json" %}

```javascript
{
  "main": "edition-node-0.8/index.js"
}
```

{% endcode %}

### Best Edition for the Environment

For producers who want consumers to automatically load the best edition for the consumers particular environment, you can make use of the [Editions Autoloader](https://github.com/bevry/editions) package.

1. Inside your project, install the Editions Autoloader package via `npm install --save editions`
2. Create a root `index.js` file that uses the Editions Autoloader to load the best edition from our available compatible editions.

   <pre class="language-javascript" data-title="index.js"><code class="lang-javascript">'use strict'
   /** @type {typeof import("./source/index.js") } */
   module.exports = require('editions').requirePackage(__dirname, require)
   </code></pre>
3. Set the `package.json` property `main` to point to the `index.js` file above, instead of a specfic edition.

   <pre class="language-javascript" data-title="package.json"><code class="lang-javascript">{
     "main": "index.js"
   }
   </code></pre>

#### Custom Entry Points

For binary executables or testing, we then we would want to specify a non-default entry to load for the editions. We can do this by passing the custom entry point as an extra argument to the `requirePackage` function.

&#x20;To specify a `bin.js` custom entry, then we would perform the following.

1. Create a root `bin.js` file that uses the Editions Autoloader to load the best `bin.js` script from our available compatible editions.

   <pre class="language-javascript" data-title="bin.js"><code class="lang-javascript">#!/usr/bin/env node
   'use strict'
   /** @type {typeof import("./source/bin.js") } */
   module.exports = require('editions').requirePackage(__dirname, require, 'bin.js')
   </code></pre>
2. Set the `bin` property in our `package.json` file to point to the root  `bin.js` file we just created.

   <pre class="language-javascript" data-title="package.json"><code class="lang-javascript">{
     "bin": "bin.js"
   }
   </code></pre>

To specify a `test.js` custom entry, then we would perform the following.

1. Create a root `test.js` file that uses the Editions Autoloader to load the best `test.js` script from our available compatible editions.

   <pre class="language-javascript" data-title="bin.js"><code class="lang-javascript">'use strict'
   /** @type {typeof import("./source/test.js") } */
   module.exports = require('editions').requirePackage(__dirname, require, 'test.js')
   </code></pre>
2. Set the `scripts.test` property in our `package.json` file to point to the root  `test.js` file we just created.

   <pre class="language-javascript" data-title="package.json"><code class="lang-javascript">{
     "scripts": {
       "test": "node ./test.js"
     }
   }
   </code></pre>

### Manually Require a Specific Edition

For consumers who [are informed about the particular editions that an editioned package offers](#displaying-editions), they can opt into a non-standard edition by specifying it manually in their consumption.

```javascript
// using require
require('a-editioned-package/a-custom-edition/')

// using import
import blah from 'a-editioned-package/a-custom-edition/'
```

### Browser Edition

For our [Example Editions Definition from earlier](#example-editions-definition), we would define the `browser` field in our `package.json` like so:

{% code title="package.json" %}

```javascript
{
  "browser": "edition-browsers/index.js"
}
```

{% endcode %}

This usage of the `browser` field tells most tools like Browserify, WebPack, and Rollup to specifically use the edition that we precompiled for the browsers we target for.

You can find more information about the `browser` field and its equivalents here:

{% content-ref url="comparisons/comparison" %}
[comparison](https://editions.bevry.me/comparisons/comparison)
{% endcontent-ref %}

You can find tooling that already has builtin support for the Editions specification here:

{% content-ref url="ecosystem" %}
[ecosystem](https://editions.bevry.me/ecosystem)
{% endcontent-ref %}

## Documenting Editions

If producers wish to inform consumers of the editions they provide, which is not necessary for consumption, but useful to the consumer, then producers can utilise [Projectz](https://github.com/bevry/projectz) to inject the appropriate editions information into your `README.md` file via the HTML comment `<!-- INSTALL -->` .

### Automatic Editions Rendering without the Editions Autoloader

If we partner our [Example Editions Definition from earlier](#example-editions-definition) with the following `package.json` fields:

{% code title="package.json" %}

```javascript
{
  "main": "editions-node-0.8/index.js"
}
```

{% endcode %}

&#x20;This will have Projectz turn the `<!-- INSTALL -->` comment in our `README.md` file into the following rendered output:

> #### [Editions](https://editions.bevry.me)
>
> * `require('project')` aliases `require('project/edition-node-0.8')`
> * `require('project/source')` is [ESNext](https://babeljs.io/docs/learn-es2015/) source code with [require for modules](https://nodejs.org/dist/latest-v10.x/docs/api/modules.html)
> * `require('project/edition-browsers')` is [ESNext](https://babeljs.io/docs/learn-es2015/) compiled for browsers with [require for modules](https://nodejs.org/dist/latest-v10.x/docs/api/modules.html)
> * `require('project/edition-node-0.8')` is [ESNext](https://babeljs.io/docs/learn-es2015/) compiled for [Node.js](https://nodejs.org/en/) >=0.8 with [require for modules](https://nodejs.org/dist/latest-v10.x/docs/api/modules.html)

### Automatic Editions Documentation with the Editions Autoloader

If we partner our [Example Editions Definition from earlier](#example-editions-definition) to [make use of the Editions Autoloader](#best-edition-for-the-environment), then Projectz will turn the `<!-- INSTALL -->` comment in our `README.md` file into the following rendered output:

> #### [Editions](https://github.com/bevry/editions)
>
> * `require('project')` aliases `require('project/index.js')`which uses the [Editions Autoloader](https://github.com/bevry/editions) to automatically select the correct edition for the consumers environment
> * `require('project/source')` is [ESNext](https://babeljs.io/docs/learn-es2015/) source code with [require for modules](https://nodejs.org/dist/latest-v10.x/docs/api/modules.html)
> * `require('project/edition-browsers')` is [ESNext](https://babeljs.io/docs/learn-es2015/) compiled for browsers with [require for modules](https://nodejs.org/dist/latest-v10.x/docs/api/modules.html)
> * `require('project/edition-node-0.8')` is [ESNext](https://babeljs.io/docs/learn-es2015/) compiled for [Node.js](https://nodejs.org/en/) >=0.8 with [require for modules](https://nodejs.org/dist/latest-v10.x/docs/api/modules.html)
