瀏覽代碼

Merge branch 'dev' into 4.0

Kia Ishii 5 年之前
父節點
當前提交
d3593a2461

+ 6 - 4
dist/logger.d.ts

@@ -1,7 +1,5 @@
-/**
- * Types for the logger plugin.
- * This file must be put alongside the JavaScript file of the logger.
- */
+// Types for the logger plugin. This file must be put alongside the bundled
+// JavaScript file of the logger.
 
 import { Payload, Plugin } from "../types/index";
 
@@ -10,6 +8,10 @@ export interface LoggerOption<S> {
   filter?: <P extends Payload>(mutation: P, stateBefore: S, stateAfter: S) => boolean;
   transformer?: (state: S) => any;
   mutationTransformer?: <P extends Payload>(mutation: P) => any;
+  actionFilter?: <P extends Payload>(action: P, state: S) => boolean;
+  actionTransformer?: <P extends Payload>(action: P) => any;
+  logMutations?: boolean;
+  logActions?: boolean;
 }
 
 export default function createLogger<S>(option?: LoggerOption<S>): Plugin<S>;

+ 19 - 8
docs/api/README.md

@@ -109,7 +109,7 @@ const store = new Vuex.Store({ ...options })
 
 ### strict
 
-- type: `Boolean`
+- type: `boolean`
 - default: `false`
 
   Force the Vuex store into strict mode. In strict mode any mutations to Vuex state outside of mutation handlers will throw an Error.
@@ -118,7 +118,7 @@ const store = new Vuex.Store({ ...options })
 
 ### devtools
 
-- type: `Boolean`
+- type: `boolean`
 
   Turn the devtools on or off for a particular vuex instance.  For instance passing false tells the Vuex store to not subscribe to devtools plugin.  Useful for if you have multiple stores on a single page.
 
@@ -128,7 +128,6 @@ const store = new Vuex.Store({ ...options })
   }
   ```
 
-
 ## Vuex.Store Instance Properties
 
 ### state
@@ -154,8 +153,8 @@ const store = new Vuex.Store({ ...options })
 
 ### dispatch
 
--  `dispatch(type: string, payload?: any, options?: Object)`
--  `dispatch(action: Object, options?: Object)`
+-  `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
+-  `dispatch(action: Object, options?: Object): Promise<any>`
 
   Dispatch an action. `options` can have `root: true` that allows to dispatch root actions in [namespaced modules](../guide/modules.md#namespacing). Returns a Promise that resolves all triggered action handlers. [Details](../guide/actions.md)
 
@@ -175,7 +174,7 @@ const store = new Vuex.Store({ ...options })
 
 ### subscribe
 
--  `subscribe(handler: Function): Function`
+-  `subscribe(handler: Function, options?: Object): Function`
 
   Subscribe to store mutations. The `handler` is called after every mutation and receives the mutation descriptor and post-mutation state as arguments:
 
@@ -186,13 +185,19 @@ const store = new Vuex.Store({ ...options })
   })
   ```
 
+  By default, new handler is added to the end of the chain, so it will be executed after other handlers that were added before. This can be overriden by adding `prepend: true` to `options`, which will add the handler to the beginning of the chain.
+
+  ``` js
+  store.subscribe(handler, { prepend: true })
+  ```
+
   To stop subscribing, call the returned unsubscribe function.
 
   Most commonly used in plugins. [Details](../guide/plugins.md)
 
 ### subscribeAction
 
--  `subscribeAction(handler: Function): Function`
+-  `subscribeAction(handler: Function, options?: Object): Function`
 
   > New in 2.5.0
 
@@ -205,6 +210,12 @@ const store = new Vuex.Store({ ...options })
   })
   ```
 
+  By default, new handler is added to the end of the chain, so it will be executed after other handlers that were added before. This can be overriden by adding `prepend: true` to `options`, which will add the handler to the beginning of the chain.
+
+  ``` js
+  store.subscribe(handler, { prepend: true })
+  ```
+
   To stop subscribing, call the returned unsubscribe function.
 
   > New in 3.1.0
@@ -240,7 +251,7 @@ const store = new Vuex.Store({ ...options })
 
 ### hasModule
 
-- `hasModule(path: string | Array<string>)`
+- `hasModule(path: string | Array<string>): boolean`
 
   Check if the module with the given name is already registered. [Details](../guide/modules.md#dynamic-module-registration)
 

+ 3 - 3
docs/fr/api/README.md

@@ -107,7 +107,7 @@ const store = new Vuex.Store({ ...options })
 
 ### strict
 
-  - type : `Boolean`
+  - type : `boolean`
   - default: `false`
 
     Force le store Vuex en mode strict. En mode strict, toute mutation de l'état en dehors des gestionnaires de mutation lancera une erreur.
@@ -139,8 +139,8 @@ const store = new Vuex.Store({ ...options })
 
 ### dispatch
 
--  `dispatch(type: string, payload?: any, options?: Object)`
--  `dispatch(action: Object, options?: Object)`
+-  `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
+-  `dispatch(action: Object, options?: Object): Promise<any>`
 
   Propager une action. Retourne la valeur renvoyée par le gestionnaire d'action déclenché, ou une Promesse si plusieurs gestionnaires ont été déclenchés. [Plus de détails](../guide/actions.md)
 

+ 3 - 1
docs/fr/guide/README.md

@@ -10,7 +10,9 @@ Au cœur de chaque application Vuex, il y a la **zone de stockage (« store »)*
 
 ### Le store le plus simple
 
-> **NOTE:** Nous allons utiliser la syntaxe ES2015 dans les exemples de code pour le reste de la documentation. Si vous ne vous êtes pas encore penché dessus, [vous devriez](https://babeljs.io/docs/learn-es2015/) !
+:::tip NOTE
+Nous allons utiliser la syntaxe ES2015 dans les exemples de code pour le reste de la documentation. Si vous ne vous êtes pas encore penché dessus, [vous devriez](https://babeljs.io/docs/learn-es2015/) !
+:::
 
 Après [avoir installé](../installation.md) Vuex, nous allons créer un store. C'est assez simple ; définissez juste un objet d'état initial et quelques mutations :
 

+ 1 - 1
docs/fr/guide/mutations.md

@@ -88,7 +88,7 @@ Puisqu'un état de store de Vuex est rendu réactif par Vue, lorsque nous mutons
 
   - Utiliser `Vue.set(obj, 'newProp', 123)`, ou
 
-  - Remplacer cet objet par un nouvel objet. Par exemple, en utilisant [opérateur de décomposition](https://github.com/tc39/proposal-object-rest-spread), il est possible d'écrire :
+  - Remplacer cet objet par un nouvel objet. Par exemple, en utilisant l'[opérateur de décomposition](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Op%C3%A9rateurs/Syntaxe_d%C3%A9composition#Utiliser_la_d%C3%A9composition_avec_les_litt%C3%A9raux_objet) (stage-4), il est possible d'écrire :
 
     ``` js
     state.obj = { ...state.obj, newProp: 123 }

+ 1 - 1
docs/fr/guide/state.md

@@ -10,7 +10,7 @@ L'arbre d'état unique n'entre pas en conflit avec la modularité. Dans les proc
 
 ### Récupération d'état Vuex dans des composants Vue
 
-Alors, comment affichons-nous l'état du store dans nos composants Vue ? Puisque les stores Vuex sont réactifs, la façon la plus simple d'y « récupérer » l'état est tout simplement de retourner une partie de l'état depuis une [une propriété calculée](https://fr.vuejs.org/guide/computed.html) :
+Alors, comment affichons-nous l'état du store dans nos composants Vue ? Puisque les stores Vuex sont réactifs, la façon la plus simple d'y « récupérer » l'état est tout simplement de retourner une partie de l'état depuis une [propriété calculée](https://fr.vuejs.org/guide/computed.html) :
 
 ``` js
 // créons un composant Counter

+ 1 - 3
docs/fr/guide/testing.md

@@ -97,9 +97,7 @@ const testAction = (action, args, state, expectedMutations, done) => {
 
     try {
       expect(mutation.type).to.equal(type)
-      if (payload) {
-        expect(payload).to.deep.equal(mutation.payload)
-      }
+      expect(payload).to.deep.equal(mutation.payload)
     } catch (error) {
       done(error)
     }

+ 38 - 2
docs/guide/README.md

@@ -10,12 +10,17 @@ At the center of every Vuex application is the **store**. A "store" is basically
 
 ### The Simplest Store
 
-> **NOTE:** We will be using ES2015 syntax for code examples for the rest of the docs. If you haven't picked it up, [you should](https://babeljs.io/docs/learn-es2015/)!
+:::tip NOTE
+We will be using ES2015 syntax for code examples for the rest of the docs. If you haven't picked it up, [you should](https://babeljs.io/docs/learn-es2015/)!
+:::
 
 After [installing](../installation.md) Vuex, let's create a store. It is pretty straightforward - just provide an initial state object, and some mutations:
 
 ``` js
-// Make sure to call Vue.use(Vuex) first if using a module system
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
 
 const store = new Vuex.Store({
   state: {
@@ -37,6 +42,37 @@ store.commit('increment')
 console.log(store.state.count) // -> 1
 ```
 
+In order to have an access to `this.$store` property in your Vue components, you need to provide the created store to Vue instance. Vuex has a mechanism to "inject" the store into all child components from the root component with the `store` option:
+
+``` js
+new Vue({
+  el: '#app',
+  store: store,
+})
+```
+
+:::tip
+If you're using ES6, you can also go for ES6 object property shorthand notation (it's used when object key has the same name as the variable passed-in as a property):
+
+```js
+new Vue({
+  el: '#app',
+  store
+})
+```
+:::
+
+Now we can commit a mutation from component's method:
+
+``` js
+methods: {
+  increment() {
+    this.$store.commit('increment')
+    console.log(this.$store.state.count)
+  }
+}
+```
+
 Again, the reason we are committing a mutation instead of changing `store.state.count` directly, is because we want to explicitly track it. This simple convention makes your intention more explicit, so that you can reason about state changes in your app better when reading the code. In addition, this gives us the opportunity to implement tools that can log every mutation, take state snapshots, or even perform time travel debugging.
 
 Using store state in a component simply involves returning the state within a computed property, because the store state is reactive. Triggering changes simply means committing mutations in component methods.

+ 11 - 0
docs/guide/plugins.md

@@ -109,6 +109,11 @@ const logger = createLogger({
     // `mutation` is a `{ type, payload }`
     return mutation.type !== "aBlacklistedMutation"
   },
+  actionFilter (action, state) {
+    // same as `filter` but for actions
+    // `action` is a `{ type, payload }`
+    return action.type !== "aBlacklistedAction"
+  },
   transformer (state) {
     // transform the state before logging it.
     // for example return only a specific sub-tree
@@ -119,6 +124,12 @@ const logger = createLogger({
     // we can format it any way we want.
     return mutation.type
   },
+  actionTransformer (action) {
+    // Same as mutationTransformer but for actions
+    return action.type
+  },
+  logActions: true, // Log Actions
+  logMutations: true, // Log mutations
   logger: console, // implementation of the `console` API, default `console`
 })
 ```

+ 1 - 3
docs/guide/testing.md

@@ -97,9 +97,7 @@ const testAction = (action, payload, state, expectedMutations, done) => {
 
     try {
       expect(type).to.equal(mutation.type)
-      if (payload) {
-        expect(payload).to.deep.equal(mutation.payload)
-      }
+      expect(payload).to.deep.equal(mutation.payload)
     } catch (error) {
       done(error)
     }

+ 22 - 16
docs/ja/api/README.md

@@ -147,27 +147,27 @@ const store = new Vuex.Store({ ...options })
 
 ### commit
 
-- **`commit(type: string, payload?: any, options?: Object)`**
-- **`commit(mutation: Object, options?: Object)`**
+- `commit(type: string, payload?: any, options?: Object)`
+- `commit(mutation: Object, options?: Object)`
 
   ミューテーションをコミットします。`options` は[名前空間付きモジュール](../guide/modules.md#名前空間)で root なミューテーションにコミットできる `root: true` を持つことできます。[詳細](../guide/mutations.md)
 
 ### dispatch
 
-- **`dispatch(type: string, payload?: any, options?: Object)`**
-- **`dispatch(action: Object, options?: Object)`**
+- `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
+- `dispatch(action: Object, options?: Object): Promise<any>`
 
   アクションをディスパッチします。`options` は[名前空間付きモジュール](../guide/modules.md#名前空間)で root なアクションにディスパッチできる `root: true` を持つことできます。 すべてのトリガーされたアクションハンドラを解決するPromiseを返します。[詳細](../guide/actions.md)
 
 ### replaceState
 
-- **`replaceState(state: Object)`**
+- `replaceState(state: Object)`
 
   ストアのルートステートを置き換えます。これは、ステートのハイドレーションやタイムトラベルのためだけに利用すべきです。
 
 ### watch
 
-- **`watch(fn: Function, callback: Function, options?: Object): Function`**
+- `watch(fn: Function, callback: Function, options?: Object): Function`
 
   `fn`が返す値をリアクティブに監視し、値が変わった時にコールバックを呼びます。`fn`は最初の引数としてストアのステートを、2番目の引数としてゲッターを受け取ります。 [Vue の`vm.$watch`メソッド](https://jp.vuejs.org/v2/api/#watch)と同じオプションをオプションのオブジェクトとして受け付けます。
 
@@ -175,7 +175,7 @@ const store = new Vuex.Store({ ...options })
 
 ### subscribe
 
-- **`subscribe(handler: Function): Function`**
+- `subscribe(handler: Function): Function`
 
   ストアへのミューテーションを購読します。`handler` は、全てのミューテーションの後に呼ばれ、引数として、ミューテーション ディスクリプタとミューテーション後の状態を受け取ります。
 
@@ -192,7 +192,7 @@ const store = new Vuex.Store({ ...options })
 
 ### subscribeAction
 
-- **`subscribeAction(handler: Function)`**
+- `subscribeAction(handler: Function)`
 
   > 2.5.0 で新規追加
 
@@ -226,7 +226,7 @@ const store = new Vuex.Store({ ...options })
 
 ### registerModule
 
-- **`registerModule(path: string | Array<string>, module: Module, options?: Object)`**
+- `registerModule(path: string | Array<string>, module: Module, options?: Object)`
 
   動的なモジュールを登録します。[詳細](../guide/modules.md#dynamic-module-registration)
 
@@ -234,13 +234,19 @@ const store = new Vuex.Store({ ...options })
 
 ### unregisterModule
 
-- **`unregisterModule(path: string | Array<string>)`**
+- `unregisterModule(path: string | Array<string>)`
 
   動的なモジュールを解除します。[詳細](../guide/modules.md#dynamic-module-registration)
 
+### hasModule
+
+- `hasModule(path: string | Array<string>): boolean`
+
+  動的なモジュールがすでに登録されているかどうかを確認します。[詳細](../guide/modules.md#dynamic-module-registration)
+
 ### hotUpdate
 
-- **`hotUpdate(newOptions: Object)`**
+- `hotUpdate(newOptions: Object)`
 
   新しいアクションとミューテーションをホットスワップします。[詳細](../guide/hot-reload.md)
 
@@ -248,7 +254,7 @@ const store = new Vuex.Store({ ...options })
 
 ### mapState
 
-- **`mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`**
+- `mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`
 
   ストアのサブツリーを返すコンポーネントの computed オプションを作成します。[詳細](../guide/state.md#the-mapstate-helper)
 
@@ -258,7 +264,7 @@ const store = new Vuex.Store({ ...options })
 
 ### mapGetters
 
-- **`mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`**
+- `mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`
 
   ゲッターの評価後の値を返すコンポーネントの computed オプションを作成します。[詳細](../guide/getters.md#the-mapgetters-helper)
 
@@ -266,7 +272,7 @@ const store = new Vuex.Store({ ...options })
 
 ### mapActions
 
-- **`mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`**
+- `mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`
 
   アクションをディスパッチするコンポーネントの methods オプションを作成します。[詳細](../guide/actions.md#dispatching-actions-in-components)
 
@@ -276,7 +282,7 @@ const store = new Vuex.Store({ ...options })
 
 ### mapMutations
 
-- **`mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`**
+- `mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`
 
   ミューテーションをコミットするコンポーネントの methods オプションを作成します。[詳細](../guide/mutations.md#commiting-mutations-in-components)
 
@@ -286,6 +292,6 @@ const store = new Vuex.Store({ ...options })
 
 ### createNamespaceHelpers
 
-- **`createNamespacedHelpers(namespace: string): Object`**
+- `createNamespacedHelpers(namespace: string): Object`
 
   名前空間付けられたコンポーネントバインディングのヘルパーを作成します。返されるオブジェクトは指定された名前空間にバインドされた `mapState`、`mapGetters`、`mapActions` そして `mapMutations` が含まれます。[詳細はこちら](../guide/modules.md#binding-helpers-with-namespace)

+ 3 - 1
docs/ja/guide/README.md

@@ -10,7 +10,9 @@ Vuex アプリケーションの中心にあるものは**ストア**です。"
 
 ### シンプルなストア
 
-> **注意:** 私たちは、このドキュメントのコード例に ES2015 のシンタックスを利用しています。 もし触れたことがなければ、[ぜひ触れてください](https://babeljs.io/docs/learn-es2015/)!
+:::tip 注意
+私たちは、このドキュメントのコード例に ES2015 のシンタックスを利用しています。 もし触れたことがなければ、[ぜひ触れてください](https://babeljs.io/docs/learn-es2015/)!
+:::
 
 Vuex を[インストール](../installation.md) してから、ストアをつくってみましょう。Vuex ストアの作成は、とても簡単です。ストアオブジェクトの初期状態と、いくつかのミューテーションを準備するだけです。
 

+ 7 - 1
docs/ja/guide/modules.md

@@ -297,7 +297,13 @@ store.registerModule(['nested', 'myModule'], {
 
 `store.unregisterModule(moduleName)` を呼び出せば、動的に登録したモジュールを削除できます。ただしストア作成(store creation)の際に宣言された、静的なモジュールはこのメソッドで削除できないことに注意してください。
 
-サーバサイドレンダリングされたアプリケーションから状態を保持するなど、新しいモジュールを登録するときに、以前の状態を保持したい場合があります。`preserveState` オプション(`store.registerModule('a', module, { preserveState: true })`)でこれを実現できます。
+また、すでに動的なモジュールが登録されているかどうかを `store.hasModule(moduleName)` メソッドを使って確認することができます。
+
+#### ステートの保持
+
+サーバサイドレンダリングされたアプリケーションから状態を保持するなど、新しいモジュールを登録するときに、以前の状態を保持したい場合があります。`preserveState` オプション(`store.registerModule('a', module, { preserveState: true })`)でこれを実現できます。
+
+`preserveState: true` を設定した場合、モジュールを登録する際、アクション、ミューテーション、そしてゲッターは登録されますがステートは登録されません。これはステートがすでにモジュールに登録されていることを前提としており、ステートを上書きしないようにするためです。
 
 ### モジュールの再利用
 

+ 3 - 5
docs/ja/guide/testing.md

@@ -50,7 +50,7 @@ describe('mutations', () => {
 ```
 
 ### アクションのテスト
- 
+
 アクションは外部の API を呼び出す可能性があるため、ミューテーションのテストよりも少し注意が必要です。アクションをテストするとき、通常、いくつかの段階でモックを作る必要があります。例えば API 呼び出しをサービスとして抽象化し、そしてテストの内部ではそのサービスをモックにすることができます。簡単に依存関係をモック化するために、webpack と [inject-loader](https://github.com/plasticine/inject-loader) を使ってテストファイルをバンドルすることができます。
 
 非同期なアクションのテストの例:
@@ -96,9 +96,7 @@ const testAction = (action, payload, state, expectedMutations, done) => {
 
     try {
       expect(type).to.equal(mutation.type)
-      if (payload) {
-        expect(payload).to.deep.equal(mutation.payload)
-      }
+      expect(payload).to.deep.equal(mutation.payload)
     } catch (error) {
       done(error)
     }
@@ -233,7 +231,7 @@ mocha test-bundle.js
 1. `mocha-loader` をインストールする
 2. 上記 webpack 設定から `entry` を `'mocha-loader!babel-loader!./test.js'` に変更する
 3. 設定を使用して `webpack-dev-server` を開始する
-4. ブラウザで `localhost:8080/webpack-dev-server/test-bundle` を開く 
+4. ブラウザで `localhost:8080/webpack-dev-server/test-bundle` を開く
 
 #### Karma + karma-webpack を使ったブラウザでの実行
 

+ 3 - 3
docs/kr/api/README.md

@@ -109,7 +109,7 @@ const store = new Vuex.Store({ ...options })
 
 ### strict
 
-- 자료형: `Boolean`
+- 자료형: `boolean`
 - 기본값: `false`
 
   Vuex 저장소를 strict 모드로 변경합니다. strict 모드에서 변이 핸들러 외부의 Vuex 상태에 대한 임의의 변이는 오류를 발생시킵니다.
@@ -141,8 +141,8 @@ const store = new Vuex.Store({ ...options })
 
 ### dispatch
 
-- `dispatch(type: string, payload?: any, options?: Object)`
-- `dispatch(action: Object, options?: Object)`
+- `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
+- `dispatch(action: Object, options?: Object): Promise<any>`
 
   액션을 디스패치 합니다. `options` 에 `root:true` 를 포함하면 [네임스페이스 모듈](../guide/modules.md#네임스페이스) 의 root 액션에 디스패치를 허용합니다. 모든 트리거된 액션 핸들러를 처리하는 Promise를 반환합니다. [상세](../guide/actions.md)
 

+ 3 - 1
docs/kr/guide/README.md

@@ -9,7 +9,9 @@
 
 ### 가장 단순한 저장소
 
-> **참고:** 모든 예제는 ES2015 문법을 사용합니다. 사용하고 있지 않은 경우 [꼭 사용해야 합니다!](https://babeljs.io/docs/learn-es2015/)
+:::tip 참고
+모든 예제는 ES2015 문법을 사용합니다. 사용하고 있지 않은 경우 [꼭 사용해야 합니다!](https://babeljs.io/docs/learn-es2015/)
+:::
 
 Vuex를 [설치](../installation.md)한 후 저장소를 만들어 봅시다. 매우 간단합니다. 초기 상태 객체와 일부 변이를 제공하십시오.
 

+ 3 - 5
docs/kr/guide/testing.md

@@ -97,9 +97,7 @@ const testAction = (action, payload, state, expectedMutations, done) => {
 
     try {
       expect(type).to.equal(mutation.type)
-      if (payload) {
-        expect(payload).to.deep.equal(mutation.payload)
-      }
+      expect(payload).to.deep.equal(mutation.payload)
     } catch (error) {
       done(error)
     }
@@ -137,9 +135,9 @@ describe('actions', () => {
   it('getAllProducts', () => {
     const commit = sinon.spy()
     const state = {}
-    
+
     actions.getAllProducts({ commit, state })
-    
+
     expect(commit.args).to.deep.equal([
       ['REQUEST_PRODUCTS'],
       ['RECEIVE_PRODUCTS', { /* 모의 응답 */ }]

+ 4 - 5
docs/ptbr/api/README.md

@@ -109,7 +109,7 @@ const store = new Vuex.Store({ ...options })
 
 ### strict
 
-- type: `Boolean`
+- type: `boolean`
 - default: `false`
 
   Força o _store_ Vuex em modo estrito. No modo estrito, qualquer mutação ao estado do Vuex fora dos manipuladores de mutação acusará um erro.
@@ -118,7 +118,7 @@ const store = new Vuex.Store({ ...options })
 
 ### devtools
 
-- type: `Boolean`
+- type: `boolean`
 
   Ative ou desative as ferramentas de desenvolvedor para uma determinada instância vuex. Passar _false_ à instância diz ao _store_ Vuex para não se integrar ao _devtools_. Útil para quando se tem vários _stores_ em uma _single page_.
 
@@ -128,7 +128,6 @@ const store = new Vuex.Store({ ...options })
   }
   ```
 
-
 ## Vuex.Store Propriedades da Instância
 
 ### state
@@ -154,8 +153,8 @@ const store = new Vuex.Store({ ...options })
 
 ### dispatch
 
--  `dispatch(type: string, payload?: any, options?: Object)`
--  `dispatch(action: Object, options?: Object)`
+-  `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
+-  `dispatch(action: Object, options?: Object): Promise<any>`
 
   Despacha uma ação. _options_ pode ter _root: true_ que permite despachar ações para raiz em [módulos namespaced](../guide/modules.md#namespacing). Retorna um _Promise_ que resolve todos os manipuladores de ação acionados. [Detalhes](../guide/actions.md)
 

+ 3 - 1
docs/ptbr/guide/README.md

@@ -10,7 +10,9 @@ No centro de cada aplicação Vuex existe o **_store_**. Um "_store_" é basicam
 
 ### O Store Mais Simples 
 
-> **NOTA:** Vamos usar a sintaxe ES2015 para exemplos de código para o resto da documentação. Se você ainda não aprendeu como usá-la, [veja aqui](https://babeljs.io/docs/learn-es2015/)!
+:::tip NOTA
+Vamos usar a sintaxe ES2015 para exemplos de código para o resto da documentação. Se você ainda não aprendeu como usá-la, [veja aqui](https://babeljs.io/docs/learn-es2015/)!
+:::
 
 Após [instalar](../installation.md) o Vuex, vamos criar um _store_. É bem simples - basta fornecer um objeto de estado inicial, e algumas mutações:
 

+ 3 - 5
docs/ptbr/guide/testing.md

@@ -97,9 +97,7 @@ const testAction = (action, payload, state, expectedMutations, done) => {
 
     try {
       expect(type).to.equal(mutation.type)
-      if (payload) {
-        expect(payload).to.deep.equal(mutation.payload)
-      }
+      expect(payload).to.deep.equal(mutation.payload)
     } catch (error) {
       done(error)
     }
@@ -137,9 +135,9 @@ describe('actions', () => {
   it('getAllProducts', () => {
     const commit = sinon.spy()
     const state = {}
-    
+
     actions.getAllProducts({ commit, state })
-    
+
     expect(commit.args).to.deep.equal([
       ['REQUEST_PRODUCTS'],
       ['RECEIVE_PRODUCTS', { /* resposta simulada */ }]

+ 8 - 8
docs/ru/api/README.md

@@ -109,7 +109,7 @@ const store = new Vuex.Store({ ...options });
 
 ### strict
 
-* тип: `Boolean`
+* тип: `boolean`
 * по умолчанию: `false`
 
   Форсирует использование «строгого режима» в хранилище Vuex. В нём любые изменения состояния, происходящие вне обработчиков мутаций, будут выбрасывать ошибки.
@@ -118,11 +118,11 @@ const store = new Vuex.Store({ ...options });
 
 ### devtools
 
-* тип: `Boolean`
+* тип: `boolean`
 
   Интеграция в devtools конкретного экземпляра Vuex. Например, передача `false` сообщает экземпляру хранилища Vuex, что не требуется подписываться на плагин devtools. Это будет полезно если у вас несколько хранилищ на одной странице.
-  
-  ``` js
+
+  ```js
   {
     devtools: false
   }
@@ -153,8 +153,8 @@ const store = new Vuex.Store({ ...options });
 
 ### dispatch
 
-* `dispatch(type: string, payload?: any, options?: Object)`
-* `dispatch(action: Object, options?: Object)`
+* `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
+* `dispatch(action: Object, options?: Object): Promise<any>`
 
 Запуск действия. `options` может содержать опцию `root: true` что позволяет запускать корневые (root) действия [в модулях со своим пространством имён](../guide/modules.md#пространства-имён). Возвращает Promise который разрешает все обработчики инициируемых действий. [Подробнее](../guide/actions.md)
 
@@ -210,7 +210,7 @@ store.subscribeAction((action, state) => {
 
 Начиная с версии 3.1.0, в `subscribeAction` также можно определять, должен ли обработчик вызываться *до* или *после* вызова действия (по умолчанию поведение *до*):
 
-``` js
+```js
 store.subscribeAction({
   before: (action, state) => {
     console.log(`before action ${action.type}`)
@@ -239,7 +239,7 @@ store.subscribeAction({
 
 ### hasModule
 
-* `hasModule(path: string | Array<string>)`
+* `hasModule(path: string | Array<string>): boolean`
 
 Проверка, не зарегистрирован ли уже модуль с заданным именем. [Подробнее](../guide/modules.md#динамическая-регистрация-модуnей)
 

+ 40 - 4
docs/ru/guide/README.md

@@ -10,12 +10,17 @@
 
 ### Простейшее хранилище
 
-> **ЗАМЕЧАНИЕ:** В примерах кода документации используется синтаксис ES2015. Если вы с ним ещё не знакомы, [сейчас самое время изучить](https://babeljs.io/docs/learn-es2015/)!
+:::tip ЗАМЕЧАНИЕ
+В примерах кода документации используется синтаксис ES2015. Если вы с ним ещё не знакомы, [сейчас самое время изучить](https://babeljs.io/docs/learn-es2015/)!
+:::
 
 После [установки](../installation.md) Vuex, давайте создадим хранилище. Это довольно просто — необходимо указать начальный объект состояния и некоторые мутации:
 
-``` js
-// Убедитесь, что вызвали Vue.use(Vuex) сначала, если используете систему сборки
+```js
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
 
 const store = new Vuex.Store({
   state: {
@@ -31,12 +36,43 @@ const store = new Vuex.Store({
 
 Теперь можно получить доступ к объекту состояния через `store.state` и вызвать изменение состояния с помощью метода `store.commit`:
 
-``` js
+```js
 store.commit('increment')
 
 console.log(store.state.count) // -> 1
 ```
 
+Чтобы получить доступ к хранилищу через свойство `this.$store` в компонентах Vue, необходимо установить созданное хранилище в экземпляр Vue. Vuex имеет механизм внедрения хранилища во все дочерние компоненты из корневого экземпляра с помощью опции `store`:
+
+```js
+new Vue({
+  el: '#app',
+  store: store,
+})
+```
+
+:::tip ПРИМЕЧАНИЕ
+Если используете синтаксис ES6, то можно использовать сокращённое обозначение свойства объекта ES6 (его можно использовать, когда ключ объекта имеет то же имя, что и переменная, передаваемая в свойство):
+
+```js
+new Vue({
+  el: '#app',
+  store
+})
+```
+:::
+
+Теперь можно совершить мутацию из метода компонента:
+
+```js
+methods: {
+  increment() {
+    this.$store.commit('increment')
+    console.log(this.$store.state.count)
+  }
+}
+```
+
 Запомните, причина, по которой мы вызываем мутацию вместо изменения `store.state.count` напрямую, в том, что мы хотим явным образом отслеживать её. Это простое соглашение делает наше намерение более явным, что упрощает понимание происходящих изменений состояния приложения при чтении кода. Кроме того, это позволяет использовать инструменты для отслеживания каждой мутации, создания снимков состояния или даже использования «машины времени» для отладки.
 
 Использование состояния хранилища в компоненте предполагает просто возврат необходимой части состояния в вычисляемом свойстве, поскольку состояние хранилища реактивно. Инициирование изменений — это просто запуск мутаций в методах компонентов.

+ 1 - 3
docs/ru/guide/testing.md

@@ -99,9 +99,7 @@ const testAction = (action, payload, state, expectedMutations, done) => {
 
     try {
       expect(type).to.equal(mutation.type);
-      if (payload) {
-        expect(payload).to.deep.equal(mutation.payload);
-      }
+      expect(payload).to.deep.equal(mutation.payload);
     } catch (error) {
       done(error);
     }

+ 12 - 4
docs/zh/api/README.md

@@ -111,7 +111,7 @@ const store = new Vuex.Store({ ...options })
 
 ### strict
 
-- 类型: `Boolean`
+- 类型: `boolean`
 - 默认值: `false`
 
   使 Vuex store 进入严格模式,在严格模式下,任何 mutation 处理函数以外修改 Vuex state 都会抛出错误。
@@ -120,7 +120,7 @@ const store = new Vuex.Store({ ...options })
 
 ### devtools
 
-- 类型:`Boolean`
+- 类型:`boolean`
 
   为某个特定的 Vuex 实例打开或关闭 devtools。对于传入 `false` 的实例来说 Vuex store 不会订阅到 devtools 插件。可用于一个页面中有多个 store 的情况。
 
@@ -155,8 +155,8 @@ const store = new Vuex.Store({ ...options })
 
 ### dispatch
 
-- `dispatch(type: string, payload?: any, options?: Object)`
-- `dispatch(action: Object, options?: Object)`
+- `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
+- `dispatch(action: Object, options?: Object): Promise<any>`
 
   分发 action。`options` 里可以有 `root: true`,它允许在[命名空间模块](../guide/modules.md#命名空间)里分发根的 action。返回一个解析所有被触发的 action 处理器的 Promise。[详细介绍](../guide/actions.md)
 
@@ -239,6 +239,14 @@ const store = new Vuex.Store({ ...options })
 
   卸载一个动态模块。[详细介绍](../guide/modules.md#模块动态注册)
 
+### hasModule
+
+- `hasModule(path: string | Array<string>): boolean`
+
+  检查该模块的名字是否已经被注册。[详细介绍](../guide/modules.md#模块动态注册)
+
+  > 3.2.0 新增
+
 ### hotUpdate
 
 - `hotUpdate(newOptions: Object)`

+ 36 - 2
docs/zh/guide/README.md

@@ -10,12 +10,15 @@
 
 ### 最简单的 Store
 
-> **提示:** 我们将在后续的文档示例代码中使用 ES2015 语法。如果你还没能掌握 ES2015,[你得抓紧了](https://babeljs.io/docs/learn-es2015/)!
+:::tip 提示
+我们将在后续的文档示例代码中使用 ES2015 语法。如果你还没能掌握 ES2015,[你得抓紧了](https://babeljs.io/docs/learn-es2015/)!
+:::
 
 [安装](../installation.md) Vuex 之后,让我们来创建一个 store。创建过程直截了当——仅需要提供一个初始 state 对象和一些 mutation:
 
 ``` js
-// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)
+import Vue from 'vue'
+import Vuex from 'vuex'
 
 const store = new Vuex.Store({
   state: {
@@ -37,6 +40,37 @@ store.commit('increment')
 console.log(store.state.count) // -> 1
 ```
 
+为了在 Vue 组件中访问 `this.$store` property,你需要为 Vue 实例提供创建好的 store。Vuex 提供了一个从根组件向所有子组件,以 `store` 选项的方式“注入”该 store 的机制:
+
+``` js
+new Vue({
+  el: '#app',
+  store: store,
+})
+```
+
+:::tip 提示
+如果使用 ES6,你也可以以 ES6 对象的 property 简写 (用在对象某个 property 的 key 和被传入的变量同名时):
+
+```js
+new Vue({
+  el: '#app',
+  store
+})
+```
+:::
+
+现在我们可以从组件的方法提交一个变更:
+
+``` js
+methods: {
+  increment() {
+    this.$store.commit('increment')
+    console.log(this.$store.state.count)
+  }
+}
+```
+
 再次强调,我们通过提交 mutation 的方式,而非直接改变 `store.state.count`,是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显,这样你在阅读代码的时候能更容易地解读应用内部的状态改变。此外,这样也让我们有机会去实现一些能记录每次状态改变,保存状态快照的调试工具。有了它,我们甚至可以实现如时间穿梭般的调试体验。
 
 由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的 methods 中提交 mutation。

+ 6 - 0
docs/zh/guide/modules.md

@@ -280,6 +280,10 @@ export function createPlugin (options = {}) {
 在 store 创建**之后**,你可以使用 `store.registerModule` 方法注册模块:
 
 ``` js
+import Vuex from 'vuex'
+
+const store = new Vuex.Store({ /* 选项 */ })
+
 // 注册模块 `myModule`
 store.registerModule('myModule', {
   // ...
@@ -296,6 +300,8 @@ store.registerModule(['nested', 'myModule'], {
 
 你也可以使用 `store.unregisterModule(moduleName)` 来动态卸载模块。注意,你不能使用此方法卸载静态模块(即创建 store 时声明的模块)。
 
+注意,你可以通过 `store.hasModule(moduleName)` 方法检查该模块是否已经被注册到 store。
+
 #### 保留 state
 
 在注册一个新 module 时,你很有可能想保留过去的 state,例如从一个服务端渲染的应用保留 state。你可以通过 `preserveState` 选项将其归档:`store.registerModule('a', module, { preserveState: true })`。

+ 1 - 1
docs/zh/guide/state.md

@@ -63,7 +63,7 @@ const Counter = {
 
 <div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c8Pz7BSK" target="_blank" rel="noopener noreferrer">在 Scrimba 上尝试这节课</a></div>
 
-当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 `mapState` 辅助函数帮助我们生成计算属性,让你少按几次键:
+当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 `mapState` 辅助函数帮助我们生成计算属性,让你少按几次键:
 
 ``` js
 // 在单独构建的版本中辅助函数为 Vuex.mapState

+ 3 - 5
docs/zh/guide/testing.md

@@ -96,9 +96,7 @@ const testAction = (action, args, state, expectedMutations, done) => {
 
     try {
       expect(mutation.type).to.equal(type)
-      if (payload) {
-        expect(mutation.payload).to.deep.equal(payload)
-      }
+      expect(mutation.payload).to.deep.equal(payload)
     } catch (error) {
       done(error)
     }
@@ -136,9 +134,9 @@ describe('actions', () => {
   it('getAllProducts', () => {
     const commit = sinon.spy()
     const state = {}
-    
+
     actions.getAllProducts({ commit, state })
-    
+
     expect(commit.args).to.deep.equal([
       ['REQUEST_PRODUCTS'],
       ['RECEIVE_PRODUCTS', { /* mocked response */ }]

+ 5 - 1
src/plugins/devtool.js

@@ -18,5 +18,9 @@ export default function devtoolPlugin (store) {
 
   store.subscribe((mutation, state) => {
     devtoolHook.emit('vuex:mutation', mutation, state)
-  })
+  }, { prepend: true })
+
+  store.subscribeAction((action, state) => {
+    devtoolHook.emit('vuex:action', action, state)
+  }, { prepend: true })
 }

+ 62 - 30
src/plugins/logger.js

@@ -7,49 +7,81 @@ export default function createLogger ({
   filter = (mutation, stateBefore, stateAfter) => true,
   transformer = state => state,
   mutationTransformer = mut => mut,
+  actionFilter = (action, state) => true,
+  actionTransformer = act => act,
+  logMutations = true,
+  logActions = true,
   logger = console
 } = {}) {
   return store => {
     let prevState = deepCopy(store.state)
 
-    store.subscribe((mutation, state) => {
-      if (typeof logger === 'undefined') {
-        return
-      }
-      const nextState = deepCopy(state)
-
-      if (filter(mutation, prevState, nextState)) {
-        const time = new Date()
-        const formattedTime = ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`
-        const formattedMutation = mutationTransformer(mutation)
-        const message = `mutation ${mutation.type}${formattedTime}`
-        const startMessage = collapsed
-          ? logger.groupCollapsed
-          : logger.group
-
-        // render
-        try {
-          startMessage.call(logger, message)
-        } catch (e) {
-          console.log(message)
+    if (typeof logger === 'undefined') {
+      return
+    }
+
+    if (logMutations) {
+      store.subscribe((mutation, state) => {
+        const nextState = deepCopy(state)
+
+        if (filter(mutation, prevState, nextState)) {
+          const formattedTime = getFormattedTime()
+          const formattedMutation = mutationTransformer(mutation)
+          const message = `mutation ${mutation.type}${formattedTime}`
+
+          startMessage(logger, message, collapsed)
+          logger.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState))
+          logger.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation)
+          logger.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState))
+          endMessage(logger)
         }
 
-        logger.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState))
-        logger.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation)
-        logger.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState))
+        prevState = nextState
+      })
+    }
 
-        try {
-          logger.groupEnd()
-        } catch (e) {
-          logger.log('—— log end ——')
+    if (logActions) {
+      store.subscribeAction((action, state) => {
+        if (actionFilter(action, state)) {
+          const formattedTime = getFormattedTime()
+          const formattedAction = actionTransformer(action)
+          const message = `action ${action.type}${formattedTime}`
+
+          startMessage(logger, message, collapsed)
+          logger.log('%c action', 'color: #03A9F4; font-weight: bold', formattedAction)
+          endMessage(logger)
         }
-      }
+      })
+    }
+  }
+}
 
-      prevState = nextState
-    })
+function startMessage (logger, message, collapsed) {
+  const startMessage = collapsed
+    ? logger.groupCollapsed
+    : logger.group
+
+  // render
+  try {
+    startMessage.call(logger, message)
+  } catch (e) {
+    logger.log(message)
+  }
+}
+
+function endMessage (logger) {
+  try {
+    logger.groupEnd()
+  } catch (e) {
+    logger.log('—— log end ——')
   }
 }
 
+function getFormattedTime () {
+  const time = new Date()
+  return ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`
+}
+
 function repeat (str, times) {
   return (new Array(times + 1)).join(str)
 }

+ 8 - 6
src/store.js

@@ -162,13 +162,13 @@ export class Store {
     })
   }
 
-  subscribe (fn) {
-    return genericSubscribe(fn, this._subscribers)
+  subscribe (fn, options) {
+    return genericSubscribe(fn, this._subscribers, options)
   }
 
-  subscribeAction (fn) {
+  subscribeAction (fn, options) {
     const subs = typeof fn === 'function' ? { before: fn } : fn
-    return genericSubscribe(subs, this._actionSubscribers)
+    return genericSubscribe(subs, this._actionSubscribers, options)
   }
 
   watch (getter, cb, options) {
@@ -236,9 +236,11 @@ export class Store {
   }
 }
 
-function genericSubscribe (fn, subs) {
+function genericSubscribe (fn, subs, options) {
   if (subs.indexOf(fn) < 0) {
-    subs.push(fn)
+    options && options.prepend
+      ? subs.unshift(fn)
+      : subs.push(fn)
   }
   return () => {
     const i = subs.indexOf(fn)

+ 1 - 0
types/index.d.ts

@@ -100,6 +100,7 @@ export interface StoreOptions<S> {
   modules?: ModuleTree<S>;
   plugins?: Plugin<S>[];
   strict?: boolean;
+  devtools?: boolean;
 }
 
 export type ActionHandler<S, R> = (this: Store<R>, injectee: ActionContext<S, R>, payload?: any) => any;

+ 2 - 1
types/test/index.ts

@@ -95,7 +95,8 @@ namespace RootModule {
     mutations: {
       bar (state, payload) {}
     },
-    strict: true
+    strict: true,
+    devtools: true
   });
 }