浏览代码

Merge branch 'dev' into 4.0

Kia Ishii 5 年之前
父节点
当前提交
0dddb47d3b

+ 91 - 0
.github/commit-convention.md

@@ -0,0 +1,91 @@
+## Git Commit Message Convention
+
+> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).
+
+#### TL;DR:
+
+Messages must be matched by the following regex:
+
+``` js
+/^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\(.+\))?: .{1,50}/
+```
+
+#### Examples
+
+Appears under "Features" header, `store` subheader:
+
+```
+feat(store): add 'watch' option
+```
+
+Appears under "Bug Fixes" header, `module` subheader, with a link to issue #28:
+
+```
+fix(module): handle state overwrite
+
+close #28
+```
+
+Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
+
+```
+perf: improve store getters performance by removing 'foo' option
+
+BREAKING CHANGE: The 'foo' option has been removed.
+```
+
+The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
+
+```
+revert: feat(store): add 'watch' option
+
+This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
+```
+
+### Full Message Format
+
+A commit message consists of a **header**, **body** and **footer**.  The header has a **type**, **scope** and **subject**:
+
+```
+<type>(<scope>): <subject>
+<BLANK LINE>
+<body>
+<BLANK LINE>
+<footer>
+```
+
+The **header** is mandatory and the **scope** of the header is optional.
+
+### Revert
+
+If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
+
+### Type
+
+If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
+
+Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
+
+### Scope
+
+The scope could be anything specifying the place of the commit change. For example `core`, `compiler`, `ssr`, `v-model`, `transition` etc...
+
+### Subject
+
+The subject contains a succinct description of the change:
+
+* use the imperative, present tense: "change" not "changed" nor "changes"
+* don't capitalize the first letter
+* no dot (.) at the end
+
+### Body
+
+Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
+The body should include the motivation for the change and contrast this with previous behavior.
+
+### Footer
+
+The footer should contain any information about **Breaking Changes** and is also the place to
+reference GitHub issues that this commit **Closes**.
+
+**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.

+ 35 - 0
.github/contributing.md

@@ -0,0 +1,35 @@
+# Vuex Contributing Guide
+
+Hi! We're really excited that you are interested in contributing to Vuex. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:
+
+- [Code of Conduct](https://github.com/vuejs/vue/blob/dev/.github/CODE_OF_CONDUCT.md)
+- [Issue Reporting Guidelines](#issue-reporting-guidelines)
+- [Pull Request Guidelines](#pull-request-guidelines)
+
+## Issue Reporting Guidelines
+
+- Always use [https://new-issue.vuejs.org/](https://new-issue.vuejs.org/) to create new issues.
+
+## Pull Request Guidelines
+
+- The `master` branch is just a snapshot of the latest stable release. All development should be done in dedicated branches. **Do not submit PRs against the `master` branch.**
+
+- Checkout a topic branch from the relevant branch, e.g. `dev`, and merge back against that branch.
+
+- Work in the `src` folder and **DO NOT** checkin `dist` in the commits.
+
+- If adding a new feature:
+
+  - Add accompanying test case.
+  - Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
+
+- If fixing bug:
+
+  - If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update state re-evaluation (fix #3899)`.
+  - Provide a detailed description of the bug in the PR. Live demo preferred.
+
+- It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging.
+
+- Make sure tests pass!
+
+- Commit messages must follow the [commit message convention](./commit-convention.md) so that changelogs can be automatically generated.

+ 289 - 0
CHANGELOG.md

@@ -0,0 +1,289 @@
+# [3.2.0](https://github.com/vuejs/vuex/compare/v3.1.3...v3.2.0) (2020-04-19)
+
+
+### Features
+
+* add Store#hasModule(path) API ([#834](https://github.com/vuejs/vuex/issues/834)) ([d65d142](https://github.com/vuejs/vuex/commit/d65d14276e87aca17cfbd3fbf4af9e8dbb808f24))
+
+
+
+## [3.1.3](https://github.com/vuejs/vuex/compare/v3.1.2...v3.1.3) (2020-03-09)
+
+
+### Bug Fixes
+
+* Prevent invalidating subscription iterator  ([#1438](https://github.com/vuejs/vuex/issues/1438)) ([e012653](https://github.com/vuejs/vuex/commit/e0126533301febf66072f1865cf9a77778cf2176))
+
+
+
+## [3.1.2](https://github.com/vuejs/vuex/compare/v3.1.1...v3.1.2) (2019-11-10)
+
+
+### Bug Fixes
+
+* tweak mapping helper warning message ([#1641](https://github.com/vuejs/vuex/issues/1641)) ([e60bc76](https://github.com/vuejs/vuex/commit/e60bc76154bb05c12b24342617b946d9a6e2f476))
+* **types:** avoid broadening vue instance type when using map helpers ([#1639](https://github.com/vuejs/vuex/issues/1639)) ([9a96720](https://github.com/vuejs/vuex/commit/9a9672050bcfee198c379069ec0e1b03ca6cb965))
+* add warnings when the different namespaced modules has the same names… ([#1554](https://github.com/vuejs/vuex/issues/1554)) ([91f3e69](https://github.com/vuejs/vuex/commit/91f3e69ed9e290cf91f8885c6d5ae2c97fa7ab81))
+* Should vuex mapState print error message [#1093](https://github.com/vuejs/vuex/issues/1093) ([#1297](https://github.com/vuejs/vuex/issues/1297)) ([e5ca2d5](https://github.com/vuejs/vuex/commit/e5ca2d52e89a126bd48bd8a6003be77379960ea9))
+* Warn about conflicts between state and module ([#1365](https://github.com/vuejs/vuex/issues/1365)) ([538ee58](https://github.com/vuejs/vuex/commit/538ee5803bbca2fc8077208fb30c8d56d8be5cae))
+* **docs:** Clearify state object type ([#1601](https://github.com/vuejs/vuex/issues/1601)) ([de06f76](https://github.com/vuejs/vuex/commit/de06f76380e7429489c0eb15acc8e0b34a383860))
+
+
+### Performance Improvements
+
+* Implementing a cache for the gettersProxy object creation ([#1546](https://github.com/vuejs/vuex/issues/1546)) ([4003382](https://github.com/vuejs/vuex/commit/40033825b7259c2e9b702bdf94e0b24ed4511d7c))
+
+
+
+## [3.1.1](https://github.com/vuejs/vuex/compare/v3.1.0...v3.1.1) (2019-05-08)
+
+
+### Bug Fixes
+
+* Memory leak happening while using registerModule/u… ([#1508](https://github.com/vuejs/vuex/issues/1508)) ([cb9986a](https://github.com/vuejs/vuex/commit/cb9986ae5a62e002a1d876e881ee5f31dd410888)), closes [issue#1507](https://github.com/issue/issues/1507)
+* **types:** Make mutation and action payload optional in definition file ([#1517](https://github.com/vuejs/vuex/issues/1517)) ([0e109e2](https://github.com/vuejs/vuex/commit/0e109e2a38dafdc0c2bd6bd3892bc66cfe252b16)), closes [#1491](https://github.com/vuejs/vuex/issues/1491)
+
+
+### Features
+
+* **devtool:** allow usage in non-browser environments ([#1404](https://github.com/vuejs/vuex/issues/1404)) ([665455f](https://github.com/vuejs/vuex/commit/665455f8daf8512e7adbf63c2842bc0b1e39efdb))
+* **esm build:** build ES modules for browser ([#1533](https://github.com/vuejs/vuex/issues/1533)) ([d7c7f98](https://github.com/vuejs/vuex/commit/d7c7f9844831f98c5c9aaca213746c4ccc5d6929))
+
+
+
+# [3.1.0](https://github.com/vuejs/vuex/compare/v3.0.1...v3.1.0) (2019-01-17)
+
+
+### Bug Fixes
+
+* **types:** add helpers to default export type declaration as in sources ([#1408](https://github.com/vuejs/vuex/issues/1408)) ([404d0de](https://github.com/vuejs/vuex/commit/404d0de9531322a1a462e53dfd858d20f0bd99af))
+* **types:** add type annotation for the context of actions ([#1322](https://github.com/vuejs/vuex/issues/1322)) ([d1b5c66](https://github.com/vuejs/vuex/commit/d1b5c66961ab53e0172cbc706ff616227bcb5c77))
+* **types:** allow a function type for root `state` option ([#1132](https://github.com/vuejs/vuex/issues/1132)) ([d39791b](https://github.com/vuejs/vuex/commit/d39791bd05830b1889705761ef5779449e35e97f))
+* Add key to v-for ([#1369](https://github.com/vuejs/vuex/issues/1369)) ([a9bd047](https://github.com/vuejs/vuex/commit/a9bd047ea147cacfcb4003946aeebccd2c5e1e4e))
+* avoid to call root state function twice ([#1034](https://github.com/vuejs/vuex/issues/1034)) ([86677eb](https://github.com/vuejs/vuex/commit/86677ebcbfaecf712f339b73a568150fc9fd5f5e))
+* fix [#1032](https://github.com/vuejs/vuex/issues/1032), relax vue typing in helpers ([#1044](https://github.com/vuejs/vuex/issues/1044)) ([7c7ed1d](https://github.com/vuejs/vuex/commit/7c7ed1d37ee8a5058082d763d80529e5fef86a0b))
+
+
+### Features
+
+* add ability to turn off devtools on vuex by passing an off options ([#1407](https://github.com/vuejs/vuex/issues/1407)) ([be75d41](https://github.com/vuejs/vuex/commit/be75d41cf54d50177a7db7e9218e8d1c820ae830))
+* ensure errors in action subscribers do not break actions ([acd7249](https://github.com/vuejs/vuex/commit/acd72492eaffff3661f75860a3d7ab37b73c3906))
+
+
+### Reverts
+
+* Revert "Update util find (#1205)" (fix #1286) ([273bf86](https://github.com/vuejs/vuex/commit/273bf86b330ee580a73176c300919996b7d9c2c3)), closes [#1286](https://github.com/vuejs/vuex/issues/1286)
+
+
+
+## [3.0.1](https://github.com/vuejs/vuex/compare/v3.0.0...v3.0.1) (2017-11-01)
+
+
+
+# [3.0.0](https://github.com/vuejs/vuex/compare/v2.5.0...v3.0.0) (2017-10-11)
+
+
+### Features
+
+* **typings:** adapt to the new Vue typings ([#909](https://github.com/vuejs/vuex/issues/909)) ([65dbfec](https://github.com/vuejs/vuex/commit/65dbfec40d5fe7aac05aab333c7b70768997ca7f))
+
+
+### BREAKING CHANGES
+
+* **typings:** It is no longer compatible with the old Vue typings
+
+* chore(package): bump typescript and vue core typings
+
+* chore: bump vue
+
+* Update package.json
+
+
+
+# [2.5.0](https://github.com/vuejs/vuex/compare/v2.4.1...v2.5.0) (2017-10-11)
+
+
+### Bug Fixes
+
+* initialize root state as an empty object if state function returns no value ([#927](https://github.com/vuejs/vuex/issues/927)) ([0e9756b](https://github.com/vuejs/vuex/commit/0e9756b93c5de8e03286d93f0b50af5f8dfd3bac))
+
+
+### Features
+
+* add logger plugin logger config support ([#771](https://github.com/vuejs/vuex/issues/771)) ([804c3bb](https://github.com/vuejs/vuex/commit/804c3bbd2e60f11412f5a7cb7694969f8f6c215c))
+* preserve state with registerModule ([#837](https://github.com/vuejs/vuex/issues/837)) ([4c1841e](https://github.com/vuejs/vuex/commit/4c1841e79e63ca0ca95d0cc1b218fde258f23c20))
+* root actions in namespaced modules ([#941](https://github.com/vuejs/vuex/issues/941)) ([73189eb](https://github.com/vuejs/vuex/commit/73189eb35509de7d49bd2b577900ad560d37dcb0))
+* subscribeAction ([#960](https://github.com/vuejs/vuex/issues/960)) ([a8326b1](https://github.com/vuejs/vuex/commit/a8326b1bd77158e7e5903eed4cc98b52599e3dbd))
+
+
+
+## [2.4.1](https://github.com/vuejs/vuex/compare/v2.4.0...v2.4.1) (2017-09-27)
+
+
+### Bug Fixes
+
+* allow installation on extended Vue copies ([c87b72f](https://github.com/vuejs/vuex/commit/c87b72f2ff7f65e708c4b59a752ef234d0f28d1f))
+* link to details of mutations in components ([#930](https://github.com/vuejs/vuex/issues/930)) ([e82782b](https://github.com/vuejs/vuex/commit/e82782ba81c398dd5b78a195257a9d1c3a6d85ef))
+* move auto installation code into the store constructor ([#914](https://github.com/vuejs/vuex/issues/914)) ([852ac43](https://github.com/vuejs/vuex/commit/852ac43ea4813ecaeb1e5106c4a29c74e57c2fd7))
+
+
+### Features
+
+* allow to passing functions in mapActions/mapMutations (fix [#750](https://github.com/vuejs/vuex/issues/750)) ([#924](https://github.com/vuejs/vuex/issues/924)) ([be15f32](https://github.com/vuejs/vuex/commit/be15f32c0077d8fe9bafa38c1b319b655cfd5f86))
+
+
+
+# [2.4.0](https://github.com/vuejs/vuex/compare/v2.3.0...v2.4.0) (2017-08-29)
+
+
+### Bug Fixes
+
+* **typings:** watch() returns an unwatch function ([#922](https://github.com/vuejs/vuex/issues/922)) ([a4bd081](https://github.com/vuejs/vuex/commit/a4bd0816838cc4a843d833363b9aa412c1256e5e))
+* add missing typings and docs of createNamespacedHelpers ([#910](https://github.com/vuejs/vuex/issues/910)) ([7ad573b](https://github.com/vuejs/vuex/commit/7ad573bba59d23dbd66e3a25e6614296aeb98d42))
+
+
+### Features
+
+* **store:** bind mutation and action handlers to store ([#872](https://github.com/vuejs/vuex/issues/872)) ([67da622](https://github.com/vuejs/vuex/commit/67da6225552e46266ed059c7f0d0128294cd08ed))
+
+
+### Performance Improvements
+
+* do not connect devtools if Vue.config.devtools == false ([#881](https://github.com/vuejs/vuex/issues/881)) ([dd7f817](https://github.com/vuejs/vuex/commit/dd7f8178d93e6121a447c410b9c652f40cd80937))
+
+
+
+# [2.3.0](https://github.com/vuejs/vuex/compare/v2.2.1...v2.3.0) (2017-04-13)
+
+
+* Add '-loader' suffix to webpack config (#722) ([84b4634](https://github.com/vuejs/vuex/commit/84b463438ea4133f7f326dc18212e3d4b7b5a177)), closes [#722](https://github.com/vuejs/vuex/issues/722)
+
+
+### BREAKING CHANGES
+
+* It's no longer allowed to omit the '-loader' suffix when using loaders. You need to specify 'babel-loader' instead of 'babel'.
+My version of webpack: 2.2.0-rc.3
+Adding the '-loader' suffix fixed the problem.
+Not sure though how safe it is to use 'babel-loader' instead of 'babel' with previous webpack versions...
+
+
+
+## [2.2.1](https://github.com/vuejs/vuex/compare/v2.2.0...v2.2.1) (2017-02-26)
+
+
+
+# [2.2.0](https://github.com/vuejs/vuex/compare/v2.1.2...v2.2.0) (2017-02-26)
+
+
+
+## [2.1.2](https://github.com/vuejs/vuex/compare/v2.1.1...v2.1.2) (2017-02-06)
+
+
+### Reverts
+
+* Revert "Update modules.md (#534)" ([5e145b3](https://github.com/vuejs/vuex/commit/5e145b3a2d45977b52cfff41b3b663f629d67e74)), closes [#534](https://github.com/vuejs/vuex/issues/534)
+
+
+
+## [2.1.1](https://github.com/vuejs/vuex/compare/v2.1.0...v2.1.1) (2016-12-17)
+
+
+
+# [2.1.0](https://github.com/vuejs/vuex/compare/v2.0.0...v2.1.0) (2016-12-16)
+
+
+
+# [2.0.0](https://github.com/vuejs/vuex/compare/v2.0.0-rc.6...v2.0.0) (2016-09-30)
+
+
+
+# [2.0.0-rc.6](https://github.com/vuejs/vuex/compare/v2.0.0-rc.5...v2.0.0-rc.6) (2016-09-24)
+
+
+
+# [2.0.0-rc.5](https://github.com/vuejs/vuex/compare/v2.0.0-rc.4...v2.0.0-rc.5) (2016-08-15)
+
+
+
+# [2.0.0-rc.4](https://github.com/vuejs/vuex/compare/v2.0.0-rc.3...v2.0.0-rc.4) (2016-08-05)
+
+
+
+# [2.0.0-rc.3](https://github.com/vuejs/vuex/compare/v2.0.0-rc.1...v2.0.0-rc.3) (2016-07-11)
+
+
+
+# [2.0.0-rc.1](https://github.com/vuejs/vuex/compare/v1.0.0-rc...v2.0.0-rc.1) (2016-07-05)
+
+
+
+# [1.0.0-rc](https://github.com/vuejs/vuex/compare/v0.8.2...v1.0.0-rc) (2016-07-01)
+
+
+
+## [0.8.2](https://github.com/vuejs/vuex/compare/v0.8.1...v0.8.2) (2016-06-28)
+
+
+
+## [0.8.1](https://github.com/vuejs/vuex/compare/v0.8.0...v0.8.1) (2016-06-28)
+
+
+
+# [0.8.0](https://github.com/vuejs/vuex/compare/v0.7.1...v0.8.0) (2016-06-23)
+
+
+
+## [0.7.1](https://github.com/vuejs/vuex/compare/v0.7.0...v0.7.1) (2016-06-22)
+
+
+
+# [0.7.0](https://github.com/vuejs/vuex/compare/v0.6.3...v0.7.0) (2016-06-21)
+
+
+
+## [0.6.3](https://github.com/vuejs/vuex/compare/v0.6.2...v0.6.3) (2016-04-23)
+
+
+
+## [0.6.2](https://github.com/vuejs/vuex/compare/v0.6.1...v0.6.2) (2016-03-08)
+
+
+
+## [0.6.1](https://github.com/vuejs/vuex/compare/v0.6.0...v0.6.1) (2016-03-07)
+
+
+
+# [0.6.0](https://github.com/vuejs/vuex/compare/v0.5.1...v0.6.0) (2016-03-07)
+
+
+
+## [0.5.1](https://github.com/vuejs/vuex/compare/v0.5.0...v0.5.1) (2016-03-04)
+
+
+
+# [0.5.0](https://github.com/vuejs/vuex/compare/v0.4.2...v0.5.0) (2016-03-04)
+
+
+
+## [0.4.2](https://github.com/vuejs/vuex/compare/v0.4.1...v0.4.2) (2016-03-02)
+
+
+
+## [0.4.1](https://github.com/vuejs/vuex/compare/v0.4.0...v0.4.1) (2016-03-01)
+
+
+
+# [0.4.0](https://github.com/vuejs/vuex/compare/v0.3.0...v0.4.0) (2016-03-01)
+
+
+
+# [0.3.0](https://github.com/vuejs/vuex/compare/4a22523b8cf4a1954ec95a0083ddef6c085f4905...v0.3.0) (2016-02-16)
+
+
+### Bug Fixes
+
+* **api:** fix typo ([4a22523](https://github.com/vuejs/vuex/commit/4a22523b8cf4a1954ec95a0083ddef6c085f4905))
+* **forms:** fix typo ([50094a6](https://github.com/vuejs/vuex/commit/50094a604f32d00ceb784a3fbf07c82c502faca2))
+
+
+

+ 10 - 2
build/release.sh

@@ -17,10 +17,18 @@ then
   # build
   VERSION=$VERSION npm run build
 
+  # generate the version so that the changelog can be generated too
+  yarn version --no-git-tag-version --no-commit-hooks --new-version $VERSION
+
+  # changelog
+  yarn changelog
+  echo "Please check the git history and the changelog and press enter"
+  read OKAY
+
   # commit
   git add -A
-  git commit -m "[build] $VERSION"
-  npm version $VERSION --message "[release] $VERSION"
+  git commit -m "realese: v$VERSION"
+  git tag "v$VERSION"
 
   # publish
   git push origin refs/tags/v$VERSION

+ 92 - 86
dist/vuex.common.js

@@ -1,35 +1,44 @@
 /**
- * vuex v4.0.0-alpha.1
+ * vuex v3.2.0
  * (c) 2020 Evan You
  * @license MIT
  */
 'use strict';
 
-var vue = require('vue');
+function applyMixin (Vue) {
+  var version = Number(Vue.version.split('.')[0]);
 
-var storeKey = 'store';
-
-function useStore (key) {
-  if ( key === void 0 ) key = null;
-
-  return vue.inject(key !== null ? key : storeKey)
-}
+  if (version >= 2) {
+    Vue.mixin({ beforeCreate: vuexInit });
+  } else {
+    // override init and inject vuex init procedure
+    // for 1.x backwards compatibility.
+    var _init = Vue.prototype._init;
+    Vue.prototype._init = function (options) {
+      if ( options === void 0 ) options = {};
+
+      options.init = options.init
+        ? [vuexInit].concat(options.init)
+        : vuexInit;
+      _init.call(this, options);
+    };
+  }
 
-function applyMixin (app, store, injectKey) {
-  app.provide(injectKey || storeKey, store);
-
-  // TODO: Refactor this to use `provide/inject`. It's currently
-  // not possible because Vue 3 doesn't work with `$` prefixed
-  // `provide/inject` at the moment.
-  app.mixin({
-    beforeCreate: function beforeCreate () {
-      if (!this.parent) {
-        this.$store = typeof store === 'function' ? store() : store;
-      } else {
-        this.$store = this.parent.$options.$store;
-      }
+  /**
+   * Vuex init hook, injected into each instances init hooks list.
+   */
+
+  function vuexInit () {
+    var options = this.$options;
+    // store injection
+    if (options.store) {
+      this.$store = typeof options.store === 'function'
+        ? options.store()
+        : options.store;
+    } else if (options.parent && options.parent.$store) {
+      this.$store = options.parent.$store;
     }
-  });
+  }
 }
 
 var target = typeof window !== 'undefined'
@@ -120,6 +129,10 @@ Module.prototype.getChild = function getChild (key) {
   return this._children[key]
 };
 
+Module.prototype.hasChild = function hasChild (key) {
+  return key in this._children
+};
+
 Module.prototype.update = function update (rawModule) {
   this._rawModule.namespaced = rawModule.namespaced;
   if (rawModule.actions) {
@@ -212,6 +225,13 @@ ModuleCollection.prototype.unregister = function unregister (path) {
   parent.removeChild(key);
 };
 
+ModuleCollection.prototype.isRegistered = function isRegistered (path) {
+  var parent = this.get(path.slice(0, -1));
+  var key = path[path.length - 1];
+
+  return parent.hasChild(key)
+};
+
 function update (path, targetModule, newModule) {
   if (process.env.NODE_ENV !== 'production') {
     assertRawModule(path, newModule);
@@ -282,28 +302,21 @@ function makeAssertionMessage (path, key, type, value, expected) {
   return buf
 }
 
-// let Vue // bind on install
-
-function createStore (options) {
-  return new Store(options)
-}
+var Vue; // bind on install
 
 var Store = function Store (options) {
   var this$1 = this;
   if ( options === void 0 ) options = {};
 
-  // TODO: Bring back this one if needed.
-  //
   // Auto install if it is not done yet and `window` has `Vue`.
   // To allow users to avoid auto-installation in some cases,
   // this code should be placed here. See #731
-  // if (!Vue && typeof window !== 'undefined' && window.Vue) {
-  // install(window.Vue)
-  // }
+  if (!Vue && typeof window !== 'undefined' && window.Vue) {
+    install(window.Vue);
+  }
 
   if (process.env.NODE_ENV !== 'production') {
-    // TODO: Maybe we can remove this depending on the new implementation.
-    // assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
+    assert(Vue, "must call Vue.use(Vuex) before creating a store instance.");
     assert(typeof Promise !== 'undefined', "vuex requires a Promise polyfill in this browser.");
     assert(this instanceof Store, "store must be called with the new operator.");
   }
@@ -320,6 +333,7 @@ var Store = function Store (options) {
   this._modules = new ModuleCollection(options);
   this._modulesNamespaceMap = Object.create(null);
   this._subscribers = [];
+  this._watcherVM = new Vue();
   this._makeLocalGettersCache = Object.create(null);
 
   // bind commit and dispatch to self
@@ -351,7 +365,7 @@ var Store = function Store (options) {
   // apply plugins
   plugins.forEach(function (plugin) { return plugin(this$1); });
 
-  var useDevtools = options.devtools !== undefined ? options.devtools : /* Vue.config.devtools */ true;
+  var useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools;
   if (useDevtools) {
     devtoolPlugin(this);
   }
@@ -359,23 +373,6 @@ var Store = function Store (options) {
 
 var prototypeAccessors$1 = { state: { configurable: true } };
 
-Store.prototype.install = function install (app, injectKey) {
-  // TODO: Removing double install check for now. Maybe we can bring this
-  // feature back again if needed.
-  //
-  // if (Vue && _Vue === Vue) {
-  // if (process.env.NODE_ENV !== 'production') {
-  //   console.error(
-  //     '[vuex] already installed. Vue.use(Vuex) should be called only once.'
-  //   )
-  // }
-  // return
-  // }
-  // Vue = _Vue
-
-  applyMixin(app, this, injectKey);
-};
-
 prototypeAccessors$1.state.get = function () {
   return this._vm._data.$$state
 };
@@ -481,13 +478,13 @@ Store.prototype.subscribeAction = function subscribeAction (fn) {
   return genericSubscribe(subs, this._actionSubscribers)
 };
 
-Store.prototype.watch = function watch$1 (getter, cb, options) {
+Store.prototype.watch = function watch (getter, cb, options) {
     var this$1 = this;
 
   if (process.env.NODE_ENV !== 'production') {
     assert(typeof getter === 'function', "store.watch only accepts a function.");
   }
-  return vue.watch(function () { return getter(this$1.state, this$1.getters); }, cb, Object.assign({}, options))
+  return this._watcherVM.$watch(function () { return getter(this$1.state, this$1.getters); }, cb, options)
 };
 
 Store.prototype.replaceState = function replaceState (state) {
@@ -526,11 +523,21 @@ Store.prototype.unregisterModule = function unregisterModule (path) {
   this._modules.unregister(path);
   this._withCommit(function () {
     var parentState = getNestedState(this$1.state, path.slice(0, -1));
-    delete parentState[path[path.length - 1]];
+    Vue.delete(parentState, path[path.length - 1]);
   });
   resetStore(this);
 };
 
+Store.prototype.hasModule = function hasModule (path) {
+  if (typeof path === 'string') { path = [path]; }
+
+  if (process.env.NODE_ENV !== 'production') {
+    assert(Array.isArray(path), "module path must be a string or an Array.");
+  }
+
+  return this._modules.isRegistered(path)
+};
+
 Store.prototype.hotUpdate = function hotUpdate (newOptions) {
   this._modules.update(newOptions);
   resetStore(this, true);
@@ -577,42 +584,30 @@ function resetStoreVM (store, state, hot) {
   // reset local getters cache
   store._makeLocalGettersCache = Object.create(null);
   var wrappedGetters = store._wrappedGetters;
-  var computedObj = {};
+  var computed = {};
   forEachValue(wrappedGetters, function (fn, key) {
-    // TODO: Refactor following code and comment. We can simplify many things
-    // using computed function.
-    //
     // use computed to leverage its lazy-caching mechanism
     // direct inline function use will lead to closure preserving oldVm.
     // using partial to return function with only arguments preserved in closure environment.
-    computedObj[key] = partial(fn, store);
+    computed[key] = partial(fn, store);
     Object.defineProperty(store.getters, key, {
-      get: function () { return vue.computed(function () { return computedObj[key](); }).value; },
+      get: function () { return store._vm[key]; },
       enumerable: true // for local getters
     });
   });
 
-  // TODO: Bring back this if it's still needed.
-  //
   // use a Vue instance to store the state tree
   // suppress warnings just in case the user has added
   // some funky global mixins
-  // const silent = Vue.config.silent
-  // Vue.config.silent = true
-
-  // TODO: Refactor the code and remove this comment.
-  //
-  // New impl with reactive. Defining redundunt keys to make it as close as
-  // the old impl api.
-  store._vm = vue.reactive({
-    _data: {
+  var silent = Vue.config.silent;
+  Vue.config.silent = true;
+  store._vm = new Vue({
+    data: {
       $$state: state
-    }
+    },
+    computed: computed
   });
-
-  // TODO: Bring back maybe?
-  //
-  // Vue.config.silent = silent
+  Vue.config.silent = silent;
 
   // enable strict mode for new vm
   if (store.strict) {
@@ -627,8 +622,7 @@ function resetStoreVM (store, state, hot) {
         oldVm._data.$$state = null;
       });
     }
-    // TODO: I think we don't need this anymore since we're not using vm?
-    // Vue.nextTick(() => oldVm.$destroy())
+    Vue.nextTick(function () { return oldVm.$destroy(); });
   }
 }
 
@@ -656,7 +650,7 @@ function installModule (store, rootState, path, module, hot) {
           );
         }
       }
-      parentState[moduleName] = module.state;
+      Vue.set(parentState, moduleName, module.state);
     });
   }
 
@@ -817,11 +811,11 @@ function registerGetter (store, type, rawGetter, local) {
 }
 
 function enableStrictMode (store) {
-  vue.watch(function () { return store._vm._data.$$state; }, function () {
+  store._vm.$watch(function () { return this._data.$$state }, function () {
     if (process.env.NODE_ENV !== 'production') {
       assert(store._committing, "do not mutate vuex store state outside mutation handlers.");
     }
-  }, { deep: true, flush: 'sync' });
+  }, { deep: true, sync: true });
 }
 
 function getNestedState (state, path) {
@@ -842,6 +836,19 @@ function unifyObjectStyle (type, payload, options) {
   return { type: type, payload: payload, options: options }
 }
 
+function install (_Vue) {
+  if (Vue && _Vue === Vue) {
+    if (process.env.NODE_ENV !== 'production') {
+      console.error(
+        '[vuex] already installed. Vue.use(Vuex) should be called only once.'
+      );
+    }
+    return
+  }
+  Vue = _Vue;
+  applyMixin(Vue);
+}
+
 /**
  * Reduce the code which written in Vue.js for getting the state.
  * @param {String} [namespace] - Module's namespace
@@ -1053,10 +1060,9 @@ function getModuleByNamespace (store, helper, namespace) {
 }
 
 var index = {
-  version: '4.0.0-alpha.1',
-  createStore: createStore,
   Store: Store,
-  useStore: useStore,
+  install: install,
+  version: '3.2.0',
   mapState: mapState,
   mapMutations: mapMutations,
   mapGetters: mapGetters,

+ 91 - 85
dist/vuex.esm.browser.js

@@ -1,31 +1,40 @@
 /**
- * vuex v4.0.0-alpha.1
+ * vuex v3.2.0
  * (c) 2020 Evan You
  * @license MIT
  */
-import { inject, watch, computed, reactive } from 'vue';
-
-const storeKey = 'store';
-
-function useStore (key = null) {
-  return inject(key !== null ? key : storeKey)
-}
+function applyMixin (Vue) {
+  const version = Number(Vue.version.split('.')[0]);
+
+  if (version >= 2) {
+    Vue.mixin({ beforeCreate: vuexInit });
+  } else {
+    // override init and inject vuex init procedure
+    // for 1.x backwards compatibility.
+    const _init = Vue.prototype._init;
+    Vue.prototype._init = function (options = {}) {
+      options.init = options.init
+        ? [vuexInit].concat(options.init)
+        : vuexInit;
+      _init.call(this, options);
+    };
+  }
 
-function applyMixin (app, store, injectKey) {
-  app.provide(injectKey || storeKey, store);
-
-  // TODO: Refactor this to use `provide/inject`. It's currently
-  // not possible because Vue 3 doesn't work with `$` prefixed
-  // `provide/inject` at the moment.
-  app.mixin({
-    beforeCreate () {
-      if (!this.parent) {
-        this.$store = typeof store === 'function' ? store() : store;
-      } else {
-        this.$store = this.parent.$options.$store;
-      }
+  /**
+   * Vuex init hook, injected into each instances init hooks list.
+   */
+
+  function vuexInit () {
+    const options = this.$options;
+    // store injection
+    if (options.store) {
+      this.$store = typeof options.store === 'function'
+        ? options.store()
+        : options.store;
+    } else if (options.parent && options.parent.$store) {
+      this.$store = options.parent.$store;
     }
-  });
+  }
 }
 
 const target = typeof window !== 'undefined'
@@ -115,6 +124,10 @@ class Module {
     return this._children[key]
   }
 
+  hasChild (key) {
+    return key in this._children
+  }
+
   update (rawModule) {
     this._rawModule.namespaced = rawModule.namespaced;
     if (rawModule.actions) {
@@ -203,6 +216,13 @@ class ModuleCollection {
 
     parent.removeChild(key);
   }
+
+  isRegistered (path) {
+    const parent = this.get(path.slice(0, -1));
+    const key = path[path.length - 1];
+
+    return parent.hasChild(key)
+  }
 }
 
 function update (path, targetModule, newModule) {
@@ -275,26 +295,19 @@ function makeAssertionMessage (path, key, type, value, expected) {
   return buf
 }
 
-// let Vue // bind on install
-
-function createStore (options) {
-  return new Store(options)
-}
+let Vue; // bind on install
 
 class Store {
   constructor (options = {}) {
-    // TODO: Bring back this one if needed.
-    //
     // Auto install if it is not done yet and `window` has `Vue`.
     // To allow users to avoid auto-installation in some cases,
     // this code should be placed here. See #731
-    // if (!Vue && typeof window !== 'undefined' && window.Vue) {
-    //   install(window.Vue)
-    // }
+    if (!Vue && typeof window !== 'undefined' && window.Vue) {
+      install(window.Vue);
+    }
 
     {
-      // TODO: Maybe we can remove this depending on the new implementation.
-      // assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
+      assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`);
       assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`);
       assert(this instanceof Store, `store must be called with the new operator.`);
     }
@@ -313,6 +326,7 @@ class Store {
     this._modules = new ModuleCollection(options);
     this._modulesNamespaceMap = Object.create(null);
     this._subscribers = [];
+    this._watcherVM = new Vue();
     this._makeLocalGettersCache = Object.create(null);
 
     // bind commit and dispatch to self
@@ -342,29 +356,12 @@ class Store {
     // apply plugins
     plugins.forEach(plugin => plugin(this));
 
-    const useDevtools = options.devtools !== undefined ? options.devtools : /* Vue.config.devtools */ true;
+    const useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools;
     if (useDevtools) {
       devtoolPlugin(this);
     }
   }
 
-  install (app, injectKey) {
-    // TODO: Removing double install check for now. Maybe we can bring this
-    // feature back again if needed.
-    //
-    // if (Vue && _Vue === Vue) {
-    //   if ("development" !== 'production') {
-    //     console.error(
-    //       '[vuex] already installed. Vue.use(Vuex) should be called only once.'
-    //     )
-    //   }
-    //   return
-    // }
-    // Vue = _Vue
-
-    applyMixin(app, this, injectKey);
-  }
-
   get state () {
     return this._vm._data.$$state
   }
@@ -471,7 +468,7 @@ class Store {
     {
       assert(typeof getter === 'function', `store.watch only accepts a function.`);
     }
-    return watch(() => getter(this.state, this.getters), cb, Object.assign({}, options))
+    return this._watcherVM.$watch(() => getter(this.state, this.getters), cb, options)
   }
 
   replaceState (state) {
@@ -504,11 +501,21 @@ class Store {
     this._modules.unregister(path);
     this._withCommit(() => {
       const parentState = getNestedState(this.state, path.slice(0, -1));
-      delete parentState[path[path.length - 1]];
+      Vue.delete(parentState, path[path.length - 1]);
     });
     resetStore(this);
   }
 
+  hasModule (path) {
+    if (typeof path === 'string') path = [path];
+
+    {
+      assert(Array.isArray(path), `module path must be a string or an Array.`);
+    }
+
+    return this._modules.isRegistered(path)
+  }
+
   hotUpdate (newOptions) {
     this._modules.update(newOptions);
     resetStore(this, true);
@@ -554,42 +561,30 @@ function resetStoreVM (store, state, hot) {
   // reset local getters cache
   store._makeLocalGettersCache = Object.create(null);
   const wrappedGetters = store._wrappedGetters;
-  const computedObj = {};
+  const computed = {};
   forEachValue(wrappedGetters, (fn, key) => {
-    // TODO: Refactor following code and comment. We can simplify many things
-    // using computed function.
-    //
     // use computed to leverage its lazy-caching mechanism
     // direct inline function use will lead to closure preserving oldVm.
     // using partial to return function with only arguments preserved in closure environment.
-    computedObj[key] = partial(fn, store);
+    computed[key] = partial(fn, store);
     Object.defineProperty(store.getters, key, {
-      get: () => computed(() => computedObj[key]()).value,
+      get: () => store._vm[key],
       enumerable: true // for local getters
     });
   });
 
-  // TODO: Bring back this if it's still needed.
-  //
   // use a Vue instance to store the state tree
   // suppress warnings just in case the user has added
   // some funky global mixins
-  // const silent = Vue.config.silent
-  // Vue.config.silent = true
-
-  // TODO: Refactor the code and remove this comment.
-  //
-  // New impl with reactive. Defining redundunt keys to make it as close as
-  // the old impl api.
-  store._vm = reactive({
-    _data: {
+  const silent = Vue.config.silent;
+  Vue.config.silent = true;
+  store._vm = new Vue({
+    data: {
       $$state: state
-    }
+    },
+    computed
   });
-
-  // TODO: Bring back maybe?
-  //
-  // Vue.config.silent = silent
+  Vue.config.silent = silent;
 
   // enable strict mode for new vm
   if (store.strict) {
@@ -604,8 +599,7 @@ function resetStoreVM (store, state, hot) {
         oldVm._data.$$state = null;
       });
     }
-    // TODO: I think we don't need this anymore since we're not using vm?
-    // Vue.nextTick(() => oldVm.$destroy())
+    Vue.nextTick(() => oldVm.$destroy());
   }
 }
 
@@ -633,7 +627,7 @@ function installModule (store, rootState, path, module, hot) {
           );
         }
       }
-      parentState[moduleName] = module.state;
+      Vue.set(parentState, moduleName, module.state);
     });
   }
 
@@ -792,11 +786,11 @@ function registerGetter (store, type, rawGetter, local) {
 }
 
 function enableStrictMode (store) {
-  watch(() => store._vm._data.$$state, () => {
+  store._vm.$watch(function () { return this._data.$$state }, () => {
     {
       assert(store._committing, `do not mutate vuex store state outside mutation handlers.`);
     }
-  }, { deep: true, flush: 'sync' });
+  }, { deep: true, sync: true });
 }
 
 function getNestedState (state, path) {
@@ -817,6 +811,19 @@ function unifyObjectStyle (type, payload, options) {
   return { type, payload, options }
 }
 
+function install (_Vue) {
+  if (Vue && _Vue === Vue) {
+    {
+      console.error(
+        '[vuex] already installed. Vue.use(Vuex) should be called only once.'
+      );
+    }
+    return
+  }
+  Vue = _Vue;
+  applyMixin(Vue);
+}
+
 /**
  * Reduce the code which written in Vue.js for getting the state.
  * @param {String} [namespace] - Module's namespace
@@ -1010,10 +1017,9 @@ function getModuleByNamespace (store, helper, namespace) {
 }
 
 var index_esm = {
-  version: '4.0.0-alpha.1',
-  createStore,
   Store,
-  useStore,
+  install,
+  version: '3.2.0',
   mapState,
   mapMutations,
   mapGetters,
@@ -1022,4 +1028,4 @@ var index_esm = {
 };
 
 export default index_esm;
-export { createStore, Store, useStore, mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers };
+export { Store, install, mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers };

文件差异内容过多而无法显示
+ 1 - 1
dist/vuex.esm.browser.min.js


+ 93 - 87
dist/vuex.esm.js

@@ -1,33 +1,42 @@
 /**
- * vuex v4.0.0-alpha.1
+ * vuex v3.2.0
  * (c) 2020 Evan You
  * @license MIT
  */
-import { inject, watch, computed, reactive } from 'vue';
+function applyMixin (Vue) {
+  var version = Number(Vue.version.split('.')[0]);
 
-var storeKey = 'store';
-
-function useStore (key) {
-  if ( key === void 0 ) key = null;
-
-  return inject(key !== null ? key : storeKey)
-}
+  if (version >= 2) {
+    Vue.mixin({ beforeCreate: vuexInit });
+  } else {
+    // override init and inject vuex init procedure
+    // for 1.x backwards compatibility.
+    var _init = Vue.prototype._init;
+    Vue.prototype._init = function (options) {
+      if ( options === void 0 ) options = {};
+
+      options.init = options.init
+        ? [vuexInit].concat(options.init)
+        : vuexInit;
+      _init.call(this, options);
+    };
+  }
 
-function applyMixin (app, store, injectKey) {
-  app.provide(injectKey || storeKey, store);
-
-  // TODO: Refactor this to use `provide/inject`. It's currently
-  // not possible because Vue 3 doesn't work with `$` prefixed
-  // `provide/inject` at the moment.
-  app.mixin({
-    beforeCreate: function beforeCreate () {
-      if (!this.parent) {
-        this.$store = typeof store === 'function' ? store() : store;
-      } else {
-        this.$store = this.parent.$options.$store;
-      }
+  /**
+   * Vuex init hook, injected into each instances init hooks list.
+   */
+
+  function vuexInit () {
+    var options = this.$options;
+    // store injection
+    if (options.store) {
+      this.$store = typeof options.store === 'function'
+        ? options.store()
+        : options.store;
+    } else if (options.parent && options.parent.$store) {
+      this.$store = options.parent.$store;
     }
-  });
+  }
 }
 
 var target = typeof window !== 'undefined'
@@ -118,6 +127,10 @@ Module.prototype.getChild = function getChild (key) {
   return this._children[key]
 };
 
+Module.prototype.hasChild = function hasChild (key) {
+  return key in this._children
+};
+
 Module.prototype.update = function update (rawModule) {
   this._rawModule.namespaced = rawModule.namespaced;
   if (rawModule.actions) {
@@ -210,6 +223,13 @@ ModuleCollection.prototype.unregister = function unregister (path) {
   parent.removeChild(key);
 };
 
+ModuleCollection.prototype.isRegistered = function isRegistered (path) {
+  var parent = this.get(path.slice(0, -1));
+  var key = path[path.length - 1];
+
+  return parent.hasChild(key)
+};
+
 function update (path, targetModule, newModule) {
   if (process.env.NODE_ENV !== 'production') {
     assertRawModule(path, newModule);
@@ -280,28 +300,21 @@ function makeAssertionMessage (path, key, type, value, expected) {
   return buf
 }
 
-// let Vue // bind on install
-
-function createStore (options) {
-  return new Store(options)
-}
+var Vue; // bind on install
 
 var Store = function Store (options) {
   var this$1 = this;
   if ( options === void 0 ) options = {};
 
-  // TODO: Bring back this one if needed.
-  //
   // Auto install if it is not done yet and `window` has `Vue`.
   // To allow users to avoid auto-installation in some cases,
   // this code should be placed here. See #731
-  // if (!Vue && typeof window !== 'undefined' && window.Vue) {
-  // install(window.Vue)
-  // }
+  if (!Vue && typeof window !== 'undefined' && window.Vue) {
+    install(window.Vue);
+  }
 
   if (process.env.NODE_ENV !== 'production') {
-    // TODO: Maybe we can remove this depending on the new implementation.
-    // assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
+    assert(Vue, "must call Vue.use(Vuex) before creating a store instance.");
     assert(typeof Promise !== 'undefined', "vuex requires a Promise polyfill in this browser.");
     assert(this instanceof Store, "store must be called with the new operator.");
   }
@@ -318,6 +331,7 @@ var Store = function Store (options) {
   this._modules = new ModuleCollection(options);
   this._modulesNamespaceMap = Object.create(null);
   this._subscribers = [];
+  this._watcherVM = new Vue();
   this._makeLocalGettersCache = Object.create(null);
 
   // bind commit and dispatch to self
@@ -349,7 +363,7 @@ var Store = function Store (options) {
   // apply plugins
   plugins.forEach(function (plugin) { return plugin(this$1); });
 
-  var useDevtools = options.devtools !== undefined ? options.devtools : /* Vue.config.devtools */ true;
+  var useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools;
   if (useDevtools) {
     devtoolPlugin(this);
   }
@@ -357,23 +371,6 @@ var Store = function Store (options) {
 
 var prototypeAccessors$1 = { state: { configurable: true } };
 
-Store.prototype.install = function install (app, injectKey) {
-  // TODO: Removing double install check for now. Maybe we can bring this
-  // feature back again if needed.
-  //
-  // if (Vue && _Vue === Vue) {
-  // if (process.env.NODE_ENV !== 'production') {
-  //   console.error(
-  //     '[vuex] already installed. Vue.use(Vuex) should be called only once.'
-  //   )
-  // }
-  // return
-  // }
-  // Vue = _Vue
-
-  applyMixin(app, this, injectKey);
-};
-
 prototypeAccessors$1.state.get = function () {
   return this._vm._data.$$state
 };
@@ -479,13 +476,13 @@ Store.prototype.subscribeAction = function subscribeAction (fn) {
   return genericSubscribe(subs, this._actionSubscribers)
 };
 
-Store.prototype.watch = function watch$1 (getter, cb, options) {
+Store.prototype.watch = function watch (getter, cb, options) {
     var this$1 = this;
 
   if (process.env.NODE_ENV !== 'production') {
     assert(typeof getter === 'function', "store.watch only accepts a function.");
   }
-  return watch(function () { return getter(this$1.state, this$1.getters); }, cb, Object.assign({}, options))
+  return this._watcherVM.$watch(function () { return getter(this$1.state, this$1.getters); }, cb, options)
 };
 
 Store.prototype.replaceState = function replaceState (state) {
@@ -524,11 +521,21 @@ Store.prototype.unregisterModule = function unregisterModule (path) {
   this._modules.unregister(path);
   this._withCommit(function () {
     var parentState = getNestedState(this$1.state, path.slice(0, -1));
-    delete parentState[path[path.length - 1]];
+    Vue.delete(parentState, path[path.length - 1]);
   });
   resetStore(this);
 };
 
+Store.prototype.hasModule = function hasModule (path) {
+  if (typeof path === 'string') { path = [path]; }
+
+  if (process.env.NODE_ENV !== 'production') {
+    assert(Array.isArray(path), "module path must be a string or an Array.");
+  }
+
+  return this._modules.isRegistered(path)
+};
+
 Store.prototype.hotUpdate = function hotUpdate (newOptions) {
   this._modules.update(newOptions);
   resetStore(this, true);
@@ -575,42 +582,30 @@ function resetStoreVM (store, state, hot) {
   // reset local getters cache
   store._makeLocalGettersCache = Object.create(null);
   var wrappedGetters = store._wrappedGetters;
-  var computedObj = {};
+  var computed = {};
   forEachValue(wrappedGetters, function (fn, key) {
-    // TODO: Refactor following code and comment. We can simplify many things
-    // using computed function.
-    //
     // use computed to leverage its lazy-caching mechanism
     // direct inline function use will lead to closure preserving oldVm.
     // using partial to return function with only arguments preserved in closure environment.
-    computedObj[key] = partial(fn, store);
+    computed[key] = partial(fn, store);
     Object.defineProperty(store.getters, key, {
-      get: function () { return computed(function () { return computedObj[key](); }).value; },
+      get: function () { return store._vm[key]; },
       enumerable: true // for local getters
     });
   });
 
-  // TODO: Bring back this if it's still needed.
-  //
   // use a Vue instance to store the state tree
   // suppress warnings just in case the user has added
   // some funky global mixins
-  // const silent = Vue.config.silent
-  // Vue.config.silent = true
-
-  // TODO: Refactor the code and remove this comment.
-  //
-  // New impl with reactive. Defining redundunt keys to make it as close as
-  // the old impl api.
-  store._vm = reactive({
-    _data: {
+  var silent = Vue.config.silent;
+  Vue.config.silent = true;
+  store._vm = new Vue({
+    data: {
       $$state: state
-    }
+    },
+    computed: computed
   });
-
-  // TODO: Bring back maybe?
-  //
-  // Vue.config.silent = silent
+  Vue.config.silent = silent;
 
   // enable strict mode for new vm
   if (store.strict) {
@@ -625,8 +620,7 @@ function resetStoreVM (store, state, hot) {
         oldVm._data.$$state = null;
       });
     }
-    // TODO: I think we don't need this anymore since we're not using vm?
-    // Vue.nextTick(() => oldVm.$destroy())
+    Vue.nextTick(function () { return oldVm.$destroy(); });
   }
 }
 
@@ -654,7 +648,7 @@ function installModule (store, rootState, path, module, hot) {
           );
         }
       }
-      parentState[moduleName] = module.state;
+      Vue.set(parentState, moduleName, module.state);
     });
   }
 
@@ -815,11 +809,11 @@ function registerGetter (store, type, rawGetter, local) {
 }
 
 function enableStrictMode (store) {
-  watch(function () { return store._vm._data.$$state; }, function () {
+  store._vm.$watch(function () { return this._data.$$state }, function () {
     if (process.env.NODE_ENV !== 'production') {
       assert(store._committing, "do not mutate vuex store state outside mutation handlers.");
     }
-  }, { deep: true, flush: 'sync' });
+  }, { deep: true, sync: true });
 }
 
 function getNestedState (state, path) {
@@ -840,6 +834,19 @@ function unifyObjectStyle (type, payload, options) {
   return { type: type, payload: payload, options: options }
 }
 
+function install (_Vue) {
+  if (Vue && _Vue === Vue) {
+    if (process.env.NODE_ENV !== 'production') {
+      console.error(
+        '[vuex] already installed. Vue.use(Vuex) should be called only once.'
+      );
+    }
+    return
+  }
+  Vue = _Vue;
+  applyMixin(Vue);
+}
+
 /**
  * Reduce the code which written in Vue.js for getting the state.
  * @param {String} [namespace] - Module's namespace
@@ -1051,10 +1058,9 @@ function getModuleByNamespace (store, helper, namespace) {
 }
 
 var index_esm = {
-  version: '4.0.0-alpha.1',
-  createStore: createStore,
   Store: Store,
-  useStore: useStore,
+  install: install,
+  version: '3.2.0',
   mapState: mapState,
   mapMutations: mapMutations,
   mapGetters: mapGetters,
@@ -1063,4 +1069,4 @@ var index_esm = {
 };
 
 export default index_esm;
-export { createStore, Store, useStore, mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers };
+export { Store, install, mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers };

+ 96 - 88
dist/vuex.js

@@ -1,37 +1,48 @@
 /**
- * vuex v4.0.0-alpha.1
+ * vuex v3.2.0
  * (c) 2020 Evan You
  * @license MIT
  */
 (function (global, factory) {
-  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('vue')) :
-  typeof define === 'function' && define.amd ? define(['vue'], factory) :
-  (global = global || self, global.Vuex = factory(global.Vue));
-}(this, function (vue) { 'use strict';
+  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+  typeof define === 'function' && define.amd ? define(factory) :
+  (global = global || self, global.Vuex = factory());
+}(this, function () { 'use strict';
 
-  var storeKey = 'store';
+  function applyMixin (Vue) {
+    var version = Number(Vue.version.split('.')[0]);
 
-  function useStore (key) {
-    if ( key === void 0 ) key = null;
-
-    return vue.inject(key !== null ? key : storeKey)
-  }
+    if (version >= 2) {
+      Vue.mixin({ beforeCreate: vuexInit });
+    } else {
+      // override init and inject vuex init procedure
+      // for 1.x backwards compatibility.
+      var _init = Vue.prototype._init;
+      Vue.prototype._init = function (options) {
+        if ( options === void 0 ) options = {};
+
+        options.init = options.init
+          ? [vuexInit].concat(options.init)
+          : vuexInit;
+        _init.call(this, options);
+      };
+    }
 
-  function applyMixin (app, store, injectKey) {
-    app.provide(injectKey || storeKey, store);
-
-    // TODO: Refactor this to use `provide/inject`. It's currently
-    // not possible because Vue 3 doesn't work with `$` prefixed
-    // `provide/inject` at the moment.
-    app.mixin({
-      beforeCreate: function beforeCreate () {
-        if (!this.parent) {
-          this.$store = typeof store === 'function' ? store() : store;
-        } else {
-          this.$store = this.parent.$options.$store;
-        }
+    /**
+     * Vuex init hook, injected into each instances init hooks list.
+     */
+
+    function vuexInit () {
+      var options = this.$options;
+      // store injection
+      if (options.store) {
+        this.$store = typeof options.store === 'function'
+          ? options.store()
+          : options.store;
+      } else if (options.parent && options.parent.$store) {
+        this.$store = options.parent.$store;
       }
-    });
+    }
   }
 
   var target = typeof window !== 'undefined'
@@ -122,6 +133,10 @@
     return this._children[key]
   };
 
+  Module.prototype.hasChild = function hasChild (key) {
+    return key in this._children
+  };
+
   Module.prototype.update = function update (rawModule) {
     this._rawModule.namespaced = rawModule.namespaced;
     if (rawModule.actions) {
@@ -214,6 +229,13 @@
     parent.removeChild(key);
   };
 
+  ModuleCollection.prototype.isRegistered = function isRegistered (path) {
+    var parent = this.get(path.slice(0, -1));
+    var key = path[path.length - 1];
+
+    return parent.hasChild(key)
+  };
+
   function update (path, targetModule, newModule) {
     {
       assertRawModule(path, newModule);
@@ -284,28 +306,21 @@
     return buf
   }
 
-  // let Vue // bind on install
-
-  function createStore (options) {
-    return new Store(options)
-  }
+  var Vue; // bind on install
 
   var Store = function Store (options) {
     var this$1 = this;
     if ( options === void 0 ) options = {};
 
-    // TODO: Bring back this one if needed.
-    //
     // Auto install if it is not done yet and `window` has `Vue`.
     // To allow users to avoid auto-installation in some cases,
     // this code should be placed here. See #731
-    // if (!Vue && typeof window !== 'undefined' && window.Vue) {
-    // install(window.Vue)
-    // }
+    if (!Vue && typeof window !== 'undefined' && window.Vue) {
+      install(window.Vue);
+    }
 
     {
-      // TODO: Maybe we can remove this depending on the new implementation.
-      // assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
+      assert(Vue, "must call Vue.use(Vuex) before creating a store instance.");
       assert(typeof Promise !== 'undefined', "vuex requires a Promise polyfill in this browser.");
       assert(this instanceof Store, "store must be called with the new operator.");
     }
@@ -322,6 +337,7 @@
     this._modules = new ModuleCollection(options);
     this._modulesNamespaceMap = Object.create(null);
     this._subscribers = [];
+    this._watcherVM = new Vue();
     this._makeLocalGettersCache = Object.create(null);
 
     // bind commit and dispatch to self
@@ -353,7 +369,7 @@
     // apply plugins
     plugins.forEach(function (plugin) { return plugin(this$1); });
 
-    var useDevtools = options.devtools !== undefined ? options.devtools : /* Vue.config.devtools */ true;
+    var useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools;
     if (useDevtools) {
       devtoolPlugin(this);
     }
@@ -361,23 +377,6 @@
 
   var prototypeAccessors$1 = { state: { configurable: true } };
 
-  Store.prototype.install = function install (app, injectKey) {
-    // TODO: Removing double install check for now. Maybe we can bring this
-    // feature back again if needed.
-    //
-    // if (Vue && _Vue === Vue) {
-    // if ("development" !== 'production') {
-    //   console.error(
-    //     '[vuex] already installed. Vue.use(Vuex) should be called only once.'
-    //   )
-    // }
-    // return
-    // }
-    // Vue = _Vue
-
-    applyMixin(app, this, injectKey);
-  };
-
   prototypeAccessors$1.state.get = function () {
     return this._vm._data.$$state
   };
@@ -482,13 +481,13 @@
     return genericSubscribe(subs, this._actionSubscribers)
   };
 
-  Store.prototype.watch = function watch$1 (getter, cb, options) {
+  Store.prototype.watch = function watch (getter, cb, options) {
       var this$1 = this;
 
     {
       assert(typeof getter === 'function', "store.watch only accepts a function.");
     }
-    return vue.watch(function () { return getter(this$1.state, this$1.getters); }, cb, Object.assign({}, options))
+    return this._watcherVM.$watch(function () { return getter(this$1.state, this$1.getters); }, cb, options)
   };
 
   Store.prototype.replaceState = function replaceState (state) {
@@ -527,11 +526,21 @@
     this._modules.unregister(path);
     this._withCommit(function () {
       var parentState = getNestedState(this$1.state, path.slice(0, -1));
-      delete parentState[path[path.length - 1]];
+      Vue.delete(parentState, path[path.length - 1]);
     });
     resetStore(this);
   };
 
+  Store.prototype.hasModule = function hasModule (path) {
+    if (typeof path === 'string') { path = [path]; }
+
+    {
+      assert(Array.isArray(path), "module path must be a string or an Array.");
+    }
+
+    return this._modules.isRegistered(path)
+  };
+
   Store.prototype.hotUpdate = function hotUpdate (newOptions) {
     this._modules.update(newOptions);
     resetStore(this, true);
@@ -578,42 +587,30 @@
     // reset local getters cache
     store._makeLocalGettersCache = Object.create(null);
     var wrappedGetters = store._wrappedGetters;
-    var computedObj = {};
+    var computed = {};
     forEachValue(wrappedGetters, function (fn, key) {
-      // TODO: Refactor following code and comment. We can simplify many things
-      // using computed function.
-      //
       // use computed to leverage its lazy-caching mechanism
       // direct inline function use will lead to closure preserving oldVm.
       // using partial to return function with only arguments preserved in closure environment.
-      computedObj[key] = partial(fn, store);
+      computed[key] = partial(fn, store);
       Object.defineProperty(store.getters, key, {
-        get: function () { return vue.computed(function () { return computedObj[key](); }).value; },
+        get: function () { return store._vm[key]; },
         enumerable: true // for local getters
       });
     });
 
-    // TODO: Bring back this if it's still needed.
-    //
     // use a Vue instance to store the state tree
     // suppress warnings just in case the user has added
     // some funky global mixins
-    // const silent = Vue.config.silent
-    // Vue.config.silent = true
-
-    // TODO: Refactor the code and remove this comment.
-    //
-    // New impl with reactive. Defining redundunt keys to make it as close as
-    // the old impl api.
-    store._vm = vue.reactive({
-      _data: {
+    var silent = Vue.config.silent;
+    Vue.config.silent = true;
+    store._vm = new Vue({
+      data: {
         $$state: state
-      }
+      },
+      computed: computed
     });
-
-    // TODO: Bring back maybe?
-    //
-    // Vue.config.silent = silent
+    Vue.config.silent = silent;
 
     // enable strict mode for new vm
     if (store.strict) {
@@ -628,8 +625,7 @@
           oldVm._data.$$state = null;
         });
       }
-      // TODO: I think we don't need this anymore since we're not using vm?
-      // Vue.nextTick(() => oldVm.$destroy())
+      Vue.nextTick(function () { return oldVm.$destroy(); });
     }
   }
 
@@ -657,7 +653,7 @@
             );
           }
         }
-        parentState[moduleName] = module.state;
+        Vue.set(parentState, moduleName, module.state);
       });
     }
 
@@ -818,11 +814,11 @@
   }
 
   function enableStrictMode (store) {
-    vue.watch(function () { return store._vm._data.$$state; }, function () {
+    store._vm.$watch(function () { return this._data.$$state }, function () {
       {
         assert(store._committing, "do not mutate vuex store state outside mutation handlers.");
       }
-    }, { deep: true, flush: 'sync' });
+    }, { deep: true, sync: true });
   }
 
   function getNestedState (state, path) {
@@ -843,6 +839,19 @@
     return { type: type, payload: payload, options: options }
   }
 
+  function install (_Vue) {
+    if (Vue && _Vue === Vue) {
+      {
+        console.error(
+          '[vuex] already installed. Vue.use(Vuex) should be called only once.'
+        );
+      }
+      return
+    }
+    Vue = _Vue;
+    applyMixin(Vue);
+  }
+
   /**
    * Reduce the code which written in Vue.js for getting the state.
    * @param {String} [namespace] - Module's namespace
@@ -1054,10 +1063,9 @@
   }
 
   var index = {
-    version: '4.0.0-alpha.1',
-    createStore: createStore,
     Store: Store,
-    useStore: useStore,
+    install: install,
+    version: '3.2.0',
     mapState: mapState,
     mapMutations: mapMutations,
     mapGetters: mapGetters,

文件差异内容过多而无法显示
+ 1 - 1
dist/vuex.min.js


+ 8 - 0
docs/api/README.md

@@ -238,6 +238,14 @@ const store = new Vuex.Store({ ...options })
 
   Unregister a dynamic module. [Details](../guide/modules.md#dynamic-module-registration)
 
+### hasModule
+
+- `hasModule(path: string | Array<string>)`
+
+  Check if the module with the given name is already registered. [Details](../guide/modules.md#dynamic-module-registration)
+
+  > New in 3.2.0
+
 ### hotUpdate
 
 -  `hotUpdate(newOptions: Object)`

+ 2 - 0
docs/guide/modules.md

@@ -301,6 +301,8 @@ Dynamic module registration makes it possible for other Vue plugins to also leve
 
 You can also remove a dynamically registered module with `store.unregisterModule(moduleName)`. Note you cannot remove static modules (declared at store creation) with this method.
 
+Note that you may check if the module is already registered to the store or not via `store.hasModule(moduleName)` method.
+
 #### Preserving state
 
 It may be likely that you want to preserve the previous state when registering a new module, such as preserving state from a Server Side Rendered app. You can achieve this with `preserveState` option: `store.registerModule('a', module, { preserveState: true })`

+ 2 - 2
docs/ru/README.md

@@ -48,7 +48,7 @@ new Vue({
 
 Решая первую проблему, придётся передавать одни и те же данные входными параметрами в глубоко вложенные компоненты. Это часто сложно и утомительно, а для соседних компонентов такое и вовсе не сработает. Решая вторую проблему, можно прийти к таким решениям, как обращение по ссылкам к родительским/дочерним экземплярам или попыткам изменять и синхронизировать несколько копий состояния через события. Оба подхода хрупки и быстро приводят к появлению кода, который невозможно поддерживать.
 
-Так почему бы не вынести всё общее состояние приложения из компонентов и управлять им в глобальном синглтоне? При этом наше дерево компонентов становится одним большим «представлением» и любой компонент может получить доступ к состоянию приложения или вызывать действия для изменения состояния, независимо от того, где они находятся в дереве!
+Так почему бы не вынести всё общее состояние приложения из компонентов и управлять им в глобальном синглтоне? При этом наше дерево компонентов становится одним большим «представлением», и любой компонент может получить доступ к состоянию приложения или вызывать действия для изменения состояния, независимо от того, где они находятся в дереве!
 
 Чётко определяя и разделяя концепции, возникающие при управлении состоянием, и требуя соблюдения определённых правил, которые поддерживают независимость между представлениями и состояниями, мы лучше структурируем код и облегчаем его поддержку.
 
@@ -60,7 +60,7 @@ new Vue({
 
 ### Когда следует использовать Vuex?
 
-Vuex помогает управлять совместно используемым состоянием, ценой привнесения новых концепций и вспомогательного кода. Компромисс, когда кратковременная продуктивность страдает на благо долгосрочной.
+Vuex помогает управлять совместно используемым состоянием ценой привнесения новых концепций и вспомогательного кода. Компромисс, когда кратковременная продуктивность страдает на благо долгосрочной.
 
 Если ещё не приходилось создавать крупные SPA и вы лишь знакомитесь с Vuex, это может показаться многословным и сложным. Всё в порядке — простые приложения могут легко обходиться и без Vuex. Возможно, будет достаточно простого паттерна [глобальной шины событий](https://ru.vuejs.org/v2/guide/state-management.html#Простой-контейнер-состояния-с-нуля). Но если вы создаёте SPA среднего или крупного размера, то, скорее всего, уже сталкивались с ситуациями, которые заставляли задуматься о том, как лучше управлять состоянием вне компонентов Vue, а Vuex в таком случае может стать вполне естественным следующим шагом. Есть хорошая цитата от Дэна Абрамова, автора Redux:
 

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

@@ -237,6 +237,14 @@ store.subscribeAction({
 
 Удаление зарегистрированного динамического модуля. [Подробнее](../guide/modules.md#динамическая-регистрация-модуnей)
 
+### hasModule
+
+* `hasModule(path: string | Array<string>)`
+
+Проверка, не зарегистрирован ли уже модуль с заданным именем. [Подробнее](../guide/modules.md#динамическая-регистрация-модуnей)
+
+> Добавлено в версии 3.2.0
+
 ### hotUpdate
 
 * `hotUpdate(newOptions: Object)`

+ 1 - 1
docs/ru/guide/README.md

@@ -37,7 +37,7 @@ store.commit('increment')
 console.log(store.state.count) // -> 1
 ```
 
-Запомните, причина, по которой мы вызываем мутацию, вместо изменения `store.state.count` напрямую, в том, что мы хотим явным образом отслеживать её. Это простое соглашение делает наше намерение более явным, что упрощает понимание происходящих изменений состояния приложения при чтении кода. Кроме того, это позволяет использовать инструменты для отслеживания каждой мутации, создания снимков состояния или даже использования «машины времени» для отладки.
+Запомните, причина, по которой мы вызываем мутацию вместо изменения `store.state.count` напрямую, в том, что мы хотим явным образом отслеживать её. Это простое соглашение делает наше намерение более явным, что упрощает понимание происходящих изменений состояния приложения при чтении кода. Кроме того, это позволяет использовать инструменты для отслеживания каждой мутации, создания снимков состояния или даже использования «машины времени» для отладки.
 
 Использование состояния хранилища в компоненте предполагает просто возврат необходимой части состояния в вычисляемом свойстве, поскольку состояние хранилища реактивно. Инициирование изменений — это просто запуск мутаций в методах компонентов.
 

+ 1 - 1
docs/ru/guide/actions.md

@@ -47,7 +47,7 @@ actions: {
 store.dispatch('increment');
 ```
 
-На первый взгляд может выглядеть глупо: если мы хотим увеличить значение count, почему бы просто не вызвать `store.commit('increment')` напрямую? Помните что **мутации должны быть синхронными**? Для действий такого ограничения нет. Внутри действий можно выполнять **асинхронные** операции:
+На первый взгляд может выглядеть глупо: если мы хотим увеличить значение count, почему бы просто не вызвать `store.commit('increment')` напрямую? Помните, что **мутации должны быть синхронными**. Для действий такого ограничения нет. Внутри действий можно выполнять **асинхронные** операции:
 
 ```js
 actions: {

+ 8 - 2
docs/ru/guide/modules.md

@@ -33,7 +33,7 @@ store.state.b // -> состояние модуля `moduleB`
 
 ### Локальное состояние модулей
 
-Первым аргументом, который получают мутации и геттеры, будет **локальное состояние модуля**.
+Первым аргументом, который получает мутации и геттеры, будет **локальное состояние модуля**.
 
 ```js
 const moduleA = {
@@ -85,7 +85,7 @@ const moduleA = {
 
 По умолчанию действия, мутации и геттеры внутри модулей регистрируются в **глобальном пространстве имён** — это позволяет нескольким модулям реагировать на тот же тип мутаций/действий.
 
-Если вы хотите сделать модули более самодостаточными и готовыми для переиспользования, вы можете создать его с собственным пространством имён, указав опцию `namespaced: true`. Когда модуль будет зарегистрирован, все его геттеры, действия и мутации будут автоматически связаны с этим пространством имён, основываясь на пути по которому зарегистрирован модуль. Например:
+Если вы хотите сделать модули более самодостаточными и готовыми для переиспользования, вы можете создать его с собственным пространством имён, указав опцию `namespaced: true`. Когда модуль будет зарегистрирован, все его геттеры, действия и мутации будут автоматически связаны с этим пространством имён, основываясь на пути, по которому зарегистрирован модуль. Например:
 
 ```js
 const store = new Vuex.Store({
@@ -277,6 +277,10 @@ export function createPlugin(options = {}) {
 Вы можете зарегистрировать модуль уже и **после** того, как хранилище было создано, используя метод `store.registerModule`:
 
 ```js
+import Vuex from 'vuex'
+
+const store = new Vuex.Store({ /* опции */ })
+
 // регистрация модуля `myModule`
 store.registerModule('myModule', {
   // ...
@@ -294,6 +298,8 @@ store.registerModule(['nested', 'myModule'], {
 
 Удалить динамически зарегистрированный модуль можно с помощью `store.unregisterModule(moduleName)`. Обратите внимание, что статические (определённые на момент создания хранилища) модули при помощи этого метода удалить не получится.
 
+Обратите внимание, что можно проверить, зарегистрирован ли уже модуль с заданным именем с помощью метода `store.hasModule(moduleName)`.
+
 #### Сохранение состояния
 
 Вероятно, вы хотите сохранить предыдущее состояние при регистрации нового модуля, например сохранить состояние из приложения с рендерингом на стороне сервера. Вы можете этого добиться с помощью опции `preserveState`: `store.registerModule('a', module, { preserveState: true })`.

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

@@ -111,7 +111,7 @@ export default {
 如果你想将一个 getter 属性另取一个名字,使用对象形式:
 
 ``` js
-mapGetters({
+...mapGetters({
   // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
   doneCount: 'doneTodosCount'
 })

+ 2 - 0
package.json

@@ -25,6 +25,7 @@
     "test:e2e": "node test/e2e/runner.js",
     "test:ssr": "rollup -c build/rollup.dev.config.js && cross-env VUE_ENV=server jasmine JASMINE_CONFIG_PATH=test/unit/jasmine.json",
     "test:types": "tsc -p types/test",
+    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
     "release": "bash build/release.sh",
     "docs": "vuepress dev docs",
     "docs:build": "vuepress build docs"
@@ -50,6 +51,7 @@
     "babel-polyfill": "^6.22.0",
     "babel-preset-env": "^1.5.1",
     "chromedriver": "^80.0.1",
+    "conventional-changelog-cli": "^2.0.31",
     "cross-env": "^5.2.0",
     "cross-spawn": "^6.0.5",
     "css-loader": "^2.1.0",

+ 7 - 0
src/module/module-collection.js

@@ -53,6 +53,13 @@ export default class ModuleCollection {
 
     parent.removeChild(key)
   }
+
+  isRegistered (path) {
+    const parent = this.get(path.slice(0, -1))
+    const key = path[path.length - 1]
+
+    return parent.hasChild(key)
+  }
 }
 
 function update (path, targetModule, newModule) {

+ 4 - 0
src/module/module.js

@@ -30,6 +30,10 @@ export default class Module {
     return this._children[key]
   }
 
+  hasChild (key) {
+    return key in this._children
+  }
+
   update (rawModule) {
     this._rawModule.namespaced = rawModule.namespaced
     if (rawModule.actions) {

+ 10 - 0
src/store.js

@@ -213,6 +213,16 @@ export class Store {
     resetStore(this)
   }
 
+  hasModule (path) {
+    if (typeof path === 'string') path = [path]
+
+    if (process.env.NODE_ENV !== 'production') {
+      assert(Array.isArray(path), `module path must be a string or an Array.`)
+    }
+
+    return this._modules.isRegistered(path)
+  }
+
   hotUpdate (newOptions) {
     this._modules.update(newOptions)
     resetStore(this, true)

+ 10 - 0
test/unit/modules.spec.js

@@ -81,6 +81,16 @@ describe('Modules', () => {
       expect(mutationSpy).toHaveBeenCalled()
     })
 
+    it('dynamic module existance test', () => {
+      const store = new Vuex.Store({})
+
+      store.registerModule('bonjour', {})
+
+      expect(store.hasModule('bonjour')).toBe(true)
+      store.unregisterModule('bonjour')
+      expect(store.hasModule('bonjour')).toBe(false)
+    })
+
     it('dynamic module registration preserving hydration', () => {
       const store = new Vuex.Store({})
       store.replaceState({ a: { foo: 'state' }})

+ 3 - 0
types/index.d.ts

@@ -28,6 +28,9 @@ export declare class Store<S> {
   unregisterModule(path: string): void;
   unregisterModule(path: string[]): void;
 
+  hasModule(path: string): boolean;
+  hasModule(path: string[]): boolean;
+
   hotUpdate(options: {
     actions?: ActionTree<S, S>;
     mutations?: MutationTree<S>;

+ 4 - 0
types/test/index.ts

@@ -292,6 +292,8 @@ namespace RegisterModule {
     state: { value: 1 }
   });
 
+  store.hasModule('a')
+
   store.registerModule(["a", "b"], {
     state: { value: 2 }
   });
@@ -300,6 +302,8 @@ namespace RegisterModule {
     state: { value: 2 }
   }, { preserveState: true });
 
+  store.hasModule(['a', 'b'])
+
   store.unregisterModule(["a", "b"]);
   store.unregisterModule("a");
 }

+ 568 - 14
yarn.lock

@@ -1211,6 +1211,14 @@
   resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8"
   integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==
 
+JSONStream@^1.0.4:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
+  integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
+  dependencies:
+    jsonparse "^1.2.0"
+    through ">=2.2.7 <3"
+
 abab@^2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a"
@@ -1281,6 +1289,11 @@ acorn@^7.1.1:
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
   integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==
 
+add-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa"
+  integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=
+
 agent-base@4, agent-base@^4.2.0, agent-base@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
@@ -1501,6 +1514,11 @@ array-flatten@1.1.1:
   resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
   integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
 
+array-ify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece"
+  integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=
+
 array-union@^1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
@@ -2653,6 +2671,14 @@ camel-case@3.0.x:
     no-case "^2.2.0"
     upper-case "^1.1.1"
 
+camelcase-keys@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
+  integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
+  dependencies:
+    camelcase "^2.0.0"
+    map-obj "^1.0.0"
+
 camelcase-keys@^4.0.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77"
@@ -2662,6 +2688,11 @@ camelcase-keys@^4.0.0:
     map-obj "^2.0.0"
     quick-lru "^1.0.0"
 
+camelcase@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+  integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
+
 camelcase@^4.0.0, camelcase@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
@@ -3000,6 +3031,11 @@ commander@^2.19.0:
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
   integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
 
+commander@~2.20.3:
+  version "2.20.3"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
 common-tags@^1.4.0:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@@ -3010,6 +3046,14 @@ commondir@^1.0.1:
   resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
   integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
 
+compare-func@^1.3.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.2.tgz#99dd0ba457e1f9bc722b12c08ec33eeab31fa648"
+  integrity sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=
+  dependencies:
+    array-ify "^1.0.0"
+    dot-prop "^3.0.0"
+
 component-emitter@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
@@ -3098,6 +3142,163 @@ content-type@^1.0.4, content-type@~1.0.4:
   resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
   integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
 
+conventional-changelog-angular@^5.0.6:
+  version "5.0.6"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz#269540c624553aded809c29a3508fdc2b544c059"
+  integrity sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==
+  dependencies:
+    compare-func "^1.3.1"
+    q "^1.5.1"
+
+conventional-changelog-atom@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-atom/-/conventional-changelog-atom-2.0.3.tgz#3bd14280aa09fe3ec49a0e8fe97b5002db02aad4"
+  integrity sha512-szZe2ut97qNO6vCCMkm1I/tWu6ol4Rr8a9Lx0y/VlpDnpY0PNp+oGpFgU55lplhx+I3Lro9Iv4/gRj0knfgjzg==
+  dependencies:
+    q "^1.5.1"
+
+conventional-changelog-cli@^2.0.31:
+  version "2.0.31"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-cli/-/conventional-changelog-cli-2.0.31.tgz#3345581170fbb540416946e460fef519a64aef43"
+  integrity sha512-nMINylKAamBLM3OmD7/44d9TPZ3V58IDTXoGC/QtXxve+1Sj37BQTzIEW3TNaviZ2ZV/b5Dqg0eSk4DNP5fBdA==
+  dependencies:
+    add-stream "^1.0.0"
+    conventional-changelog "^3.1.18"
+    lodash "^4.17.15"
+    meow "^5.0.0"
+    tempfile "^3.0.0"
+
+conventional-changelog-codemirror@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.3.tgz#ebc088154684f8f5171446b8d546ba6b460d46f2"
+  integrity sha512-t2afackdgFV2yBdHhWPqrKbpaQeVnz2hSJKdWqjasPo5EpIB6TBL0er3cOP1mnGQmuzk9JSvimNSuqjWGDtU5Q==
+  dependencies:
+    q "^1.5.1"
+
+conventional-changelog-conventionalcommits@^4.2.3:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.3.tgz#22855b32d57d0328951c1c2dc01b172a5f24ea37"
+  integrity sha512-atGa+R4vvEhb8N/8v3IoW59gCBJeeFiX6uIbPu876ENAmkMwsenyn0R21kdDHJFLQdy6zW4J6b4xN8KI3b9oww==
+  dependencies:
+    compare-func "^1.3.1"
+    lodash "^4.17.15"
+    q "^1.5.1"
+
+conventional-changelog-core@^4.1.4:
+  version "4.1.4"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.1.4.tgz#39be27fca6ef20a0f998d7a3a1e97cfa8a055cb6"
+  integrity sha512-LO58ZbEpp1Ul+y/vOI8rJRsWkovsYkCFbOCVgi6UnVfU8WC0F8K8VQQwaBZWWUpb6JvEiN4GBR5baRP2txZ+Vg==
+  dependencies:
+    add-stream "^1.0.0"
+    conventional-changelog-writer "^4.0.11"
+    conventional-commits-parser "^3.0.8"
+    dateformat "^3.0.0"
+    get-pkg-repo "^1.0.0"
+    git-raw-commits "2.0.0"
+    git-remote-origin-url "^2.0.0"
+    git-semver-tags "^3.0.1"
+    lodash "^4.17.15"
+    normalize-package-data "^2.3.5"
+    q "^1.5.1"
+    read-pkg "^3.0.0"
+    read-pkg-up "^3.0.0"
+    through2 "^3.0.0"
+
+conventional-changelog-ember@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-ember/-/conventional-changelog-ember-2.0.4.tgz#c29b78e4af7825cbecb6c3fd6086ca5c09471ac1"
+  integrity sha512-q1u73sO9uCnxN4TSw8xu6MRU8Y1h9kpwtcdJuNRwu/LSKI1IE/iuNSH5eQ6aLlQ3HTyrIpTfUuVybW4W0F17rA==
+  dependencies:
+    q "^1.5.1"
+
+conventional-changelog-eslint@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.4.tgz#8f4736a23e0cd97e890e76fccc287db2f205f2ff"
+  integrity sha512-CPwTUENzhLGl3auunrJxiIEWncAGaby7gOFCdj2gslIuOFJ0KPJVOUhRz4Da/I53sdo/7UncUJkiLg94jEsjxg==
+  dependencies:
+    q "^1.5.1"
+
+conventional-changelog-express@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-express/-/conventional-changelog-express-2.0.1.tgz#fea2231d99a5381b4e6badb0c1c40a41fcacb755"
+  integrity sha512-G6uCuCaQhLxdb4eEfAIHpcfcJ2+ao3hJkbLrw/jSK/eROeNfnxCJasaWdDAfFkxsbpzvQT4W01iSynU3OoPLIw==
+  dependencies:
+    q "^1.5.1"
+
+conventional-changelog-jquery@^3.0.6:
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.6.tgz#460236ad8fb1d29ff932a14fe4e3a45379b63c5e"
+  integrity sha512-gHAABCXUNA/HjnZEm+vxAfFPJkgtrZvCDIlCKfdPVXtCIo/Q0lN5VKpx8aR5p8KdVRQFF3OuTlvv5kv6iPuRqA==
+  dependencies:
+    q "^1.5.1"
+
+conventional-changelog-jshint@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.3.tgz#ef6e2caf2ee6ffdfda78fcdf7ce87cf6c512d728"
+  integrity sha512-Pc2PnMPcez634ckzr4EOWviwRSpZcURaK7bjyD9oK6N5fsC/a+3G7LW5m/JpcHPhA9ZxsfIbm7uqZ3ZDGsQ/sw==
+  dependencies:
+    compare-func "^1.3.1"
+    q "^1.5.1"
+
+conventional-changelog-preset-loader@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.0.tgz#580fa8ab02cef22c24294d25e52d7ccd247a9a6a"
+  integrity sha512-/rHb32J2EJnEXeK4NpDgMaAVTFZS3o1ExmjKMtYVgIC4MQn0vkNSbYpdGRotkfGGRWiqk3Ri3FBkiZGbAfIfOQ==
+
+conventional-changelog-writer@^4.0.11:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz#9f56d2122d20c96eb48baae0bf1deffaed1edba4"
+  integrity sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw==
+  dependencies:
+    compare-func "^1.3.1"
+    conventional-commits-filter "^2.0.2"
+    dateformat "^3.0.0"
+    handlebars "^4.4.0"
+    json-stringify-safe "^5.0.1"
+    lodash "^4.17.15"
+    meow "^5.0.0"
+    semver "^6.0.0"
+    split "^1.0.0"
+    through2 "^3.0.0"
+
+conventional-changelog@^3.1.18:
+  version "3.1.18"
+  resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-3.1.18.tgz#7da0a5ab34a604b920b8bf71c6cf5d952f0e805e"
+  integrity sha512-aN6a3rjgV8qwAJj3sC/Lme2kvswWO7fFSGQc32gREcwIOsaiqBaO6f2p0NomFaPDnTqZ+mMZFLL3hlzvEnZ0mQ==
+  dependencies:
+    conventional-changelog-angular "^5.0.6"
+    conventional-changelog-atom "^2.0.3"
+    conventional-changelog-codemirror "^2.0.3"
+    conventional-changelog-conventionalcommits "^4.2.3"
+    conventional-changelog-core "^4.1.4"
+    conventional-changelog-ember "^2.0.4"
+    conventional-changelog-eslint "^3.0.4"
+    conventional-changelog-express "^2.0.1"
+    conventional-changelog-jquery "^3.0.6"
+    conventional-changelog-jshint "^2.0.3"
+    conventional-changelog-preset-loader "^2.3.0"
+
+conventional-commits-filter@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz#f122f89fbcd5bb81e2af2fcac0254d062d1039c1"
+  integrity sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==
+  dependencies:
+    lodash.ismatch "^4.4.0"
+    modify-values "^1.0.0"
+
+conventional-commits-parser@^3.0.8:
+  version "3.0.8"
+  resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz#23310a9bda6c93c874224375e72b09fb275fe710"
+  integrity sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ==
+  dependencies:
+    JSONStream "^1.0.4"
+    is-text-path "^1.0.1"
+    lodash "^4.17.15"
+    meow "^5.0.0"
+    split2 "^2.0.0"
+    through2 "^3.0.0"
+    trim-off-newlines "^1.0.0"
+
 convert-source-map@^1.1.0, convert-source-map@^1.5.1:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
@@ -3444,6 +3645,13 @@ d@1:
   dependencies:
     es5-ext "^0.10.9"
 
+dargs@^4.0.1:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17"
+  integrity sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=
+  dependencies:
+    number-is-nan "^1.0.0"
+
 dashdash@^1.12.0:
   version "1.14.1"
   resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -3470,6 +3678,11 @@ date-now@^0.1.4:
   resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
   integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=
 
+dateformat@^3.0.0:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
+  integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
+
 de-indent@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
@@ -3794,6 +4007,13 @@ domutils@1.5.1:
     dom-serializer "0"
     domelementtype "1"
 
+dot-prop@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
+  integrity sha1-G3CK8JSknJoOfbyteQq6U52sEXc=
+  dependencies:
+    is-obj "^1.0.0"
+
 dot-prop@^4.1.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
@@ -3913,7 +4133,7 @@ errno@^0.1.3, errno@~0.1.7:
   dependencies:
     prr "~1.0.1"
 
-error-ex@^1.3.1:
+error-ex@^1.2.0, error-ex@^1.3.1:
   version "1.3.2"
   resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
   integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
@@ -4527,6 +4747,14 @@ find-up@3.0.0, find-up@^3.0.0:
   dependencies:
     locate-path "^3.0.0"
 
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
 find-up@^2.0.0, find-up@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
@@ -4717,11 +4945,27 @@ get-own-enumerable-property-symbols@^3.0.0:
   resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203"
   integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==
 
+get-pkg-repo@^1.0.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz#c73b489c06d80cc5536c2c853f9e05232056972d"
+  integrity sha1-xztInAbYDMVTbCyFP54FIyBWly0=
+  dependencies:
+    hosted-git-info "^2.1.4"
+    meow "^3.3.0"
+    normalize-package-data "^2.3.0"
+    parse-github-repo-url "^1.3.0"
+    through2 "^2.0.0"
+
 get-port@^3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc"
   integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=
 
+get-stdin@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
+  integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
+
 get-stream@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -4751,6 +4995,40 @@ getpass@^0.1.1:
   dependencies:
     assert-plus "^1.0.0"
 
+git-raw-commits@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.0.tgz#d92addf74440c14bcc5c83ecce3fb7f8a79118b5"
+  integrity sha512-w4jFEJFgKXMQJ0H0ikBk2S+4KP2VEjhCvLCNqbNRQC8BgGWgLKNCO7a9K9LI+TVT7Gfoloje502sEnctibffgg==
+  dependencies:
+    dargs "^4.0.1"
+    lodash.template "^4.0.2"
+    meow "^4.0.0"
+    split2 "^2.0.0"
+    through2 "^2.0.0"
+
+git-remote-origin-url@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f"
+  integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=
+  dependencies:
+    gitconfiglocal "^1.0.0"
+    pify "^2.3.0"
+
+git-semver-tags@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-3.0.1.tgz#9cb9e4974437de1f71f32da3bfe74f4d35afb1b9"
+  integrity sha512-Hzd1MOHXouITfCasrpVJbRDg9uvW7LfABk3GQmXYZByerBDrfrEMP9HXpNT7RxAbieiocP6u+xq20DkvjwxnCA==
+  dependencies:
+    meow "^5.0.0"
+    semver "^6.0.0"
+
+gitconfiglocal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b"
+  integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=
+  dependencies:
+    ini "^1.3.2"
+
 glob-base@^0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
@@ -4923,6 +5201,18 @@ growl@1.10.5:
   resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
   integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
 
+handlebars@^4.4.0:
+  version "4.7.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e"
+  integrity sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==
+  dependencies:
+    minimist "^1.2.5"
+    neo-async "^2.6.0"
+    source-map "^0.6.1"
+    wordwrap "^1.0.0"
+  optionalDependencies:
+    uglify-js "^3.1.4"
+
 har-schema@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
@@ -5300,6 +5590,13 @@ imurmurhash@^0.1.4:
   resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
   integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
 
+indent-string@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+  integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
+  dependencies:
+    repeating "^2.0.0"
+
 indent-string@^3.0.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
@@ -5343,7 +5640,7 @@ inherits@2.0.4:
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
 
-ini@^1.3.4, ini@~1.3.0:
+ini@^1.3.2, ini@^1.3.4, ini@~1.3.0:
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
   integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
@@ -5721,6 +6018,13 @@ is-symbol@^1.0.2:
   dependencies:
     has-symbols "^1.0.0"
 
+is-text-path@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e"
+  integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=
+  dependencies:
+    text-extensions "^1.0.0"
+
 is-typedarray@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@@ -5731,6 +6035,11 @@ is-url@^1.2.2:
   resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
   integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
 
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+  integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+
 is-windows@^1.0.0, is-windows@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -5957,6 +6266,11 @@ jsonfile@^4.0.0:
   optionalDependencies:
     graceful-fs "^4.1.6"
 
+jsonparse@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
+  integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
+
 jsprim@^1.2.2:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@@ -6135,6 +6449,17 @@ linkify-it@^2.0.0:
   dependencies:
     uc.micro "^1.0.1"
 
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
 load-json-file@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@@ -6298,6 +6623,11 @@ lodash.isarray@^3.0.0:
   resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
   integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=
 
+lodash.ismatch@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37"
+  integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=
+
 lodash.keys@^3.0.0:
   version "3.1.2"
   resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
@@ -6322,7 +6652,7 @@ lodash.sortby@^4.7.0:
   resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
   integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
 
-lodash.template@^4.4.0:
+lodash.template@^4.0.2, lodash.template@^4.4.0:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
   integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==
@@ -6442,7 +6772,7 @@ map-cache@^0.2.2:
   resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
   integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
 
-map-obj@^1.0.0:
+map-obj@^1.0.0, map-obj@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
   integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
@@ -6527,6 +6857,37 @@ memory-fs@^0.4.0, memory-fs@~0.4.1:
     errno "^0.1.3"
     readable-stream "^2.0.1"
 
+meow@^3.3.0:
+  version "3.7.0"
+  resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
+  integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
+  dependencies:
+    camelcase-keys "^2.0.0"
+    decamelize "^1.1.2"
+    loud-rejection "^1.0.0"
+    map-obj "^1.0.1"
+    minimist "^1.1.3"
+    normalize-package-data "^2.3.4"
+    object-assign "^4.0.1"
+    read-pkg-up "^1.0.1"
+    redent "^1.0.0"
+    trim-newlines "^1.0.0"
+
+meow@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/meow/-/meow-4.0.1.tgz#d48598f6f4b1472f35bf6317a95945ace347f975"
+  integrity sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==
+  dependencies:
+    camelcase-keys "^4.0.0"
+    decamelize-keys "^1.0.0"
+    loud-rejection "^1.0.0"
+    minimist "^1.1.3"
+    minimist-options "^3.0.1"
+    normalize-package-data "^2.3.4"
+    read-pkg-up "^3.0.0"
+    redent "^2.0.0"
+    trim-newlines "^2.0.0"
+
 meow@^5.0.0:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4"
@@ -6713,6 +7074,11 @@ minimist@0.0.8:
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
   integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
 
+minimist@^1.1.3, minimist@^1.2.5:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
+  integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+
 minimist@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
@@ -6829,6 +7195,11 @@ mocha@^6.2.2:
     yargs-parser "13.1.1"
     yargs-unparser "1.6.0"
 
+modify-values@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
+  integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
+
 move-concurrently@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -6945,6 +7316,11 @@ neo-async@^2.5.0:
   resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835"
   integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==
 
+neo-async@^2.6.0:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
+  integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
+
 netmask@^1.0.6:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
@@ -7064,6 +7440,16 @@ nopt@^4.0.1:
     abbrev "1"
     osenv "^0.1.4"
 
+normalize-package-data@^2.3.0, normalize-package-data@^2.3.5:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+  dependencies:
+    hosted-git-info "^2.1.4"
+    resolve "^1.10.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
 normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
   version "2.4.0"
   resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
@@ -7447,6 +7833,11 @@ parse-asn1@^5.0.0:
     pbkdf2 "^3.0.3"
     safe-buffer "^5.1.1"
 
+parse-github-repo-url@^1.3.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50"
+  integrity sha1-nn2LslKmy2ukJZUGC3v23z28H1A=
+
 parse-glob@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
@@ -7457,6 +7848,13 @@ parse-glob@^3.0.4:
     is-extglob "^1.0.0"
     is-glob "^2.0.0"
 
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+  dependencies:
+    error-ex "^1.2.0"
+
 parse-json@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -7490,6 +7888,13 @@ path-dirname@^1.0.0:
   resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
   integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
 
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
+  dependencies:
+    pinkie-promise "^2.0.0"
+
 path-exists@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
@@ -7520,6 +7925,15 @@ path-to-regexp@0.1.7:
   resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
   integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
 
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
 path-type@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -7558,11 +7972,28 @@ picomatch@^2.0.5, picomatch@^2.2.1:
   resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
   integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
 
+pify@^2.0.0, pify@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+  integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
 pify@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
   integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
 
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+  integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
 pkg-dir@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
@@ -8135,7 +8566,7 @@ punycode@^1.2.4, punycode@^1.4.1:
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
   integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
 
-q@^1.1.2:
+q@^1.1.2, q@^1.5.1:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
   integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
@@ -8227,6 +8658,14 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
     minimist "^1.2.0"
     strip-json-comments "~2.0.1"
 
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
 read-pkg-up@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
@@ -8235,6 +8674,15 @@ read-pkg-up@^3.0.0:
     find-up "^2.0.0"
     read-pkg "^3.0.0"
 
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
 read-pkg@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
@@ -8277,6 +8725,15 @@ readable-stream@1.1.x:
     isarray "0.0.1"
     string_decoder "~0.10.x"
 
+"readable-stream@2 || 3":
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
+  integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
 readdirp@^2.0.0:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
@@ -8286,6 +8743,14 @@ readdirp@^2.0.0:
     micromatch "^3.1.10"
     readable-stream "^2.0.2"
 
+redent@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
+  integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
+  dependencies:
+    indent-string "^2.1.0"
+    strip-indent "^1.0.1"
+
 redent@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
@@ -8615,6 +9080,13 @@ resolve-url@^0.2.1:
   resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
   integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
 
+resolve@^1.10.0:
+  version "1.16.1"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.16.1.tgz#49fac5d8bacf1fd53f200fa51247ae736175832c"
+  integrity sha512-rmAglCSqWWMrrBv/XM6sW0NuRFiKViw/W4d9EbC4pt+49H8JwHy+mcGmALTEg504AUDcLTvb1T2q3E9AnmY+ig==
+  dependencies:
+    path-parse "^1.0.6"
+
 resolve@^1.2.0, resolve@^1.3.2, resolve@^1.6.0:
   version "1.9.0"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06"
@@ -8735,6 +9207,11 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
   integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
 
+safe-buffer@~5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
 safe-regex@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
@@ -8811,7 +9288,7 @@ semver@^5.7.0:
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
   integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
 
-semver@^6.3.0:
+semver@^6.0.0, semver@^6.3.0:
   version "6.3.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
   integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
@@ -9108,6 +9585,20 @@ split-string@^3.0.1, split-string@^3.0.2:
   dependencies:
     extend-shallow "^3.0.0"
 
+split2@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493"
+  integrity sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==
+  dependencies:
+    through2 "^2.0.2"
+
+split@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
+  integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
+  dependencies:
+    through "2"
+
 sprintf-js@~1.0.2:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
@@ -9252,6 +9743,13 @@ string_decoder@^1.0.0:
   dependencies:
     safe-buffer "~5.1.0"
 
+string_decoder@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+  dependencies:
+    safe-buffer "~5.2.0"
+
 string_decoder@~0.10.x:
   version "0.10.31"
   resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
@@ -9313,6 +9811,13 @@ strip-bom-string@^1.0.0:
   resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92"
   integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=
 
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+  dependencies:
+    is-utf8 "^0.2.0"
+
 strip-bom@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
@@ -9331,6 +9836,13 @@ strip-eof@^1.0.0:
   resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
   integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
 
+strip-indent@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
+  integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
+  dependencies:
+    get-stdin "^4.0.1"
+
 strip-indent@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
@@ -9468,6 +9980,19 @@ tcp-port-used@^1.0.1:
     debug "4.1.0"
     is2 "2.0.1"
 
+temp-dir@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e"
+  integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==
+
+tempfile@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-3.0.0.tgz#5376a3492de7c54150d0cc0612c3f00e2cdaf76c"
+  integrity sha512-uNFCg478XovRi85iD42egu+eSFUmmka750Jy7L5tfHI5hQKKtbPnxaSaXAbBqCDYrw3wx4tXjKwci4/QmsZJxw==
+  dependencies:
+    temp-dir "^2.0.0"
+    uuid "^3.3.2"
+
 term-size@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
@@ -9507,6 +10032,11 @@ terser@^3.8.1:
     source-map "~0.6.1"
     source-map-support "~0.5.6"
 
+text-extensions@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26"
+  integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==
+
 text-table@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -9526,7 +10056,7 @@ thenify-all@^1.0.0:
   dependencies:
     any-promise "^1.0.0"
 
-through2@^2.0.0:
+through2@^2.0.0, through2@^2.0.2:
   version "2.0.5"
   resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
   integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
@@ -9534,7 +10064,14 @@ through2@^2.0.0:
     readable-stream "~2.3.6"
     xtend "~4.0.1"
 
-through@^2.3.6, through@~2.3.4:
+through2@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a"
+  integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==
+  dependencies:
+    readable-stream "2 || 3"
+
+through@2, "through@>=2.2.7 <3", through@^2.3.6, through@~2.3.4:
   version "2.3.8"
   resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
   integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
@@ -9689,11 +10226,21 @@ tr46@^2.0.0:
   dependencies:
     punycode "^2.1.1"
 
+trim-newlines@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
+  integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
+
 trim-newlines@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20"
   integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=
 
+trim-off-newlines@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3"
+  integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM=
+
 trim-right@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
@@ -9764,6 +10311,13 @@ uglify-js@3.4.x:
     commander "~2.17.1"
     source-map "~0.6.1"
 
+uglify-js@^3.1.4:
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.9.1.tgz#a56a71c8caa2d36b5556cc1fd57df01ae3491539"
+  integrity sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA==
+  dependencies:
+    commander "~2.20.3"
+
 unicode-canonical-property-names-ecmascript@^1.0.4:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
@@ -9923,7 +10477,7 @@ use@^3.1.0:
   resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
   integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
 
-util-deprecate@~1.0.1:
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
   integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
@@ -10439,16 +10993,16 @@ widest-line@^2.0.0:
   dependencies:
     string-width "^2.1.1"
 
+wordwrap@^1.0.0, wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+  integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
+
 wordwrap@~0.0.2:
   version "0.0.3"
   resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
   integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
 
-wordwrap@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
-  integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
-
 workbox-background-sync@^3.6.3:
   version "3.6.3"
   resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-3.6.3.tgz#6609a0fac9eda336a7c52e6aa227ba2ae532ad94"

部分文件因为文件数量过多而无法显示