---
url: /intro/progressive.md
---
# Progressive Development

Egg provides both [Plugin](../basics/plugin.md) and [Framework](../advanced/framework.md), and the former has two loading modes which are `path` and `package`. Then how should we choose?

Step-by-step example will be provided to demonstrate how to start coding development progressively.

Find detail codes on [eggjs/examples/progressive](https://github.com/eggjs/examples/tree/master/progressive).

## Getting Started

Assume that we are writing a code to analyze UA to implement the function below:

* `ctx.isAndroid`
* `ctx.isIOS`

You can easily write it down after previous tutorials, let's have a quick review:

Codes refer to [step1](https://github.com/eggjs/examples/tree/master/progressive/step1).

Directory structure:

```bash
example-app
├── app
│   ├── extend
│   │   └── context.js
│   └── router.js
├── test
│   └── index.test.js
└── package.json
```

Core code:

```js
// app/extend/context.js
module.exports = {
  get isIOS() {
    const iosReg = /iphone|ipad|ipod/i;
    return iosReg.test(this.get('user-agent'));
  },
};
```

## Prototype of Plugin

Obviously, the logic is universal that can be written as a plugin.

But since function might not be perfect at the beginning, it might be difficult to maintain if encapsulated into a plugin directly.

We can write the code as the format of plugin, but not separate out.

Codes refer to [step2](https://github.com/eggjs/examples/tree/master/progressive/step2).

New directory structure:

```bash
example-app
├── app
│   └── router.js
├── config
│   └── plugin.js
├── lib
│   └── plugin
│       └── egg-ua
│           ├── app
│           │   └── extend
│           │       └── context.js
│           └── package.json
├── test
│   └── index.test.js
└── package.json
```

Core code:

* `app/extend/context.js` move to `lib/plugin/egg-ua/app/extend/context.js`.

* `lib/plugin/egg-ua/package.json` declares plugin.

```json
{
  "eggPlugin": {
    "name": "ua"
  }
}
```

* `config/plugin.js` uses `path` to mount the plugin.

```js
// config/plugin.js
const path = require('path');
exports.ua = {
  enable: true,
  path: path.join(__dirname, '../lib/plugin/egg-ua'),
};
```

## Extract to Independent Plugin

The functions of module become better after a period of developing so we could extract it out as an independent plugin.

We extract an egg-ua plugin and have a quick review as below. Details refer to [Plugin Development](../advanced/plugin.md).

Directory structure:

```bash
egg-ua
├── app
│   └── extend
│       └── context.js
├── test
│   ├── fixtures
│   │   └── test-app
│   │       ├── app
│   │       │   └── router.js
│   │       └── package.json
│   └── ua.test.js
└── package.json
```

Codes refer to [step3/egg-ua](https://github.com/eggjs/examples/tree/master/progressive/step3/egg-ua).

Then modify the application, details refer to [step3/example-app](https://github.com/eggjs/examples/tree/master/progressive/step3/example-app).

* Remove directory `lib/plugin/egg-ua`.
* Declare dependencies `egg-ua` in `package.json`.
* Change type to `package` in `config/plugin.js`.

```js
// config/plugin.js
exports.ua = {
  enable: true,
  package: 'egg-ua',
};
```

**Note：We can use `npm link` for local test before releasing the plugin. Details refer to [npm-link](https://docs.npmjs.com/cli/link).**

```bash
$ cd example-app
$ npm link ../egg-ua
$ npm i
$ npm test
```

## Finally: A Framework

After repeating the process above, we accumulate a few plugins and configurations, and might find that most of our team projects are using them.

At that time, you can consider abstracting them as a framework which is suitable for business scenarios.

Firstly, abstract the example-framework as below. Let's have a quick review, details refer to [Framework](../advanced/framework.md).

Directory structure:

```bash
example-framework
├── config
│   ├── config.default.js
│   └── plugin.js
├── lib
│   ├── agent.js
│   └── application.js
├── test
│   ├── fixtures
│   │   └── test-app
│   └── framework.test.j.
├── README.md
├── index.js
└── package.json
```

* Codes refer to [example-framework](https://github.com/eggjs/examples/tree/master/progressive/step4/example-framework).
* Remove the dependencies of plugins such as `egg-ua` and remove it from example-app, then configure them into the `package.json` and `config/plugin.js` of the framework.

Then modify the application, details refer to [step4/example-app](https://github.com/eggjs/examples/tree/master/progressive/step4/example-app).

* Remove `egg-ua` in `config/plugin.js`.
* Remove `egg-ua` in `package.json`.
* declare `example-framework` in `package.json` and configure the `egg.framework`.

```json
{
  "name": "progressive",
  "version": "1.0.0",
  "private": true,
  "egg": {
    "framework": "example-framework"
  },
  "dependencies": {
    "example-framework": "*"
  }
}
```

**Note：We can use `npm link` for local test before releasing the framework [npm-link](https://docs.npmjs.com/cli/link).**

```bash
$ cd example-app
$ npm link ../egg-framework
$ npm i
$ npm test
```

## In the End

In conclusion, we can see how to make the framework evolution step by step which benefits from Egg's powerful plugin mechanism, code co-build, reusability and modularity.

* In general, put codes into `lib/plugin` if they can be reused in the application.

* Separate it into a `node module` when plugin becomes stable.

* Application with relatively reusable codes will work as a separate plugin.

* Abstract it as framework to release after application become certain solutions of specified business scenario.

* It would be a great improvement in the efficiency of teamwork after plugins were extracted, modularized and finally became a framework, because other projects could reuse codes by just using `npm install`.

* **Note：Whether it's the application/plugin/framework, unittest is necessary and try to reach 100% coverage**
