Merge pull request #92 from Granipouss/master

Store generation
This commit is contained in:
Sébastien Chopin 2017-01-02 18:41:39 +01:00 committed by GitHub
commit d7de8bf458
11 changed files with 263 additions and 2 deletions

View File

@ -0,0 +1,94 @@
# Nuxt.js with Vuex 2
> Using a store to manage the state is important to every big application, that's why nuxt.js implement Vuex in its core.
> Alternative way of creating a store modularly.
## Activating the store
Nuxt.js will look for the `./store/` directory, if it exists, its will import and use Vuex. If there is no `./store/index.js` file that returns a store, Nuxt.js will go through all files of the `./store/` directory and create a store with a module for each file (`./store/index.js` being "root" module).
## Create the store folder
Let's create a file `store/index.js`:
```js
export const state = { counter: 0 }
export const mutations = {
increment (state) {
state.counter++
}
}
```
and
`store/todos.js`:
```js
export const state = {
list: []
}
export const mutations = {
add (state, { text }) {
state.list.push({
text,
done: false
})
},
delete (state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1)
},
toggle (state, { todo }) {
todo.done = !todo.done
}
}
```
> We don't need to install `Vuex` since it's shipped with nuxt.js
## Voilà !
We can now use `this.$store` inside our `.vue` files.
```html
<template>
<button @click="$store.commit('increment')">{{ $store.state.counter }}</button>
</template>
```
The store will be as such:
```js
new Vuex.Store({
state: { counter: 0 },
mutations: {
increment (state) {
state.counter++
}
},
modules: {
todos: {
state: {
list: []
},
mutations: {
add (state, { text }) {
state.list.push({
text,
done: false
})
},
delete (state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1)
},
toggle (state, { todo }) {
todo.done = !todo.done
}
}
}
}
})
```

View File

@ -0,0 +1,11 @@
{
"name": "nuxt-vuex-store",
"dependencies": {
"nuxt": "latest"
},
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start"
}
}

View File

@ -0,0 +1,8 @@
<template>
<div>
<p>
<button @click="$store.commit('increment')">{{ $store.state.counter }}</button><br>
<nuxt-link to="/">Home</nuxt-link>
</p>
</div>
</template>

View File

@ -0,0 +1,29 @@
<template>
<div>
<p>
<button @click="increment">{{ counter }}</button>
<br>
<nuxt-link to="/about">About</nuxt-link>
<br>
<nuxt-link to="/todos">Todos</nuxt-link>
</p>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
// fetch(context) is called by the server-side
// and nuxt before instantiating the component
fetch ({ store }) {
store.commit('increment')
},
computed: mapState([
'counter'
]),
methods: {
increment () { this.$store.commit('increment') }
}
}
</script>

View File

@ -0,0 +1,41 @@
<template>
<div>
<h2>Todos</h2>
<input placeholder="What needs to be done?" @keyup.enter="addTodo">
<ul>
<li v-for="todo in todos">
<input type="checkbox" :checked="todo.done" @change="toggle({ todo })">
<label v-text="todo.text" @dblclick="editing = true"></label>
</li>
</ul>
<nuxt-link to="/">Home</nuxt-link>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
computed: {
todos () { return this.$store.state.todos.list }
},
methods: {
addTodo (e) {
var text = e.target.value
if (text.trim()) {
this.$store.commit('todos/add', { text })
}
e.target.value = ''
},
...mapMutations({
toggle: 'todos/toggle'
})
}
}
</script>
<style>
li {
list-style: none;
}
</style>

View File

@ -0,0 +1,7 @@
export const state = { counter: 0 }
export const mutations = {
increment (state) {
state.counter++
}
}

View File

@ -0,0 +1,20 @@
export const state = {
list: []
}
export const mutations = {
add (state, { text }) {
state.list.push({
text,
done: false
})
},
delete (state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1)
},
toggle (state, { todo }) {
todo.done = !todo.done
}
}

View File

@ -4,7 +4,7 @@ require('es6-object-assign').polyfill()
import Vue from 'vue'
import Meta from 'vue-meta'
import router from './router.js'
<% if (store) { %>import store from '~store/index.js'<% } %>
<% if (store) { %>import store from './store.js'<% } %>
import NuxtChild from './components/nuxt-child.js'
import NuxtLink from './components/nuxt-link.js'
import Nuxt from './components/nuxt.vue'

47
lib/app/store.js Normal file
View File

@ -0,0 +1,47 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let files
let filenames = []
try {
files = require.context('~store', false, /^\.\/.*\.js$/)
filenames = files.keys()
} catch (e) {
console.warn('Nuxt.js store:', e.message)
}
function getModule (filename) {
let file = files(filename)
return file.default
? file.default
: file
}
let store
let storeData = {}
// Check if store/index.js returns a vuex store
if (filenames.indexOf('./index.js') !== -1) {
let mainModule = getModule('./index.js')
if (mainModule.commit) {
store = mainModule
} else {
storeData = mainModule
}
}
// Generate the store if there is no store yet
if (store == null) {
storeData.modules = storeData.modules || {}
for (let filename of filenames) {
let name = filename.replace(/^\.\//, '').replace(/\.js$/, '')
if (name === 'index') continue
storeData.modules[name] = getModule(filename)
storeData.modules[name].namespaced = true
}
store = new Vuex.Store(storeData)
}
export default store

View File

@ -191,6 +191,10 @@ function * generateRoutesAndFiles () {
templatesFiles.push('layouts/default.vue')
layouts.default = r(__dirname, 'app', 'layouts', 'default.vue')
}
// Add store if needed
if (this.options.store) {
templatesFiles.push('store.js')
}
let moveTemplates = templatesFiles.map((file) => {
return readFile(r(__dirname, 'app', file), 'utf8')
.then((fileContent) => {

View File

@ -51,7 +51,7 @@ class Nuxt {
this.dir = (typeof options.rootDir === 'string' && options.rootDir ? options.rootDir : process.cwd())
this.srcDir = (typeof options.srcDir === 'string' && options.srcDir ? resolve(this.dir, options.srcDir) : this.dir)
// If store defined, update store options to true
if (fs.existsSync(join(this.srcDir, 'store', 'index.js'))) {
if (fs.existsSync(join(this.srcDir, 'store'))) {
this.options.store = true
}
// Template