# koa-vuessr-middleware

> a vue ssr middleware for koa

Latest version **1.0.3** (published 2019-02-21) · ISC license · 0 weekly downloads

## Install

```sh
npm install koa-vuessr-middleware
pnpm add koa-vuessr-middleware
yarn add koa-vuessr-middleware
bun add koa-vuessr-middleware
```

Provides the command `vuessr`.

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.3 |
| Published | 2019-02-21 |
| First published | 2018-11-08 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 35 |
| Unpacked size | 107.7 KB |
| Known vulnerabilities | 0 (+4 in 3 direct dependencies) |
| Install scripts | no |
| GitHub stars | 8 |
| Author | Evont |
| Maintainers | evont |
| Keywords | koa, middleware, vue, ssr |

## Links

- npm: https://www.npmjs.com/package/koa-vuessr-middleware
- Repository: https://github.com/evont/koa-vuessr
- Issues: https://github.com/evont/koa-vuessr/issues
- npm.io page: https://npm.io/package/koa-vuessr-middleware

## Dependencies (35)

- [vue](https://npm.io/package/vue.md) ^2.5.22
- [glob](https://npm.io/package/glob.md) ^7.1.3
- [vuex](https://npm.io/package/vuex.md) ^3.0.1
- [rimraf](https://npm.io/package/rimraf.md) ^2.6.2
- [webpack](https://npm.io/package/webpack.md) ^4.25.1
- [cross-env](https://npm.io/package/cross-env.md) ^5.2.0
- [lru-cache](https://npm.io/package/lru-cache.md) ^4.1.3
- [babel-core](https://npm.io/package/babel-core.md) ^6.26.3
- [css-loader](https://npm.io/package/css-loader.md) ^1.0.1
- [url-loader](https://npm.io/package/url-loader.md) ^1.1.2
- [vue-loader](https://npm.io/package/vue-loader.md) ^15.4.2
- [vue-router](https://npm.io/package/vue-router.md) ^3.0.1
- [es6-promise](https://npm.io/package/es6-promise.md) ^4.2.5
- [file-loader](https://npm.io/package/file-loader.md) ^2.0.0
- [null-loader](https://npm.io/package/null-loader.md) ^0.1.1
- [webpack-cli](https://npm.io/package/webpack-cli.md) ^3.1.2
- [babel-loader](https://npm.io/package/babel-loader.md) ^7.1.5
- [webpack-merge](https://npm.io/package/webpack-merge.md) ^4.1.4
- [postcss-loader](https://npm.io/package/postcss-loader.md) ^3.0.0
- [babel-preset-env](https://npm.io/package/babel-preset-env.md) ^1.7.0
- [vuex-router-sync](https://npm.io/package/vuex-router-sync.md) ^5.0.0
- [vue-server-renderer](https://npm.io/package/vue-server-renderer.md) ^2.5.22
- [vue-template-compiler](https://npm.io/package/vue-template-compiler.md) ^2.5.22
- [webpack-dev-middleware](https://npm.io/package/webpack-dev-middleware.md) ^3.4.0
- [webpack-hot-middleware](https://npm.io/package/webpack-hot-middleware.md) ^2.24.3
- [webpack-node-externals](https://npm.io/package/webpack-node-externals.md) ^1.7.2
- [babel-plugin-syntax-jsx](https://npm.io/package/babel-plugin-syntax-jsx.md) ^6.18.0
- [mini-css-extract-plugin](https://npm.io/package/mini-css-extract-plugin.md) ^0.4.4
- [sw-precache-webpack-plugin](https://npm.io/package/sw-precache-webpack-plugin.md) ^0.11.5
- [extract-text-webpack-plugin](https://npm.io/package/extract-text-webpack-plugin.md) ^3.0.2
- [babel-plugin-transform-runtime](https://npm.io/package/babel-plugin-transform-runtime.md) ^6.23.0
- [babel-plugin-transform-vue-jsx](https://npm.io/package/babel-plugin-transform-vue-jsx.md) ^3.7.0
- [friendly-errors-webpack-plugin](https://npm.io/package/friendly-errors-webpack-plugin.md) ^1.7.0
- [babel-helper-vue-jsx-merge-props](https://npm.io/package/babel-helper-vue-jsx-merge-props.md) ^2.0.3
- [babel-plugin-syntax-dynamic-import](https://npm.io/package/babel-plugin-syntax-dynamic-import.md) ^6.18.0

## Alternatives

- [@sindresorhus/slugify](https://npm.io/package/@sindresorhus/slugify.md) — 3.7M weekly downloads
- [solid-js](https://npm.io/package/solid-js.md) — 2.7M weekly downloads
- [expo-glass-effect](https://npm.io/package/expo-glass-effect.md) — 2.5M weekly downloads
- [nanoassert](https://npm.io/package/nanoassert.md) — 780.8K weekly downloads
- [@ffmpeg/ffmpeg](https://npm.io/package/@ffmpeg/ffmpeg.md) — 529.5K weekly downloads

## Recent versions

- 1.0.3 (latest) — 2019-02-21
- 1.0.2 — 2019-01-15
- 1.0.1 — 2019-01-15
- 1.0.0 — 2019-01-06
- 0.0.11 — 2019-01-05
- 0.0.10 — 2018-11-29
- 0.0.9 — 2018-11-26
- 0.0.8 — 2018-11-22
- 0.0.7 — 2018-11-20
- 0.0.6 — 2018-11-13
- 0.0.5 — 2018-11-11
- 0.0.4 — 2018-11-09
- 0.0.3 — 2018-11-09
- 0.0.2 — 2018-11-08
- 0.0.1 — 2018-11-08

## README

# Koa-VueSSR
基于Koa 2.x 的Vue SSR 中间件（Vue SSR middleware for `koa 2.x`）

## **installation**

```javascript
npm install koa-vuessr-middleware
```
---
## **用法**
如果你需要运行在生产环境中，你需要先在`package.json` 文件中配置`scripts`字段，
```json
  "scripts": {
    "build": "vuessr"
  }
```
然后执行 `npm run build` 命令生成生产代码

```javascript
const koa = require('koa');
const app = new koa();
const koaRouter = require('koa-router');
const ssr = require('koa-vuessrr-middleware');

router.get('/otherroute', othermiddleware);
router.get('*', ssr(app, opts));

app.use(router.routes());
app.listen(8080);
```

- `app` koa 的app 实例
- `opts` 配置选项

    **Options**
    - `title` 页面默认标题，默认为空；
    - `isProd` 是否为生产模式，默认为 `false`，如果设置为 `true`，你需要先生成生产代码，为`false` 时，该中间件会使用 `webpack-hot-middleware`& `webpack-dev-middleware` 以实现热更新功能；
    - ~~`templatePath` 默认网页模板，默认为空，即使用内置的网页模板~~
---

你需要在项目根目录下有一个 `.ssrconfig` 作为配置文件，以下是配置例子

.ssrconfig
```json
{
  "template": "./src/index.template.html",
  "ouput": {
    "path": "./dist", 
    "publicPath": "/dist/"
  },
  "errorPage": {
    "500": "./500.html",
    "404": "./404.html"
  },
  "entry": {
    "client": "./src/entry-client.js",
    "server": "./src/entry-server.js"
  },
  "webpackConfig": {
    "client": "./build/webpack.client.conf.js",
    "server": "./build/webpack.server.conf.js"
  }
}
```
- `template` 默认网页模板，默认为空，即使用内置的网页模板
- `entry` 当你想要使用内置webpack 配置文件的时候为**必要**选项。 webpack的入口js， `client` 是客户端入口文件, `server` 为服务端入口文件;
- `errorPage` 当服务端出现500或404错误时使用的页面，可配置500 or 404字段，不配置时会显示报错信息
- `output` 如果你想使用内置webpack 配置文件的时候，你需要声明输出目录选项， `path` 为输出的文件夹目录，`publicPath` 是生成到模板中时的资源路径, 具体可以参考 [webpack output 配置](https://webpack.js.org/configuration/output/)
- `webpackConfig` 如果你倾向于使用你自己的webpack 配置文件，你需要配置下列选项: 
    - `client` 客户端配置webpack 配置
    - `server` 服务端配置webpack 配置

---

实际使用可以参考 [Demo](https://github.com/evont/koa-vuessr-middleware/tree/master/demo) 

目录结构示例

```
├── src                      app directory
│   ├── router/              route directory
│   ├── views/               views directory
│   ├── components/          compoennts directory
│   ├── app.js               js file to export a createApp function
│   ├── App.vue              root Vue
│   ├── entry-server.js      server side entry point
│   └── entry-client.js      client side entry point
├── index.js                 server entry point
├── .ssrconfig               SSR configuration file
├── ...	
```

app.js 例子 

```javascript
import Vue from 'vue'
import App from './App.vue'
import { createRouter } from './router'
import titleMixin from './util/title'

Vue.mixin(titleMixin)
export function createApp () {
  const router = createRouter()
  const app = new Vue({
    router,
    render: h => h(App)
  })
  return { app, router, }
}
```

entry-client.js 例子

```javascript
import Vue from 'vue'
import 'es6-promise/auto'
import { createApp } from './app'

const { app, router } = createApp()

router.onReady(() => {
  app.$mount('#app')
})
```

entry-server.js 例子

```javascript
import { createApp } from './app';
export default context => {
  return new Promise((resolve, reject) => {
    const { app, router } = createApp()
    const { url } = context
    const { fullPath } = router.resolve(url).route
    if (fullPath !== url) {
      return reject({ url: fullPath })
    }
    router.push(url)
    router.onReady(() => {
      const matchedComponents = router.getMatchedComponents()
      if (!matchedComponents.length) {
        return reject({ code: 404 })
      }
      Promise.all(matchedComponents.map(({ asyncData }) => asyncData)).then(() => {
        resolve(app)
      }).catch(reject)
    }, reject)
  })
}
```

##  **注意**

如果你想要使用自己的webpack 配置文件，你需要使用`Code-Splitting` 功能，你需要在你的`.babelrc` or `babel-loader`中配置 `syntax-dynamic-import`，否则会报错

```json
"plugins": [
    "syntax-dynamic-import"
]
```

---

## **usage**

if you want to run in production mode, you should run `vuessr` command first

```javascript
const koa = require('koa');
const app = new koa();
const koaRouter = require('koa-router');
const ssr = require('koa-vuessrr-middleware');

router.get('/otherroute', othermiddleware);
router.get('*', ssr(app, opts));

app.use(router.routes());
app.listen(8080);
```

- `app` koa app
- `opts` options object

    **Options**
    - `title` default title for html, default to empty string
    - `isProd` is Production Mode, default to false, if true, you need to run `vuessr` command to build distrubution file first. if false, the middleware will use `webpack-hot-middleware`& `webpack-dev-middleware` to setup a hot reload server;
    - ~~`templatePath` html template path, default to empty string, then it will use the built in template file~~
---

You also need to have a `.ssrconfig` file in your root directory, here is an example for `.ssrconfig` file;

.ssrconfig
```json
{
  "template": "./src/index.template.html",
  "ouput": {
    "path": "./dist", 
    "publicPath": "/dist/"
  },
  "entry": {
    "client": "./src/entry-client.js",
    "server": "./src/entry-server.js"
  },
  "webpackConfig": {
    "client": "./build/webpack.client.conf.js",
    "server": "./build/webpack.server.conf.js"
  }
}
```
- `template` html template path, default to empty string, then it will use the built in template file
- `entry` **required** if you want to use the built in webpack config file. This is the entrypoint js for webpack, `client` is the client side entrypoint, `server` is the server side entrypoint;
- `output` if you want to use the built in webpack config file, you need to specify output option with `path` for distribution file path & `publicPath` for every URL created by the runtime or loaders, check [webpack output configuration](https://webpack.js.org/configuration/output/)
- `webpackConfig` if you prefer to use your own webpack config, you need to specify this option, you need two configuration file: 
    - `client` for client side configuration file path 
    - `server` for server side configuration file path;

---

See [Demo](https://github.com/evont/koa-vuessr-middleware/tree/master/demo) for more pratical usage

Directory structure example:

```
├── src                      app directory
│   ├── router/              route directory
│   ├── views/               views directory
│   ├── components/          compoennts directory
│   ├── app.js               js file to export a createApp function
│   ├── App.vue              root Vue
│   ├── entry-server.js      server side entry point
│   └── entry-client.js      client side entry point
├── index.js                 server entry point
├── .ssrconfig               SSR configuration file
├── ...	
```

app.js example 

```javascript
import Vue from 'vue'
import App from './App.vue'
import { createRouter } from './router'
import titleMixin from './util/title'

Vue.mixin(titleMixin)
export function createApp () {
  const router = createRouter()
  const app = new Vue({
    router,
    render: h => h(App)
  })
  return { app, router, }
}
```

entry-client.js example

```javascript
import Vue from 'vue'
import 'es6-promise/auto'
import { createApp } from './app'

const { app, router } = createApp()

router.onReady(() => {
  app.$mount('#app')
})
```

entry-server.js example

```javascript
import { createApp } from './app';
export default context => {
  return new Promise((resolve, reject) => {
    const { app, router } = createApp()
    const { url } = context
    const { fullPath } = router.resolve(url).route
    if (fullPath !== url) {
      return reject({ url: fullPath })
    }
    router.push(url)
    router.onReady(() => {
      const matchedComponents = router.getMatchedComponents()
      if (!matchedComponents.length) {
        return reject({ code: 404 })
      }
      Promise.all(matchedComponents.map(({ asyncData }) => asyncData)).then(() => {
        resolve(app)
      }).catch(reject)
    }, reject)
  })
}
```

##  **Notice**

if you want to use your own webpack configuration & you want to use `Code-Splitting`, you need to use `syntax-dynamic-import` plugin in your `.babelrc` or `babel-loader` options;

```json
"plugins": [
    "syntax-dynamic-import"
]
```


## **ChangeLog**
### v 1.0.3
- 新增自定义错误页面
- 将500 错误设置默认显示为报错信息

---
_Source: https://npm.io/package/koa-vuessr-middleware · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
