Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/egoist/eva.js
💫 A complete solution to building modern webs with Vue.js and its friends.
https://github.com/egoist/eva.js
Last synced: about 2 months ago
JSON representation
💫 A complete solution to building modern webs with Vue.js and its friends.
- Host: GitHub
- URL: https://github.com/egoist/eva.js
- Owner: egoist
- Archived: true
- Created: 2016-08-03T16:21:29.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2020-04-30T20:21:40.000Z (over 4 years ago)
- Last Synced: 2024-04-14T14:17:00.562Z (5 months ago)
- Language: JavaScript
- Homepage:
- Size: 447 KB
- Stars: 203
- Watchers: 10
- Forks: 7
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
eva.js is a complete solution to
building modern webs with Vue.js.## tl;dr
```js
// model
app.model()
// router
app.router()
// bootstrap
app.start()
```Play with the [JSBin example](http://jsbin.com/laqopo/edit?js,output) or the [simple webpack example](https://github.com/egoist/eva-webpack-simple) 😀
Table of Contents
- [Sites using eva.js](#sites-using-evajs)
- [Features](#features)
- [Install](#install)
- [Usage](#usage)
- [Concepts](#concepts)
* [Models](#models)
+ [Top-level model:](#top-level-model)
+ [Namespaced model:](#namespaced-model)
+ [Helpers:](#helpers)
* [Router](#router)
* [Views](#views)
- [Vue constructor](#vue-constructor)
- [Access $store and $router outside component](#access-store-and-router-outside-component)
- [Server-side rendering](#server-side-rendering)
- [API](#api)
* [new EVA([options: object])](#new-evaoptions-object)
+ [options.mode](#optionsmode)
* [app.model(model: object)](#appmodelmodel-object)
* [app.router(handler: function)](#approuterhandler-function)
* [app.use(plugin: function, [options: object])](#appuseplugin-function-options-object)
* [app.start([App: object], [selector: string])](#appstartapp-object-selector-string)
* [app.mount(selector)](#appmountselector)
* [app.syncRouterInStore()](#appsyncrouterinstore)
* [app.$store](#appstore)
* [app.$router](#approuter)
* [app.instance](#appinstance)
- [Development](#development)
- [License](#license)## Sites using eva.js
Feel free to add your project here!
- [vbuild.js.org](https://vbuild.js.org/) ([source](https://github.com/egoist/vbuild.js.org))
- [vue-play](http://vue-play-button.surge.sh/#/) ([source](https://github.com/egoist/vue-play))## Features
- Battery included, Vue 2 and its friends (Vuex & Vue-Router)
- Small APIs, just Vue and the official plugins you already play well with!
- Support server-side rendering, of course!
- Inspired by the [choo](https://github.com/yoshuawuyts/choo) framework which is inpired by the [elm architecture](https://guide.elm-lang.org/architecture/)## Install
```bash
$ npm install --save eva.js
```In case you may want to use it directly in browser instead, view https://unpkg.com/eva.js/dist/, and add:
```html
```
If you use the commonjs version and wanna include the runtime for vue template, follow the [official guide](http://vuejs.org/guide/installation.html#Standalone-vs-Runtime-only-Build):
## Usage
```js
import EVA from 'eva.js'// Create app instance
const app = new EVA()// A counter model
app.model({
state: {count: 0},
mutations: {
INCREMENT(state) {state.count++}
}
})// A home view
const Home = {
computed: {
count() {
return this.$store.state.count
}
},
render(h) {
return (
Home
this.$store.commit('INCREMENT')}>
{this.count}
)
}
}// Apply views to relevant routes
// route(path, view, child_routes)
app.router(route => [
route('/', Home)
])// Start app
const App = {
render(h) {
return (
)
}
}
app.start(App, '#app')
// equal to
// app.start(App)
// app.mount('#app')
```## Concepts
### Models
A model contains it's initial state and the methods you use to update its state, in fact, it's a typical Vuex module too.
#### Top-level model:
```js
// An app instance only have at most one top-level model
app.model({
state: {count: 0},
mutations: {
INCREMENT(state) {state.count++}
}
})
```#### Named/Namespaced model:
```js
// An app could have multiple named models
app.model({
name: 'user',
state: {login: false},
mutations: {
LOG_IN(state) {state.login = true}
}
})
```By default only state are registered locally under provided name, eg `state.user.login`. But `mutations` `actions` `getters` are still in global namespace, to enforce name for those too, please change `name` to `namespace`:
```js
app.model({
namespace: 'user',
state: {login: false},
mutations: {
LOG_IN(state) {state.login = true}
},
actions: {
login({commit}) {
commit('LOG_IN') //=> user/LOG_IN
}
}
})
```Check out official docs for `modules` in vuex: http://vuex.vuejs.org/en/modules.html
> In most cases using namespaces is beneficial, as having clear boundaries makes it easier to follow logic.
#### Helpers:
As how you use Vuex^2, you can use its helpers too:
```js
const {mapState, mapActions, mapGetters} = require('eva.js')
// or ES6 modules
import {mapState, mapActions, mapGetters} from 'eva.js'// of course you can directly import from 'vuex' too
import {mapState, mapActions, mapGetters} from 'vuex'
```### Router
The router could render the component which matches the URL path. It has a `route` helper for creating an actual route object used in `vue-router`. routes are passed in as a nested array.
```js
app.router(route => [
route('/', Home),
route('/settings', Settings, [
route('/profile', SettingsProfile),
route('/password', SettingsPassword)
])
])// use an object as route argument:
route({path: '/', component: Home, /*...*/})// use an object as router argument:
app.router({
mode: 'history',
routes: []
})
```[The router state is effortlessly synced in vuex store.](https://github.com/vuejs/vuex-router-sync#how-does-it-work)
### Views
A view is a simple Vue component, that easy :)
## Vue constructor
If you wan to access Vue constructor directly, simply do:
```js
import {Vue} from 'eva.js'
// or without any change
// import Vue from 'vue'
// works tooVue.use(yourPlugin)
```## Access $store and $router outside component
You can initialize your app and bootstrap it later:
```js
// ./src/app.js
import EVA from 'eva.js'const app = new EVA()
app.model() //...
app.router() //...export default app.start()
// ./src/index.js
import app from './app'
app.mount('#app')// ./some/other/file.js
import app from './path/to/src/app.js'app.$router.push('/somewhere')
```## Server-side rendering
Similar to the official [hackernews example](https://github.com/vuejs/vue-hackernews-2.0/blob/master/src/app.js):
```js
// ./src/app.js
import EVA from 'eva.js'
import App from './App.vue'const app = new EVA()
export default app.start(App)
// without selector!
// otherwise it will be mounted to the selector
```Then for the `server-entry.js`:
```js
// ./src/server-entry.js
import app from './app'export default context => {
// you can access app.$router / app.$store
return Promise.all(operations)
.then(() => {
return app.instance
})
}
```For `client-entry.js`:
```js
import app from './app'app.mount('#app')
```## Promise polyfill
Some browsers do not have native Promise, like IE, but `vuex` requires Promise. Thus `eva.js` provides an lightweight Promise polyfill with [promise-polyfill](https://github.com/taylorhakes/promise-polyfill).
```js
import 'eva.js/promise-polyfill'
import EVA from 'eva.js'
// ... your app code
```## API
### new EVA([options: object])
Create an app instance.
#### options.mode
The router mode, can be either `hash` *(default)* or `history`.
### app.model(model: object)
Register a model, a.k.a. store module in Vuex. You can omit the `name` and `namespace` property to make it top-level.
### app.router(handler: function)
Register routes.
### app.use(plugin: function, [options: object])
The same as `Vue.use`, you can apply any Vue plugin.
### app.start([App: object], [selector: string])
Create app instance. Optionally mount App component to a domNode if selector is defined.
If App is not specified, we use a default value:
```js
const defaultApp = {
render(h) {
return
}
}
```If selector is not specified, we won't mount the app instance to dom.
### app.mount(selector)
Mounted app instance to dom, must be call after `app.start([App])` (without `selector` argument). Default `selector` is `#app`
### app.syncRouterInStore()
keep vue-router and vuex store in sync, i.e. keep router state in vuex store.
The method will be called automatically in `app.start()`, you can also call it manually before `app.start()` and `app.start()` won't call it again.
### app.$store
The vuex store instance.
### app.$router
The vue-router instance.
### app.instance
The Vue instance created by `app.start()`, most likely you will use this in [server-side rendering](#server-side-rendering).
## Development
```bash
# build and watch source files
$ npm run watch# launch server for simple html example
$ http-server .
# run webpack example
$ npm run webpack# build for publish to npm
# cjs and umd and compressed umd
$ npm run build
```## License
MIT © [EGOIST](https://github.com/egoist)