Merge branch 'dev' into move_to_typescript

# Conflicts:
#	dist/vue.common.dev.js
#	dist/vue.common.prod.js
#	dist/vue.esm.browser.js
#	dist/vue.esm.browser.min.js
#	dist/vue.esm.js
#	dist/vue.js
#	dist/vue.min.js
#	dist/vue.runtime.common.dev.js
#	dist/vue.runtime.common.prod.js
#	dist/vue.runtime.esm.js
#	dist/vue.runtime.js
#	dist/vue.runtime.min.js
#	packages/vue-server-renderer/basic.js
#	packages/vue-server-renderer/build.dev.js
#	packages/vue-server-renderer/build.prod.js
#	packages/vue-server-renderer/client-plugin.js
#	packages/vue-server-renderer/server-plugin.js
#	packages/vue-template-compiler/browser.js
#	packages/vue-template-compiler/build.js
#	packages/weex-template-compiler/build.js
#	packages/weex-vue-framework/index.js
#	src/compiler/codegen/index.ts
#	src/core/components/keep-alive.ts
#	src/core/instance/lifecycle.js
#	src/core/instance/render-helpers/render-slot.ts
#	src/core/instance/state.ts
#	src/core/observer/watcher.ts
#	src/core/vdom/helpers/normalize-scoped-slots.ts
#	src/core/vdom/patch.ts
#	src/platforms/web/runtime/modules/events.ts
#	src/platforms/weex/entry-framework.ts
#	src/server/webpack-plugin/client.js
#	src/server/webpack-plugin/server.ts
#	src/server/webpack-plugin/util.ts
#	yarn.lock
This commit is contained in:
Carlos Rodrigues 2022-04-29 19:40:58 +01:00
commit da64b4a41f
51 changed files with 31079 additions and 26241 deletions

View File

@ -124,15 +124,7 @@ The default test script will do the following: lint with ESLint -> type check wi
## Financial Contribution
As a pure community-driven project without major corporate backing, we also welcome financial contributions via Patreon and OpenCollective.
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou)
- [Become a backer or sponsor on OpenCollective](https://opencollective.com/vuejs)
- [One-time donation via PayPal or crypto-currencies](https://vuejs.org/support-vuejs/#One-time-Donations)
### What's the difference between Patreon and OpenCollective funding?
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
As a pure community-driven project without major corporate backing, we also welcome financial contributions via GitHub Sponsors and OpenCollective. Please consult the [Sponsor Page](https://vuejs.org/sponsor/) for more details.
## Credits

View File

@ -1,488 +1,9 @@
<h1 align="center">Sponsors &amp; Backers</h1>
Vue.js is an MIT-licensed open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [backers](https://github.com/vuejs/vue/blob/dev/BACKERS.md). If you'd like to join them, please consider:
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou).
- [Become a backer or sponsor on OpenCollective](https://opencollective.com/vuejs).
- [One-time donation via PayPal or crypto-currencies.](https://vuejs.org/support-vuejs/#One-time-Donations)
#### What's the difference between Patreon and OpenCollective?
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
<br><br>
<h2 align="center">Special Sponsors</h2>
<!--special start-->
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of the awesome sponsors and backers listed in this file. If you'd like to join them, please consider [ sponsor Vue's development](https://vuejs.org/sponsor/).
<p align="center">
<a href="https://autocode.com/" target="_blank">
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true">
<a target="_blank" href="https://sponsors.vuejs.org/backers.svg">
<img alt="sponsors" src="https://sponsors.vuejs.org/backers.svg">
</a>
</p>
<!--special end-->
<h2 align="center">Platinum via Patreon</h2>
<!--platinum start-->
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vueschool.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://vehikl.com/" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vehikl.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/retool.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://passionatepeople.io/" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/passionate_people.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.storyblok.com" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/storyblok.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/ionic.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://nuxtjs.org/" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/nuxt.png">
</a>
</td>
</tr><tr></tr>
</tbody>
</table>
<!--platinum end-->
<!--special-china start-->
<h3 align="center">Platinum Sponsors (China)</h3>
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci=" target="_blank">
<img width="177px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/dcloud.gif">
</a>
</td>
</tr><tr></tr>
</tbody>
</table>
<!--special-china end-->
<h2 align="center">Platinum via OpenCollective</h2>
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/avatar.svg"></a>
<h2 align="center">Gold via Patreon</h2>
<!--gold start-->
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://www.vuemastery.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuemastery.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://laravel.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/laravel.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://htmlburger.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/html_burger.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.frontenddeveloperlove.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/frontendlove.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neds.com.au/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/neds.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://icons8.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/icons_8.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://vuejobs.com/?ref=vuejs" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuejobs.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://tidelift.com/subscription/npm/vue" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tidelift.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.firesticktricks.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/firestick_tricks.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://intygrate.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/intygrate.png">
</a>
</td>
<td align="center" valign="middle">
<a href="http://en.shopware.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/shopware_ag.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.vpnranks.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpnranks.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.bacancytechnology.com/hire-vuejs-developer" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bacancy_technology.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.bestvpn.co/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bestvpn_co.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.y8.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/y8.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://js.devexpress.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/devexpress.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://fastcoding.jp/javascript/ " target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/fastcoding_inc.svg?sanitize=true">
</a>
</td>
<td align="center" valign="middle">
<a href="https://usave.co.uk/utilities/broadband" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/usave.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.foo.software" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/foo.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://flatlogic.com/templates" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/flatlogic_templates.svg?sanitize=true">
</a>
</td>
<td align="center" valign="middle">
<a href="http://moovweb.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/moovweb.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://vpn-review.com/netflix-vpn" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpn_review.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://cosmos.network/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tendermint.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.okayhq.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/okay.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.vpsserver.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpsserver_com.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://aussiecasinohex.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/aussiecasinohex.svg?sanitize=true">
</a>
</td>
<td align="center" valign="middle">
<a href="https://litslink.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/litslink.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://newicon.net" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/newicon.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://lowdefy.com?k=w432" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/lowdefy.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://quickbookstoolhub.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/quickbooks_tool_hub.png">
</a>
</td>
</tr><tr></tr>
</tbody>
</table>
<!--gold end-->
<h2 align="center">Gold via OpenCollective</h2>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/0/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/1/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/2/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/2/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/3/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/3/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/4/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/4/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/5/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/5/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/6/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/6/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/7/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/7/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/8/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/8/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/9/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/9/avatar.svg" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/10/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/10/avatar.svg" height="60px"></a>
<h2 align="center">Silver via Patreon</h2>
- Matt Mullenweg
<!--silver start-->
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://roadster.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/roadster.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.inkoop.io" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/inkoop.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.thecasinodb.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/isolutions_uk_limited.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://teamextension.io" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/team_extension_north_america_inc.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://freebets.us" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/free_bets_us.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://betting.bet" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/betting_bet.png">
</a>
</td>
</tr><tr></tr>
</tbody>
</table>
<!--silver end-->
<h4 align="center">Silver via OpenCollective</h4>
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/0/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/1/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/2/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/2/avatar.svg"></a>
<h2 align="center">Bronze via Patreon</h2>
<!--bronze start-->
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://www.accelebrate.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/accelebrate.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://polyglotengineer.com/derek.pollard" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/derek_pollard.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.earthlink.ro" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/earthlink.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.webucator.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/webucator.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://memberful.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/memberful.png">
</a>
</td>
</tr><tr></tr>
</tbody>
</table>
<!--bronze end-->
<h2 align="center">Bronze via OpenCollective</h2>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/0/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/1/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/2/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/2/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/3/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/3/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/4/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/4/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/5/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/5/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/6/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/6/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/7/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/7/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/8/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/8/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/9/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/9/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/10/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/10/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/11/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/11/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/12/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/12/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/13/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/13/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/14/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/14/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/15/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/15/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/16/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/16/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/17/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/17/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/18/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/18/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/19/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/19/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/20/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/20/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/21/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/21/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/22/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/22/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/23/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/23/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/24/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/24/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/25/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/25/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/26/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/26/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/27/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/27/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/28/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/28/avatar.svg"></a>
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/29/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/29/avatar.svg"></a>
<h2 align="center">Generous Backers via Patreon ($50+)</h2>
<!--50 start-->
- Yoshitaka M
- Peter Imburg
- Sean Ferguson
- Johnny Ray Austin
- errorrik
- Wasim Khamlichi
<!--50 end-->
<h2 align="center">Backers via Patreon</h2>
<!--10 start-->
- Sara McVey
- Keisuke Kita
- Alex Riviere
- Thomas Sittig
- WhereJuly
- Fontis
- Jack
- Nick Carr
- Artur Bańka
- Traversy Media
- Pierre Baron
- Donghai Gai
- Aleksander Figiel
- Faizal Andyka
- wickedwei
- Sunny Yuen
- Jules
- Zeth Odderskov
- Santi Sanchez Canals
- Thomas Wiedemann
- Nobuhide Esaki
- Roy Segall
- Allan McKernan
- 琚致远
- Diana Bergholz
- Riki Fridrich
- Alfonso Herrera
- Bichinger Software & Consulting
- username
- Pierre Lebrun
- Peter Matkovsky
- 龙腾道
- Nick Dandakis
- Yusuke Kawabata
- Shawn Wildermuth
- Andrew Willis
- Elon Hung
- Роман Латкин
- Juan Bermudez
- Hannes Kochniß
- Daniel Mattingley
- Matt Sencenbaugh
- Jaeyoung Lee
- David Kaplan
- David Ang
- Wakana Seki
- Jere Sjöroos
- Donald Fischer
- Eric
- tyler madsen
- Joe Gregory
- Masahiro Tanaka
- Tyler
- IMGNRY
- Jim Raden
- Haim Yulzari
- Anthony Estebe
- Asaf Yishai
- Jon Hobbs-Smith
- Pierre Vanhulst
- Zoran Knezevic
- Luiz
- Bernhard E. Reiter
- Guy Gavergun
- Matt Jones
- Niannian Modisette
- Matsumoto Takamasa
- Barbara Liau
- Wen-Tien Chang
- Stephen Michael Hartley
- Victor Tolbert
- Lars Andreas Ness
- Benjamin Listwon
- Chris Calo
<!--10 end-->
<h2 align="center">Backers via OpenCollective</h2>
<a href="https://opencollective.com/vuejs#backers" target="_blank"><img src="https://opencollective.com/vuejs/backers.svg?width=890"></a>

295
README.md
View File

@ -7,279 +7,21 @@
<a href="https://www.npmjs.com/package/vue"><img src="https://img.shields.io/npm/v/vue.svg?sanitize=true" alt="Version"></a>
<a href="https://www.npmjs.com/package/vue"><img src="https://img.shields.io/npm/l/vue.svg?sanitize=true" alt="License"></a>
<a href="https://chat.vuejs.org/"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true" alt="Chat"></a>
<br>
<a href="https://app.saucelabs.com/builds/50f8372d79f743a3b25fb6ca4851ca4c"><img src="https://app.saucelabs.com/buildstatus/vuejs" alt="Build Status"></a>
</p>
<h2 align="center">Supporting Vue.js</h2>
## This repo is for Vue 2
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/vue/blob/dev/BACKERS.md). If you'd like to join them, please consider:
You are looking at the repository for Vue 2. The repo for Vue 3 is [vuejs/core](https://github.com/vuejs/core).
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou).
- [Become a backer or sponsor on Open Collective](https://opencollective.com/vuejs).
- [One-time donation via PayPal or crypto-currencies.](https://vuejs.org/support-vuejs/#One-time-Donations)
## Sponsors
#### What's the difference between Patreon and OpenCollective?
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
<h3 align="center">Special Sponsors</h3>
<!--special start-->
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/core/blob/main/BACKERS.md). If you'd like to join them, please consider [ sponsor Vue's development](https://vuejs.org/sponsor/).
<p align="center">
<a href="https://autocode.com/" target="_blank">
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true">
<a target="_blank" href="https://vuejs.org/sponsor/">
<img alt="sponsors" src="https://sponsors.vuejs.org/sponsors.svg">
</a>
</p>
<!--special end-->
<h3 align="center">Platinum Sponsors</h3>
<!--platinum start-->
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vueschool.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://vehikl.com/" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vehikl.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/retool.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://passionatepeople.io/" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/passionate_people.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.storyblok.com" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/storyblok.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/ionic.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://nuxtjs.org/" target="_blank">
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/nuxt.png">
</a>
</td>
</tr><tr></tr>
</tbody>
</table>
<!--platinum end-->
<!--special-china start-->
<h3 align="center">Platinum Sponsors (China)</h3>
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci=" target="_blank">
<img width="177px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/dcloud.gif">
</a>
</td>
</tr><tr></tr>
</tbody>
</table>
<!--special-china end-->
<h3 align="center">Gold Sponsors</h3>
<!--gold start-->
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://www.vuemastery.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuemastery.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://laravel.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/laravel.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://htmlburger.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/html_burger.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.frontenddeveloperlove.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/frontendlove.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neds.com.au/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/neds.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://icons8.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/icons_8.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://vuejobs.com/?ref=vuejs" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuejobs.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://tidelift.com/subscription/npm/vue" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tidelift.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.firesticktricks.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/firestick_tricks.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://intygrate.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/intygrate.png">
</a>
</td>
<td align="center" valign="middle">
<a href="http://en.shopware.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/shopware_ag.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.vpnranks.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpnranks.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.bacancytechnology.com/hire-vuejs-developer" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bacancy_technology.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.bestvpn.co/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bestvpn_co.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.y8.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/y8.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://js.devexpress.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/devexpress.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://fastcoding.jp/javascript/ " target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/fastcoding_inc.svg?sanitize=true">
</a>
</td>
<td align="center" valign="middle">
<a href="https://usave.co.uk/utilities/broadband" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/usave.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.foo.software" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/foo.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://flatlogic.com/templates" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/flatlogic_templates.svg?sanitize=true">
</a>
</td>
<td align="center" valign="middle">
<a href="http://moovweb.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/moovweb.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://vpn-review.com/netflix-vpn" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpn_review.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://cosmos.network/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tendermint.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.okayhq.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/okay.png">
</a>
</td>
</tr><tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.vpsserver.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpsserver_com.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://aussiecasinohex.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/aussiecasinohex.svg?sanitize=true">
</a>
</td>
<td align="center" valign="middle">
<a href="https://litslink.com" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/litslink.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://newicon.net" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/newicon.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://lowdefy.com?k=w432" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/lowdefy.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://quickbookstoolhub.com/" target="_blank">
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/quickbooks_tool_hub.png">
</a>
</td>
</tr><tr></tr>
</tbody>
</table>
<!--gold end-->
<h3 align="center">Sponsors via <a href="https://opencollective.com/vuejs">Open Collective</a></h3>
<h4 align="center">Platinum</h4>
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/avatar.svg?sanitize=true"></a>
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/avatar.svg?sanitize=true"></a>
<h4 align="center">Gold</h4>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/0/avatar.svg?sanitize=true" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/1/avatar.svg?sanitize=true" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/2/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/2/avatar.svg?sanitize=true" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/3/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/3/avatar.svg?sanitize=true" height="60px"></a>
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/4/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/4/avatar.svg?sanitize=true" height="60px"></a>
---
@ -293,16 +35,16 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
## Ecosystem
| Project | Status | Description |
|---------|--------|-------------|
| [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing |
| [vuex] | [![vuex-status]][vuex-package] | Large-scale state management |
| [vue-cli] | [![vue-cli-status]][vue-cli-package] | Project scaffolding |
| [vue-loader] | [![vue-loader-status]][vue-loader-package] | Single File Component (`*.vue` file) loader for webpack |
| [vue-server-renderer] | [![vue-server-renderer-status]][vue-server-renderer-package] | Server-side rendering support |
| [vue-class-component] | [![vue-class-component-status]][vue-class-component-package] | TypeScript decorator for a class-based API |
| [vue-rx] | [![vue-rx-status]][vue-rx-package] | RxJS integration |
| [vue-devtools] | [![vue-devtools-status]][vue-devtools-package] | Browser DevTools extension |
| Project | Status | Description |
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------- |
| [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing |
| [vuex] | [![vuex-status]][vuex-package] | Large-scale state management |
| [vue-cli] | [![vue-cli-status]][vue-cli-package] | Project scaffolding |
| [vue-loader] | [![vue-loader-status]][vue-loader-package] | Single File Component (`*.vue` file) loader for webpack |
| [vue-server-renderer] | [![vue-server-renderer-status]][vue-server-renderer-package] | Server-side rendering support |
| [vue-class-component] | [![vue-class-component-status]][vue-class-component-package] | TypeScript decorator for a class-based API |
| [vue-rx] | [![vue-rx-status]][vue-rx-package] | RxJS integration |
| [vue-devtools] | [![vue-devtools-status]][vue-devtools-package] | Browser DevTools extension |
[vue-router]: https://github.com/vuejs/vue-router
[vuex]: https://github.com/vuejs/vuex
@ -311,8 +53,7 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
[vue-server-renderer]: https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer
[vue-class-component]: https://github.com/vuejs/vue-class-component
[vue-rx]: https://github.com/vuejs/vue-rx
[vue-devtools]: https://github.com/vuejs/vue-devtools
[vue-devtools]: https://github.com/vuejs/vue-devtools
[vue-router-status]: https://img.shields.io/npm/v/vue-router.svg
[vuex-status]: https://img.shields.io/npm/v/vuex.svg
[vue-cli-status]: https://img.shields.io/npm/v/@vue/cli.svg
@ -321,7 +62,6 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
[vue-class-component-status]: https://img.shields.io/npm/v/vue-class-component.svg
[vue-rx-status]: https://img.shields.io/npm/v/vue-rx.svg
[vue-devtools-status]: https://img.shields.io/chrome-web-store/v/nhdogjmejiglipccpnnnanhbledajbpd.svg
[vue-router-package]: https://npmjs.com/package/vue-router
[vuex-package]: https://npmjs.com/package/vuex
[vue-cli-package]: https://npmjs.com/package/@vue/cli
@ -361,7 +101,6 @@ Thank you to all the people who already contributed to Vue!
<a href="https://github.com/vuejs/vue/graphs/contributors"><img src="https://opencollective.com/vuejs/contributors.svg?width=890" /></a>
## License
[MIT](https://opensource.org/licenses/MIT)

View File

@ -1,6 +1,6 @@
{
"name": "vue",
"version": "2.6.12",
"version": "2.6.14",
"description": "Reactive, component-oriented view layer for modern web interfaces.",
"main": "dist/vue.runtime.common.js",
"module": "dist/vue.runtime.esm.js",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,85 +1,124 @@
'use strict';
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };
var isCSS = function (file) { return /\.css(\?[^.]+)?$/.test(file); };
var ref = require('chalk');
var red = ref.red;
var yellow = ref.yellow;
var webpack = require('webpack');
var prefix = "[vue-server-renderer-webpack-plugin]";
(exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); });
(exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); });
var onEmit = function (compiler, name, hook) {
if (compiler.hooks) {
// Webpack >= 4.0.0
compiler.hooks.emit.tapAsync(name, hook);
}
else {
// Webpack < 4.0.0
compiler.plugin('emit', hook);
}
var warn = exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); };
var tip = exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); };
var isWebpack5 = !!(webpack.version && webpack.version[0] > 4);
var onEmit = function (compiler, name, stageName, hook) {
if (isWebpack5) {
// Webpack >= 5.0.0
compiler.hooks.compilation.tap(name, function (compilation) {
if (compilation.compiler !== compiler) {
// Ignore child compilers
return
}
var stage = webpack.Compilation[stageName];
compilation.hooks.processAssets.tapAsync({ name: name, stage: stage }, function (assets, cb) {
hook(compilation, cb);
});
});
} else if (compiler.hooks) {
// Webpack >= 4.0.0
compiler.hooks.emit.tapAsync(name, hook);
} else {
// Webpack < 4.0.0
compiler.plugin('emit', hook);
}
};
var stripModuleIdHash = function (id) {
if (isWebpack5) {
// Webpack >= 5.0.0
return id.replace(/\|\w+$/, '')
}
// Webpack < 5.0.0
return id.replace(/\s\w+$/, '')
};
var getAssetName = function (asset) {
if (typeof asset === 'string') {
return asset
}
return asset.name
};
var hash = require('hash-sum');
var uniq = require('lodash.uniq');
var VueSSRClientPlugin = function VueSSRClientPlugin(options) {
if ( options === void 0 ) options = {};
//@ts-expect-error
this.options = Object.assign({
filename: 'vue-ssr-client-manifest.json',
}, options);
var VueSSRClientPlugin = function VueSSRClientPlugin (options) {
if ( options === void 0 ) options = {};
this.options = Object.assign({
filename: 'vue-ssr-client-manifest.json'
}, options);
};
VueSSRClientPlugin.prototype.apply = function apply (compiler) {
var this$1 = this;
var this$1 = this;
onEmit(compiler, 'vue-client-plugin', function (compilation, cb) {
var stats = compilation.getStats().toJson();
var allFiles = uniq(stats.assets.map(function (a) { return a.name; }));
var initialFiles = uniq(Object.keys(stats.entrypoints)
.map(function (name) { return stats.entrypoints[name].assets; })
.reduce(function (assets, all) { return all.concat(assets); }, [])
.filter(function (file) { return isJS(file) || isCSS(file); }));
var asyncFiles = allFiles
.filter(function (file) { return isJS(file) || isCSS(file); })
.filter(function (file) { return initialFiles.indexOf(file) < 0; });
var manifest = {
publicPath: stats.publicPath,
all: allFiles,
initial: initialFiles,
async: asyncFiles,
modules: {
/* [identifier: string]: Array<index: number> */
},
};
var assetModules = stats.modules.filter(function (m) { return m.assets.length; });
var fileToIndex = function (file) { return manifest.all.indexOf(file); };
stats.modules.forEach(function (m) {
// ignore modules duplicated in multiple chunks
if (m.chunks.length === 1) {
var cid = m.chunks[0];
var chunk = stats.chunks.find(function (c) { return c.id === cid; });
if (!chunk || !chunk.files) {
return;
}
var id = m.identifier.replace(/\s\w+$/, ''); // remove appended hash
var files = (manifest.modules[hash(id)] = chunk.files.map(fileToIndex));
// find all asset modules associated with the same chunk
assetModules.forEach(function (m) {
if (m.chunks.some(function (id) { return id === cid; })) {
files.push.apply(files, m.assets.map(fileToIndex));
}
});
}
var stage = 'PROCESS_ASSETS_STAGE_ADDITIONAL';
onEmit(compiler, 'vue-client-plugin', stage, function (compilation, cb) {
var stats = compilation.getStats().toJson();
var allFiles = uniq(stats.assets
.map(function (a) { return a.name; }));
var initialFiles = uniq(Object.keys(stats.entrypoints)
.map(function (name) { return stats.entrypoints[name].assets; })
.reduce(function (assets, all) { return all.concat(assets); }, [])
.map(getAssetName)
.filter(function (file) { return isJS(file) || isCSS(file); }));
var asyncFiles = allFiles
.filter(function (file) { return isJS(file) || isCSS(file); })
.filter(function (file) { return initialFiles.indexOf(file) < 0; });
var manifest = {
publicPath: stats.publicPath,
all: allFiles,
initial: initialFiles,
async: asyncFiles,
modules: { /* [identifier: string]: Array<index: number> */ }
};
var assetModules = stats.modules.filter(function (m) { return m.assets.length; });
var fileToIndex = function (asset) { return manifest.all.indexOf(getAssetName(asset)); };
stats.modules.forEach(function (m) {
// ignore modules duplicated in multiple chunks
if (m.chunks.length === 1) {
var cid = m.chunks[0];
var chunk = stats.chunks.find(function (c) { return c.id === cid; });
if (!chunk || !chunk.files) {
return
}
var id = stripModuleIdHash(m.identifier);
var files = manifest.modules[hash(id)] = chunk.files.map(fileToIndex);
// find all asset modules associated with the same chunk
assetModules.forEach(function (m) {
if (m.chunks.some(function (id) { return id === cid; })) {
files.push.apply(files, m.assets.map(fileToIndex));
}
});
var json = JSON.stringify(manifest, null, 2);
//@ts-expect-error
compilation.assets[this$1.options.filename] = {
source: function () { return json; },
size: function () { return json.length; },
};
cb();
}
});
var json = JSON.stringify(manifest, null, 2);
compilation.assets[this$1.options.filename] = {
source: function () { return json; },
size: function () { return json.length; }
};
cb();
});
};
module.exports = VueSSRClientPlugin;
module.exports = VueSSRClientPlugin;

View File

@ -1,6 +1,6 @@
{
"name": "vue-server-renderer",
"version": "2.6.12",
"version": "2.6.14",
"description": "server renderer for Vue 2.0",
"main": "index.js",
"types": "types/index.d.ts",

View File

@ -1,90 +1,142 @@
'use strict';
/* */
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };
var ref = require('chalk');
var red = ref.red;
var yellow = ref.yellow;
var webpack = require('webpack');
var prefix = "[vue-server-renderer-webpack-plugin]";
var warn = (exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); });
var tip = (exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); });
var warn = exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); };
var tip = exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); };
var isWebpack5 = !!(webpack.version && webpack.version[0] > 4);
var validate = function (compiler) {
if (compiler.options.target !== 'node') {
warn('webpack config `target` should be "node".');
}
if (compiler.options.output &&
compiler.options.output.libraryTarget !== 'commonjs2') {
warn('webpack config `output.libraryTarget` should be "commonjs2".');
}
if (!compiler.options.externals) {
tip('It is recommended to externalize dependencies in the server build for ' +
'better build performance.');
}
};
var onEmit = function (compiler, name, hook) {
if (compiler.hooks) {
// Webpack >= 4.0.0
compiler.hooks.emit.tapAsync(name, hook);
}
else {
// Webpack < 4.0.0
compiler.plugin('emit', hook);
if (compiler.options.target !== 'node') {
warn('webpack config `target` should be "node".');
}
if (compiler.options.output) {
if (compiler.options.output.library) {
// Webpack >= 5.0.0
if (compiler.options.output.library.type !== 'commonjs2') {
warn('webpack config `output.library.type` should be "commonjs2".');
}
} else if (compiler.options.output.libraryTarget !== 'commonjs2') {
// Webpack < 5.0.0
warn('webpack config `output.libraryTarget` should be "commonjs2".');
}
}
if (!compiler.options.externals) {
tip(
'It is recommended to externalize dependencies in the server build for ' +
'better build performance.'
);
}
};
var VueSSRServerPlugin = function VueSSRServerPlugin(options) {
if ( options === void 0 ) options = {};
//@ts-expect-error
this.options = Object.assign({
filename: 'vue-ssr-server-bundle.json',
}, options);
};
VueSSRServerPlugin.prototype.apply = function apply (compiler) {
var this$1 = this;
validate(compiler);
onEmit(compiler, 'vue-server-plugin', function (compilation, cb) {
var stats = compilation.getStats().toJson();
var entryName = Object.keys(stats.entrypoints)[0];
var entryInfo = stats.entrypoints[entryName];
if (!entryInfo) {
// #5553
return cb();
}
var entryAssets = entryInfo.assets.filter(isJS);
if (entryAssets.length > 1) {
throw new Error("Server-side bundle should have one single entry file. " +
"Avoid using CommonsChunkPlugin in the server config.");
}
var entry = entryAssets[0];
if (!entry || typeof entry !== 'string') {
throw new Error(("Entry \"" + entryName + "\" not found. Did you specify the correct entry option?"));
}
var bundle = {
entry: entry,
files: {},
maps: {},
};
stats.assets.forEach(function (asset) {
if (isJS(asset.name)) {
bundle.files[asset.name] = compilation.assets[asset.name].source();
}
else if (asset.name.match(/\.js\.map$/)) {
bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[asset.name].source());
}
// do not emit anything else for server
delete compilation.assets[asset.name];
});
var json = JSON.stringify(bundle, null, 2);
//@ts-expect-error
var filename = this$1.options.filename;
compilation.assets[filename] = {
source: function () { return json; },
size: function () { return json.length; },
};
cb();
var onEmit = function (compiler, name, stageName, hook) {
if (isWebpack5) {
// Webpack >= 5.0.0
compiler.hooks.compilation.tap(name, function (compilation) {
if (compilation.compiler !== compiler) {
// Ignore child compilers
return
}
var stage = webpack.Compilation[stageName];
compilation.hooks.processAssets.tapAsync({ name: name, stage: stage }, function (assets, cb) {
hook(compilation, cb);
});
});
} else if (compiler.hooks) {
// Webpack >= 4.0.0
compiler.hooks.emit.tapAsync(name, hook);
} else {
// Webpack < 4.0.0
compiler.plugin('emit', hook);
}
};
var getAssetName = function (asset) {
if (typeof asset === 'string') {
return asset
}
return asset.name
};
var VueSSRServerPlugin = function VueSSRServerPlugin (options) {
if ( options === void 0 ) options = {};
this.options = Object.assign({
filename: 'vue-ssr-server-bundle.json'
}, options);
};
VueSSRServerPlugin.prototype.apply = function apply (compiler) {
var this$1 = this;
validate(compiler);
var stage = 'PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER';
onEmit(compiler, 'vue-server-plugin', stage, function (compilation, cb) {
var stats = compilation.getStats().toJson();
var entryName = Object.keys(stats.entrypoints)[0];
var entryInfo = stats.entrypoints[entryName];
if (!entryInfo) {
// #5553
return cb()
}
var entryAssets = entryInfo.assets
.map(getAssetName)
.filter(isJS);
if (entryAssets.length > 1) {
throw new Error(
"Server-side bundle should have one single entry file. " +
"Avoid using CommonsChunkPlugin in the server config."
)
}
var entry = entryAssets[0];
if (!entry || typeof entry !== 'string') {
throw new Error(
("Entry \"" + entryName + "\" not found. Did you specify the correct entry option?")
)
}
var bundle = {
entry: entry,
files: {},
maps: {}
};
Object.keys(compilation.assets).forEach(function (name) {
if (isJS(name)) {
bundle.files[name] = compilation.assets[name].source();
} else if (name.match(/\.js\.map$/)) {
bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source());
}
// do not emit anything else for server
delete compilation.assets[name];
});
var json = JSON.stringify(bundle, null, 2);
var filename = this$1.options.filename;
compilation.assets[filename] = {
source: function () { return json; },
size: function () { return json.length; }
};
cb();
});
};
module.exports = VueSSRServerPlugin;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "vue-template-compiler",
"version": "2.6.12",
"version": "2.6.14",
"description": "template compiler for Vue 2.0",
"main": "index.js",
"unpkg": "browser.js",

File diff suppressed because it is too large Load Diff

View File

@ -2,133 +2,156 @@
Object.defineProperty(exports, '__esModule', { value: true });
/* */
// this will be preserved during build
// $flow-disable-line
var VueFactory = require('./factory');
var instanceOptions = {};
/**
* Create instance context.
*/
function createInstanceContext(instanceId, runtimeContext, data) {
if (data === void 0) { data = {}; }
var weex = runtimeContext.weex;
var instance = (instanceOptions[instanceId] = {
instanceId: instanceId,
config: weex.config,
document: weex.document,
data: data,
});
// Each instance has a independent `Vue` module instance
var Vue = (instance.Vue = createVueModuleInstance(instanceId, weex));
// DEPRECATED
var timerAPIs = getInstanceTimer(instanceId, weex.requireModule);
var instanceContext = Object.assign({ Vue: Vue }, timerAPIs);
Object.freeze(instanceContext);
return instanceContext;
function createInstanceContext (
instanceId,
runtimeContext,
data
) {
if ( data === void 0 ) data = {};
var weex = runtimeContext.weex;
var instance = instanceOptions[instanceId] = {
instanceId: instanceId,
config: weex.config,
document: weex.document,
data: data
};
// Each instance has an independent `Vue` module instance
var Vue = instance.Vue = createVueModuleInstance(instanceId, weex);
// DEPRECATED
var timerAPIs = getInstanceTimer(instanceId, weex.requireModule);
var instanceContext = Object.assign({ Vue: Vue }, timerAPIs);
Object.freeze(instanceContext);
return instanceContext
}
/**
* Destroy an instance with id. It will make sure all memory of
* this instance released and no more leaks.
*/
function destroyInstance(instanceId) {
var instance = instanceOptions[instanceId];
//@ts-expect-error
if (instance && instance.app instanceof instance.Vue) {
try {
instance.app.$destroy();
instance.document.destroy();
}
catch (e) { }
//@ts-expect-error
delete instance.document;
delete instance.app;
}
delete instanceOptions[instanceId];
function destroyInstance (instanceId) {
var instance = instanceOptions[instanceId];
if (instance && instance.app instanceof instance.Vue) {
try {
instance.app.$destroy();
instance.document.destroy();
} catch (e) {}
delete instance.document;
delete instance.app;
}
delete instanceOptions[instanceId];
}
/**
* Refresh an instance with id and new top-level component data.
* It will use `Vue.set` on all keys of the new data. So it's better
* define all possible meaningful keys when instance created.
*/
function refreshInstance(instanceId, data) {
var instance = instanceOptions[instanceId];
//@ts-expect-error
if (!instance || !(instance.app instanceof instance.Vue)) {
return new Error("refreshInstance: instance " + instanceId + " not found!");
function refreshInstance (
instanceId,
data
) {
var instance = instanceOptions[instanceId];
if (!instance || !(instance.app instanceof instance.Vue)) {
return new Error(("refreshInstance: instance " + instanceId + " not found!"))
}
if (instance.Vue && instance.Vue.set) {
for (var key in data) {
instance.Vue.set(instance.app, key, data[key]);
}
if (instance.Vue && instance.Vue.set) {
for (var key in data) {
instance.Vue.set(instance.app, key, data[key]);
}
}
// Finally `refreshFinish` signal needed.
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, []);
}
// Finally `refreshFinish` signal needed.
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, []);
}
/**
* Create a fresh instance of Vue for each Weex instance.
*/
function createVueModuleInstance(instanceId, weex) {
var exports = {};
VueFactory(exports, weex.document);
//@ts-expect-error
var Vue = exports.Vue;
var instance = instanceOptions[instanceId];
// patch reserved tag detection to account for dynamically registered
// components
var weexRegex = /^weex:/i;
var isReservedTag = Vue.config.isReservedTag || (function () { return false; });
var isRuntimeComponent = Vue.config.isRuntimeComponent || (function () { return false; });
Vue.config.isReservedTag = function (name) {
return ((!isRuntimeComponent(name) && weex.supports("@component/" + name)) ||
isReservedTag(name) ||
weexRegex.test(name));
};
Vue.config.parsePlatformTagName = function (name) { return name.replace(weexRegex, ''); };
// expose weex-specific info
Vue.prototype.$instanceId = instanceId;
Vue.prototype.$document = instance.document;
// expose weex native module getter on subVue prototype so that
// vdom runtime modules can access native modules via vnode.context
Vue.prototype.$requireWeexModule = weex.requireModule;
// Hack `Vue` behavior to handle instance information and data
// before root component created.
Vue.mixin({
beforeCreate: function () {
var options = this.$options;
// root component (vm)
if (options.el) {
// set external data of instance
var dataOption = options.data;
var internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {};
options.data = Object.assign(internalData, instance.data);
// record instance by id
instance.app = this;
}
},
mounted: function () {
var options = this.$options;
// root component (vm)
if (options.el && weex.document && instance.app === this) {
try {
// Send "createFinish" signal to native.
weex.document.taskCenter.send('dom', { action: 'createFinish' }, []);
}
catch (e) { }
}
},
});
/**
* @deprecated Just instance variable `weex.config`
* Get instance config.
* @return {object}
*/
Vue.prototype.$getConfig = function () {
if (instance.app instanceof Vue) {
return instance.config;
}
};
return Vue;
function createVueModuleInstance (
instanceId,
weex
) {
var exports = {};
VueFactory(exports, weex.document);
var Vue = exports.Vue;
var instance = instanceOptions[instanceId];
// patch reserved tag detection to account for dynamically registered
// components
var weexRegex = /^weex:/i;
var isReservedTag = Vue.config.isReservedTag || (function () { return false; });
var isRuntimeComponent = Vue.config.isRuntimeComponent || (function () { return false; });
Vue.config.isReservedTag = function (name) {
return (!isRuntimeComponent(name) && weex.supports(("@component/" + name))) ||
isReservedTag(name) ||
weexRegex.test(name)
};
Vue.config.parsePlatformTagName = function (name) { return name.replace(weexRegex, ''); };
// expose weex-specific info
Vue.prototype.$instanceId = instanceId;
Vue.prototype.$document = instance.document;
// expose weex native module getter on subVue prototype so that
// vdom runtime modules can access native modules via vnode.context
Vue.prototype.$requireWeexModule = weex.requireModule;
// Hack `Vue` behavior to handle instance information and data
// before root component created.
Vue.mixin({
beforeCreate: function beforeCreate () {
var options = this.$options;
// root component (vm)
if (options.el) {
// set external data of instance
var dataOption = options.data;
var internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {};
options.data = Object.assign(internalData, instance.data);
// record instance by id
instance.app = this;
}
},
mounted: function mounted () {
var options = this.$options;
// root component (vm)
if (options.el && weex.document && instance.app === this) {
try {
// Send "createFinish" signal to native.
weex.document.taskCenter.send('dom', { action: 'createFinish' }, []);
} catch (e) {}
}
}
});
/**
* @deprecated Just instance variable `weex.config`
* Get instance config.
* @return {object}
*/
Vue.prototype.$getConfig = function () {
if (instance.app instanceof Vue) {
return instance.config
}
};
return Vue
}
/**
* DEPRECATED
* Generate HTML5 Timer APIs. An important point is that the callback
@ -136,46 +159,43 @@ function createVueModuleInstance(instanceId, weex) {
* framework can make sure no side effect of the callback happened after
* an instance destroyed.
*/
function getInstanceTimer(instanceId, moduleGetter) {
var instance = instanceOptions[instanceId];
var timer = moduleGetter('timer');
var timerAPIs = {
setTimeout: function () {
var arguments$1 = arguments;
function getInstanceTimer (
instanceId,
moduleGetter
) {
var instance = instanceOptions[instanceId];
var timer = moduleGetter('timer');
var timerAPIs = {
setTimeout: function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments$1[_i];
}
var handler = function () {
args[0].apply(args, args.slice(2));
};
timer.setTimeout(handler, args[1]);
//@ts-expect-error
return instance.document.taskCenter.callbackManager.lastCallbackId.toString();
},
setInterval: function () {
var arguments$1 = arguments;
var handler = function () {
args[0].apply(args, args.slice(2));
};
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments$1[_i];
}
var handler = function () {
args[0].apply(args, args.slice(2));
};
timer.setInterval(handler, args[1]);
//@ts-expect-error
return instance.document.taskCenter.callbackManager.lastCallbackId.toString();
},
clearTimeout: function (n) {
timer.clearTimeout(n);
},
clearInterval: function (n) {
timer.clearInterval(n);
},
};
return timerAPIs;
timer.setTimeout(handler, args[1]);
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
setInterval: function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
var handler = function () {
args[0].apply(args, args.slice(2));
};
timer.setInterval(handler, args[1]);
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
clearTimeout: function (n) {
timer.clearTimeout(n);
},
clearInterval: function (n) {
timer.clearInterval(n);
}
};
return timerAPIs
}
exports.createInstanceContext = createInstanceContext;

View File

@ -560,18 +560,15 @@ export function genComment(comment: ASTText): string {
function genSlot(el: ASTElement, state: CodegenState): string {
const slotName = el.slotName || '"default"'
const children = genChildren(el, state)
let res = `_t(${slotName}${children ? `,${children}` : ''}`
const attrs =
el.attrs || el.dynamicAttrs
? genProps(
(el.attrs || []).concat(el.dynamicAttrs || []).map((attr) => ({
// slot props are camelized
name: camelize(attr.name),
value: attr.value,
dynamic: attr.dynamic,
}))
)
: null
let res = `_t(${slotName}${children ? `,function(){return ${children}}` : ''}`
const attrs = el.attrs || el.dynamicAttrs
? genProps((el.attrs || []).concat(el.dynamicAttrs || []).map(attr => ({
// slot props are camelized
name: camelize(attr.name),
value: attr.value,
dynamic: attr.dynamic
})))
: null
const bind = el.attrsMap['v-bind']
if ((attrs || bind) && !children) {
res += `,null`

View File

@ -1,12 +1,21 @@
import { isRegExp, remove } from 'shared/util'
import { getFirstComponentChild } from 'core/vdom/helpers/index'
import VNode from 'core/vdom/vnode'
import type { VNodeComponentOptions } from 'typescript/vnode'
/* @flow */
type VNodeCache = { [key: string]: VNode | null }
import { isRegExp, remove } from "shared/util";
import { getFirstComponentChild } from "core/vdom/helpers/index";
import type VNode from "core/vdom/vnode";
import type { VNodeComponentOptions } from "typescript/vnode";
import type { Component } from "typescript/component";
type CacheEntry = {
name?: string;
tag?: string;
componentInstance?: Component;
};
type CacheEntryMap = Record<string, CacheEntry | null>;
function getComponentName(opts?: VNodeComponentOptions): string | null {
return opts && (opts.Ctor.options.name || opts.tag)
return opts && (opts.Ctor.options.name || opts.tag);
}
function matches(
@ -14,49 +23,52 @@ function matches(
name: string
): boolean {
if (Array.isArray(pattern)) {
return pattern.indexOf(name) > -1
} else if (typeof pattern === 'string') {
return pattern.split(',').indexOf(name) > -1
return pattern.indexOf(name) > -1;
} else if (typeof pattern === "string") {
return pattern.split(",").indexOf(name) > -1;
} else if (isRegExp(pattern)) {
return pattern.test(name)
return pattern.test(name);
}
/* istanbul ignore next */
return false
return false;
}
function pruneCache(keepAliveInstance: any, filter: Function) {
const { cache, keys, _vnode } = keepAliveInstance
function pruneCache(
keepAliveInstance: { cache: CacheEntryMap; keys: string[]; _vnode: VNode },
filter: Function
) {
const { cache, keys, _vnode } = keepAliveInstance;
for (const key in cache) {
const cachedNode: VNode | null = cache[key]
if (cachedNode) {
const name = getComponentName(cachedNode.componentOptions)
const entry = cache[key];
if (entry) {
const name = entry.name;
if (name && !filter(name)) {
pruneCacheEntry(cache, key, keys, _vnode)
pruneCacheEntry(cache, key, keys, _vnode);
}
}
}
}
function pruneCacheEntry(
cache: VNodeCache,
cache: CacheEntryMap,
key: string,
keys: Array<string>,
current?: VNode
) {
const cached = cache[key]
if (cached && (!current || cached.tag !== current.tag)) {
//@ts-expect-error has void type
cached.componentInstance.$destroy()
const entry = cache[key];
if (entry && (!current || entry.tag !== current.tag)) {
// @ts-expect-error can be undefined
entry.componentInstance.$destroy();
}
cache[key] = null
remove(keys, key)
cache[key] = null;
remove(keys, key);
}
const patternTypes: Array<Function> = [String, RegExp, Array]
const patternTypes: Array<Function> = [String, RegExp, Array];
// TODO use defineComponent
// TODO defineComponent
export default {
name: 'keep-alive',
name: "keep-alive",
abstract: true,
props: {
@ -65,68 +77,90 @@ export default {
max: [String, Number],
},
methods: {
cacheVNode() {
const { cache, keys, vnodeToCache, keyToCache } = this;
if (vnodeToCache) {
const { tag, componentInstance, componentOptions } = vnodeToCache;
cache[keyToCache] = {
name: getComponentName(componentOptions),
tag,
componentInstance,
};
keys.push(keyToCache);
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode);
}
this.vnodeToCache = null;
}
},
},
created() {
this.cache = Object.create(null)
this.keys = []
this.cache = Object.create(null);
this.keys = [];
},
destroyed() {
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
pruneCacheEntry(this.cache, key, this.keys);
}
},
mounted() {
this.$watch('include', (val) => {
pruneCache(this, (name) => matches(val, name))
})
this.$watch('exclude', (val) => {
pruneCache(this, (name) => !matches(val, name))
})
this.cacheVNode();
this.$watch("include", (val) => {
pruneCache(this, (name) => matches(val, name));
});
this.$watch("exclude", (val) => {
pruneCache(this, (name) => !matches(val, name));
});
},
updated() {
this.cacheVNode();
},
render() {
const slot = this.$slots.default
const vnode = getFirstComponentChild(slot)
const componentOptions =
vnode && vnode.componentOptions
const slot = this.$slots.default;
const vnode = getFirstComponentChild(slot);
const componentOptions = vnode && vnode.componentOptions;
if (componentOptions) {
// check pattern
const name = getComponentName(componentOptions)
const { include, exclude } = this
const name = getComponentName(componentOptions);
const { include, exclude } = this;
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
return vnode;
}
const { cache, keys } = this
const { cache, keys } = this;
const key =
vnode!.key == null
vnode.key == null
? // same constructor may get registered as different local components
// so cid alone is not enough (#3269)
componentOptions.Ctor.cid +
(componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode!.key
(componentOptions.tag ? `::${componentOptions.tag}` : "")
: vnode.key;
if (cache[key]) {
vnode!.componentInstance = cache[key].componentInstance
vnode.componentInstance = cache[key].componentInstance;
// make current key freshest
remove(keys, key)
keys.push(key)
remove(keys, key);
keys.push(key);
} else {
cache[key] = vnode
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
// delay setting the cache until update
this.vnodeToCache = vnode;
this.keyToCache = key;
}
vnode!.data!.keepAlive = true
// @ts-expect-error can vnode.data can be undefined
vnode.data.keepAlive = true;
}
return vnode || (slot && slot[0])
return vnode || (slot && slot[0]);
},
}
};

View File

@ -6,6 +6,8 @@ import { updateComponentListeners } from "./events";
import { resolveSlots } from "./render-helpers/resolve-slots";
import { toggleObserving } from "../observer/index";
import { pushTarget, popTarget } from "../observer/dep";
import type { Component } from "../../../typescript/component";
import type { MountedComponentVNode } from "../../../typescript/vnode";
import {
warn,
@ -15,8 +17,6 @@ import {
validateProp,
invokeWithErrorHandling,
} from "../util/index";
import type { Component } from "typescript/component";
import type { MountedComponentVNode } from "typescript/vnode";
export let activeInstance: any = null;
export let isUpdatingChildComponent: boolean = false;
@ -30,7 +30,7 @@ export function setActiveInstance(vm: Component) {
}
export function initLifecycle(vm: Component) {
const options: any = vm.$options;
const options = vm.$options;
// locate first non-abstract parent
let parent = options.parent;
@ -122,7 +122,7 @@ export function lifecycleMixin(Vue: Component) {
// call the last hook...
vm._isDestroyed = true;
// invoke destroy hooks on current rendered tree
vm.__patch__(vm._vnode!, null);
vm.__patch__(vm._vnode, null);
// fire destroyed hook
callHook(vm, "destroyed");
// turn off all instance listeners.
@ -133,7 +133,6 @@ export function lifecycleMixin(Vue: Component) {
}
// release circular reference (#6759)
if (vm.$vnode) {
// @ts-expect-error null is not undefined
vm.$vnode.parent = null;
}
};
@ -240,12 +239,13 @@ export function updateChildComponent(
// check if there are dynamic scopedSlots (hand-written or compiled but with
// dynamic slot names). Static scoped slots compiled from template has the
// "$stable" marker.
const newScopedSlots = parentVnode!.data.scopedSlots;
const newScopedSlots = parentVnode.data.scopedSlots;
const oldScopedSlots = vm.$scopedSlots;
const hasDynamicScopedSlot = !!(
(newScopedSlots && !newScopedSlots.$stable) ||
(oldScopedSlots !== emptyObject && !oldScopedSlots.$stable) ||
(newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key)
(newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key) ||
(!newScopedSlots && vm.$scopedSlots.$key)
);
// Any static slot children from the parent may have changed during parent's
@ -258,7 +258,6 @@ export function updateChildComponent(
);
vm.$options._parentVnode = parentVnode;
vm.$vnode = parentVnode; // update vm's placeholder node without re-render
if (vm._vnode) {
@ -270,7 +269,7 @@ export function updateChildComponent(
// update $attrs and $listeners hash
// these are also reactive so they may trigger child update if the child
// used them during render
vm.$attrs = parentVnode!.data.attrs || emptyObject;
vm.$attrs = parentVnode.data.attrs || emptyObject;
vm.$listeners = listeners || emptyObject;
// update props
@ -296,7 +295,7 @@ export function updateChildComponent(
// resolve slots + force update if has children
if (needsForceUpdate) {
vm.$slots = resolveSlots(renderChildren, parentVnode!.context);
vm.$slots = resolveSlots(renderChildren, parentVnode.context);
vm.$forceUpdate();
}

View File

@ -30,4 +30,5 @@ export function checkKeyCodes(
} else if (eventKeyName) {
return hyphenate(eventKeyName) !== key
}
return eventKeyCode === undefined
}

View File

@ -1,35 +1,43 @@
import { extend, warn, isObject } from 'core/util/index'
import VNode from 'core/vdom/vnode'
import { extend, warn, isObject } from "core/util/index";
import VNode from "core/vdom/vnode";
/**
* Runtime helper for rendering <slot>
*/
export function renderSlot(
name: string,
fallback: Array<VNode> | null,
fallbackRender: ((() => Array<VNode>) | Array<VNode>) | null,
props: Record<string, any> | null,
bindObject: object | null
): Array<VNode> | null {
const scopedSlotFn = this.$scopedSlots[name]
let nodes
const scopedSlotFn = this.$scopedSlots[name];
let nodes;
if (scopedSlotFn) {
// scoped slot
props = props || {}
props = props || {};
if (bindObject) {
if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) {
warn('slot v-bind without argument expects an Object', this)
if (process.env.NODE_ENV !== "production" && !isObject(bindObject)) {
warn("slot v-bind without argument expects an Object", this);
}
props = extend(extend({}, bindObject), props)
props = extend(extend({}, bindObject), props);
}
nodes = scopedSlotFn(props) || fallback
nodes =
scopedSlotFn(props) ||
(typeof fallbackRender === "function"
? fallbackRender()
: fallbackRender);
} else {
nodes = this.$slots[name] || fallback
nodes =
this.$slots[name] ||
(typeof fallbackRender === "function"
? fallbackRender()
: fallbackRender);
}
const target = props && props.slot
const target = props && props.slot;
if (target) {
return this.$createElement('template', { slot: target }, nodes)
return this.$createElement("template", { slot: target }, nodes);
} else {
return nodes
return nodes;
}
}

View File

@ -1,8 +1,7 @@
import config from '../config'
import Watcher from '../observer/watcher'
import Dep, { pushTarget, popTarget } from '../observer/dep'
import { isUpdatingChildComponent } from './lifecycle'
import config from "../config";
import Watcher from "../observer/watcher";
import Dep, { pushTarget, popTarget } from "../observer/dep";
import { isUpdatingChildComponent } from "./lifecycle";
import {
set,
@ -10,7 +9,7 @@ import {
observe,
defineReactive,
toggleObserving,
} from '../observer/index'
} from "../observer/index";
import {
warn,
@ -25,59 +24,60 @@ import {
isPlainObject,
isServerRendering,
isReservedAttribute,
} from '../util/index'
import type { Component } from 'typescript/component'
invokeWithErrorHandling,
} from "../util/index";
import type { Component } from "../../../typescript/component";
const sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop,
}
};
export function proxy(target: Object, sourceKey: string, key: string) {
sharedPropertyDefinition.get = function proxyGetter() {
return this[sourceKey][key]
}
return this[sourceKey][key];
};
sharedPropertyDefinition.set = function proxySetter(val) {
this[sourceKey][key] = val
}
Object.defineProperty(target, key, sharedPropertyDefinition)
this[sourceKey][key] = val;
};
Object.defineProperty(target, key, sharedPropertyDefinition);
}
export function initState(vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
vm._watchers = [];
const opts = vm.$options;
if (opts.props) initProps(vm, opts.props);
if (opts.methods) initMethods(vm, opts.methods);
if (opts.data) {
initData(vm)
initData(vm);
} else {
observe((vm._data = {}), true /* asRootData */)
observe((vm._data = {}), true /* asRootData */);
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.computed) initComputed(vm, opts.computed);
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
initWatch(vm, opts.watch);
}
}
function initProps(vm: Component, propsOptions: Object) {
const propsData = vm.$options.propsData || {}
const props = (vm._props = {})
const propsData = vm.$options.propsData || {};
const props = (vm._props = {});
// cache prop keys so that future props updates can iterate using Array
// instead of dynamic object key enumeration.
const keys: string[] = (vm.$options._propKeys = [])
const isRoot = !vm.$parent
const keys: string[] = (vm.$options._propKeys = []);
const isRoot = !vm.$parent;
// root instance props should be converted
if (!isRoot) {
toggleObserving(false)
toggleObserving(false);
}
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
keys.push(key);
const value = validateProp(key, propsOptions, propsData, vm);
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
const hyphenatedKey = hyphenate(key)
if (process.env.NODE_ENV !== "production") {
const hyphenatedKey = hyphenate(key);
if (
isReservedAttribute(hyphenatedKey) ||
config.isReservedAttr(hyphenatedKey)
@ -85,7 +85,7 @@ function initProps(vm: Component, propsOptions: Object) {
warn(
`"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
vm
)
);
}
defineReactive(props, key, value, () => {
if (!isRoot && !isUpdatingChildComponent) {
@ -95,87 +95,90 @@ function initProps(vm: Component, propsOptions: Object) {
`Instead, use a data or computed property based on the prop's ` +
`value. Prop being mutated: "${key}"`,
vm
)
);
}
})
});
} else {
defineReactive(props, key, value)
defineReactive(props, key, value);
}
// static props are already proxied on the component's prototype
// during Vue.extend(). We only need to proxy props defined at
// instantiation here.
if (!(key in vm)) {
proxy(vm, `_props`, key)
proxy(vm, `_props`, key);
}
}
toggleObserving(true)
toggleObserving(true);
}
function initData(vm: Component) {
let data: any = vm.$options.data
data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
let data: any = vm.$options.data;
data = vm._data = typeof data === "function" ? getData(data, vm) : data || {};
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== 'production' &&
data = {};
process.env.NODE_ENV !== "production" &&
warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
"data functions should return an object:\n" +
"https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function",
vm
)
);
}
// proxy data on instance
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
let i = keys.length
const keys = Object.keys(data);
const props = vm.$options.props;
const methods = vm.$options.methods;
let i = keys.length;
while (i--) {
const key = keys[i]
if (process.env.NODE_ENV !== 'production') {
const key = keys[i];
if (process.env.NODE_ENV !== "production") {
if (methods && hasOwn(methods, key)) {
warn(`Method "${key}" has already been defined as a data property.`, vm)
warn(
`Method "${key}" has already been defined as a data property.`,
vm
);
}
}
if (props && hasOwn(props, key)) {
process.env.NODE_ENV !== 'production' &&
process.env.NODE_ENV !== "production" &&
warn(
`The data property "${key}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
)
);
} else if (!isReserved(key)) {
proxy(vm, `_data`, key)
proxy(vm, `_data`, key);
}
}
// observe data
observe(data, true /* asRootData */)
observe(data, true /* asRootData */);
}
export function getData(data: Function, vm: Component): any {
// #7573 disable dep collection when invoking data getters
pushTarget()
pushTarget();
try {
return data.call(vm, vm)
} catch (e) {
handleError(e, vm, `data()`)
return {}
return data.call(vm, vm);
} catch (e: any) {
handleError(e, vm, `data()`);
return {};
} finally {
popTarget()
popTarget();
}
}
const computedWatcherOptions = { lazy: true }
const computedWatcherOptions = { lazy: true };
function initComputed(vm: Component, computed: Object) {
// $flow-disable-line
const watchers = (vm._computedWatchers = Object.create(null))
const watchers = (vm._computedWatchers = Object.create(null));
// computed properties are just getters during SSR
const isSSR = isServerRendering()
const isSSR = isServerRendering();
for (const key in computed) {
const userDef = computed[key]
const getter = typeof userDef === 'function' ? userDef : userDef.get
if (process.env.NODE_ENV !== 'production' && getter == null) {
warn(`Getter is missing for computed property "${key}".`, vm)
const userDef = computed[key];
const getter = typeof userDef === "function" ? userDef : userDef.get;
if (process.env.NODE_ENV !== "production" && getter == null) {
warn(`Getter is missing for computed property "${key}".`, vm);
}
if (!isSSR) {
@ -185,19 +188,27 @@ function initComputed(vm: Component, computed: Object) {
getter || noop,
noop,
computedWatcherOptions
)
);
}
// component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
// at instantiation here.
if (!(key in vm)) {
defineComputed(vm, key, userDef)
} else if (process.env.NODE_ENV !== 'production') {
defineComputed(vm, key, userDef);
} else if (process.env.NODE_ENV !== "production") {
if (key in vm.$data) {
warn(`The computed property "${key}" is already defined in data.`, vm)
warn(`The computed property "${key}" is already defined in data.`, vm);
} else if (vm.$options.props && key in vm.$options.props) {
warn(`The computed property "${key}" is already defined as a prop.`, vm)
warn(
`The computed property "${key}" is already defined as a prop.`,
vm
);
} else if (vm.$options.methods && key in vm.$options.methods) {
warn(
`The computed property "${key}" is already defined as a method.`,
vm
);
}
}
}
@ -208,91 +219,92 @@ export function defineComputed(
key: string,
userDef: Record<string, any> | Function
) {
const shouldCache = !isServerRendering()
if (typeof userDef === 'function') {
const shouldCache = !isServerRendering();
if (typeof userDef === "function") {
sharedPropertyDefinition.get = shouldCache
? createComputedGetter(key)
: createGetterInvoker(userDef)
sharedPropertyDefinition.set = noop
: createGetterInvoker(userDef);
sharedPropertyDefinition.set = noop;
} else {
sharedPropertyDefinition.get = userDef.get
? shouldCache && userDef.cache !== false
? createComputedGetter(key)
: createGetterInvoker(userDef.get)
: noop
sharedPropertyDefinition.set = userDef.set || noop
: noop;
sharedPropertyDefinition.set = userDef.set || noop;
}
if (
process.env.NODE_ENV !== 'production' &&
process.env.NODE_ENV !== "production" &&
sharedPropertyDefinition.set === noop
) {
sharedPropertyDefinition.set = function () {
warn(
`Computed property "${key}" was assigned to but it has no setter.`,
this
)
}
);
};
}
Object.defineProperty(target, key, sharedPropertyDefinition)
Object.defineProperty(target, key, sharedPropertyDefinition);
}
function createComputedGetter(key) {
return function computedGetter() {
const watcher = this._computedWatchers && this._computedWatchers[key]
const watcher = this._computedWatchers && this._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {
watcher.evaluate()
watcher.evaluate();
}
if (Dep.target) {
watcher.depend()
watcher.depend();
}
return watcher.value
return watcher.value;
}
}
};
}
function createGetterInvoker(fn) {
return function computedGetter() {
return fn.call(this, this)
}
return fn.call(this, this);
};
}
function initMethods(vm: Component, methods: Object) {
const props = vm.$options.props
const props = vm.$options.props;
for (const key in methods) {
if (process.env.NODE_ENV !== 'production') {
if (typeof methods[key] !== 'function') {
if (process.env.NODE_ENV !== "production") {
if (typeof methods[key] !== "function") {
warn(
`Method "${key}" has type "${typeof methods[
key
]}" in the component definition. ` +
`Did you reference the function correctly?`,
vm
)
);
}
if (props && hasOwn(props, key)) {
warn(`Method "${key}" has already been defined as a prop.`, vm)
warn(`Method "${key}" has already been defined as a prop.`, vm);
}
if (key in vm && isReserved(key)) {
warn(
`Method "${key}" conflicts with an existing Vue instance method. ` +
`Avoid defining component methods that start with _ or $.`
)
);
}
}
vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
vm[key] =
typeof methods[key] !== "function" ? noop : bind(methods[key], vm);
}
}
function initWatch(vm: Component, watch: Object) {
for (const key in watch) {
const handler = watch[key]
const handler = watch[key];
if (Array.isArray(handler)) {
for (let i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i])
createWatcher(vm, key, handler[i]);
}
} else {
createWatcher(vm, key, handler)
createWatcher(vm, key, handler);
}
}
}
@ -304,72 +316,65 @@ function createWatcher(
options?: Object
) {
if (isPlainObject(handler)) {
options = handler
handler = handler.handler
options = handler;
handler = handler.handler;
}
if (typeof handler === 'string') {
handler = vm[handler]
if (typeof handler === "string") {
handler = vm[handler];
}
return vm.$watch(expOrFn, handler, options)
return vm.$watch(expOrFn, handler, options);
}
export function stateMixin(Vue: Component) {
// flow somehow has problems with directly declared definition object
// when using Object.defineProperty, so we have to procedurally build up
// the object here.
const dataDef:any = {}
const dataDef: any = {};
dataDef.get = function () {
return this._data
}
const propsDef: any = {}
return this._data;
};
const propsDef: any = {};
propsDef.get = function () {
return this._props
}
if (process.env.NODE_ENV !== 'production') {
return this._props;
};
if (process.env.NODE_ENV !== "production") {
dataDef.set = function () {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
"Avoid replacing instance root $data. " +
"Use nested data properties instead.",
this
)
}
);
};
propsDef.set = function () {
warn(`$props is readonly.`, this)
}
warn(`$props is readonly.`, this);
};
}
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
Object.defineProperty(Vue.prototype, "$data", dataDef);
Object.defineProperty(Vue.prototype, "$props", propsDef);
Vue.prototype.$set = set
Vue.prototype.$delete = del
Vue.prototype.$set = set;
Vue.prototype.$delete = del;
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Record<string,any>
options?: Record<string, any>
): Function {
const vm: Component = this
const vm: Component = this;
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
return createWatcher(vm, expOrFn, cb, options);
}
options = options || {}
options.user = true
const watcher = new Watcher(vm, expOrFn, cb, options)
options = options || {};
options.user = true;
const watcher = new Watcher(vm, expOrFn, cb, options);
if (options.immediate) {
pushTarget()
try {
cb.call(vm, watcher.value)
} catch (error) {
handleError(
error,
vm,
`callback for immediate watcher "${watcher.expression}"`
)
}
popTarget()
const info = `callback for immediate watcher "${watcher.expression}"`;
pushTarget();
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info);
popTarget();
}
return function unwatchFn() {
watcher.teardown()
}
}
watcher.teardown();
};
};
}

View File

@ -6,7 +6,8 @@ import {
parsePath,
_Set as Set,
handleError,
noop,
invokeWithErrorHandling,
noop
} from '../util/index'
import { traverse } from './traverse'
@ -78,8 +79,9 @@ export default class Watcher {
this.newDeps = []
this.depIds = new Set()
this.newDepIds = new Set()
this.expression =
process.env.NODE_ENV !== 'production' ? expOrFn.toString() : ''
this.expression = process.env.NODE_ENV !== 'production'
? expOrFn.toString()
: ''
// parse expression for getter
if (typeof expOrFn === 'function') {
this.getter = expOrFn
@ -87,16 +89,17 @@ export default class Watcher {
this.getter = parsePath(expOrFn)
if (!this.getter) {
this.getter = noop
process.env.NODE_ENV !== 'production' &&
warn(
`Failed watching path: "${expOrFn}" ` +
'Watcher only accepts simple dot-delimited paths. ' +
'For full control, use a function instead.',
vm
)
process.env.NODE_ENV !== 'production' && warn(
`Failed watching path: "${expOrFn}" ` +
'Watcher only accepts simple dot-delimited paths. ' +
'For full control, use a function instead.',
vm
)
}
}
this.value = this.lazy ? undefined : this.get()
this.value = this.lazy
? undefined
: this.get()
}
/**
@ -195,11 +198,8 @@ export default class Watcher {
const oldValue = this.value
this.value = value
if (this.user) {
try {
this.cb.call(this.vm, value, oldValue)
} catch (e) {
handleError(e, this.vm, `callback for watcher "${this.expression}"`)
}
const info = `callback for watcher "${this.expression}"`
invokeWithErrorHandling(this.cb, this.vm, [value, oldValue], this.vm, info)
} else {
this.cb.call(this.vm, value, oldValue)
}

View File

@ -1,23 +1,23 @@
import { def } from 'core/util/lang'
import { normalizeChildren } from 'core/vdom/helpers/normalize-children'
import { emptyObject } from 'shared/util'
import VNode from '../vnode'
import { def } from "core/util/lang";
import { normalizeChildren } from "core/vdom/helpers/normalize-children";
import { emptyObject } from "shared/util";
import { isAsyncPlaceholder } from "./is-async-placeholder";
import type VNode from "../vnode";
export function normalizeScopedSlots(
slots: { [key: string]: Function } | void,
normalSlots: { [key: string]: Array<VNode> },
prevSlots?: { [key: string]: Function } | void
): any {
let res
const hasNormalSlots = Object.keys(normalSlots).length > 0
const isStable = slots ? !!slots.$stable : !hasNormalSlots
const key = slots && slots.$key
let res;
const hasNormalSlots = Object.keys(normalSlots).length > 0;
const isStable = slots ? !!slots.$stable : !hasNormalSlots;
const key = slots && slots.$key;
if (!slots) {
res = {}
res = {};
} else if (slots._normalized) {
// fast path 1: child component re-render only, parent did not change
return slots._normalized
return slots._normalized;
} else if (
isStable &&
prevSlots &&
@ -28,43 +28,46 @@ export function normalizeScopedSlots(
) {
// fast path 2: stable scoped slots w/ no normal slots to proxy,
// only need to normalize once
return prevSlots
return prevSlots;
} else {
res = {}
res = {};
for (const key in slots) {
if (slots[key] && key[0] !== '$') {
res[key] = normalizeScopedSlot(normalSlots, key, slots[key])
if (slots[key] && key[0] !== "$") {
res[key] = normalizeScopedSlot(normalSlots, key, slots[key]);
}
}
}
// expose normal slots on scopedSlots
for (const key in normalSlots) {
if (!(key in res)) {
res[key] = proxyNormalSlot(normalSlots, key)
res[key] = proxyNormalSlot(normalSlots, key);
}
}
// avoriaz seems to mock a non-extensible $scopedSlots object
// and when that is passed down this would cause an error
if (slots && Object.isExtensible(slots)) {
slots._normalized = res
slots._normalized = res;
}
def(res, '$stable', isStable)
def(res, '$key', key)
def(res, '$hasNormal', hasNormalSlots)
return res
def(res, "$stable", isStable);
def(res, "$key", key);
def(res, "$hasNormal", hasNormalSlots);
return res;
}
function normalizeScopedSlot(normalSlots, key, fn) {
const normalized = function () {
let res = arguments.length ? fn.apply(null, arguments) : fn({})
let res = arguments.length ? fn.apply(null, arguments) : fn({});
res =
res && typeof res === 'object' && !Array.isArray(res)
res && typeof res === "object" && !Array.isArray(res)
? [res] // single vnode
: normalizeChildren(res)
return res && (res.length === 0 || (res.length === 1 && res[0].isComment)) // #9658
: normalizeChildren(res);
let vnode: VNode | null = res && res[0];
return res &&
(!vnode ||
(res.length === 1 && vnode.isComment && !isAsyncPlaceholder(vnode))) // #9658, #10391
? undefined
: res
}
: res;
};
// this is a slot using the new v-slot syntax without scope. although it is
// compiled as a scoped slot, render fn users would expect it to be present
// on this.$slots because the usage is semantically a normal slot.
@ -73,11 +76,11 @@ function normalizeScopedSlot(normalSlots, key, fn) {
get: normalized,
enumerable: true,
configurable: true,
})
});
}
return normalized
return normalized;
}
function proxyNormalSlot(slots, key) {
return () => slots[key]
return () => slots[key];
}

View File

@ -35,13 +35,17 @@ const hooks = ['create', 'activate', 'update', 'remove', 'destroy']
function sameVnode(a, b) {
return (
a.key === b.key &&
((a.tag === b.tag &&
a.isComment === b.isComment &&
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b)) ||
(isTrue(a.isAsyncPlaceholder) &&
a.asyncFactory === b.asyncFactory &&
isUndef(b.asyncFactory.error)))
a.asyncFactory === b.asyncFactory && (
(
a.tag === b.tag &&
a.isComment === b.isComment &&
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b)
) || (
isTrue(a.isAsyncPlaceholder) &&
isUndef(b.asyncFactory.error)
)
)
)
}

View File

@ -13,7 +13,7 @@ export default class VNode {
key: string | number | undefined;
componentOptions?: VNodeComponentOptions;
componentInstance?: Component; // component instance
parent: VNode | undefined; // component placeholder node
parent: VNode | undefined | null; // component placeholder node
// strictly internal
raw: boolean; // contains raw HTML? (server only)

View File

@ -18,7 +18,7 @@ function transformNode(el: ASTElement, options: CompilerOptions) {
}
}
if (staticClass) {
el.staticClass = JSON.stringify(staticClass)
el.staticClass = JSON.stringify(staticClass.replace(/\s+/g, ' ').trim())
}
const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
if (classBinding) {

View File

@ -7,6 +7,7 @@ import {
CHECKBOX_RADIO_TOKEN,
} from 'web/compiler/directives/model'
import { currentFlushTimestamp } from 'core/observer/scheduler'
import { emptyNode } from 'core/vdom/patch'
import type { VNodeWithData } from 'typescript/vnode'
// normalize v-model event tokens that can only be determined at runtime.
@ -62,7 +63,7 @@ function add(
if (useMicrotaskFix) {
const attachedTimestamp = currentFlushTimestamp
const original = handler
//@ts-expect-error
//@ts-expect-error
handler = original._wrapper = function (e) {
if (
// no bubbling, should always fire.
@ -111,7 +112,9 @@ function updateDOMListeners(oldVnode: VNodeWithData, vnode: VNodeWithData) {
}
const on = vnode.data.on || {}
const oldOn = oldVnode.data.on || {}
target = vnode.elm
// vnode is empty when removing all listeners,
// and use old vnode dom element
target = vnode.elm || oldVnode.elm
normalizeEvents(on)
updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context)
target = undefined
@ -120,4 +123,6 @@ function updateDOMListeners(oldVnode: VNodeWithData, vnode: VNodeWithData) {
export default {
create: updateDOMListeners,
update: updateDOMListeners,
// @ts-expect-error emptyNode has actually data
destroy: (vnode: VNodeWithData) => updateDOMListeners(vnode, emptyNode)
}

View File

@ -25,11 +25,11 @@ export function createInstanceContext(
instanceId,
config: weex.config,
document: weex.document,
data,
})
data
}
// Each instance has a independent `Vue` module instance
const Vue = (instance.Vue = createVueModuleInstance(instanceId, weex))
// Each instance has an independent `Vue` module instance
const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)
// DEPRECATED
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)

View File

@ -0,0 +1,67 @@
const hash = require('hash-sum')
const uniq = require('lodash.uniq')
import { isJS, isCSS, getAssetName, onEmit, stripModuleIdHash } from './util'
export default class VueSSRClientPlugin {
constructor (options = {}) {
this.options = Object.assign({
filename: 'vue-ssr-client-manifest.json'
}, options)
}
apply (compiler) {
const stage = 'PROCESS_ASSETS_STAGE_ADDITIONAL'
onEmit(compiler, 'vue-client-plugin', stage, (compilation, cb) => {
const stats = compilation.getStats().toJson()
const allFiles = uniq(stats.assets
.map(a => a.name))
const initialFiles = uniq(Object.keys(stats.entrypoints)
.map(name => stats.entrypoints[name].assets)
.reduce((assets, all) => all.concat(assets), [])
.map(getAssetName)
.filter((file) => isJS(file) || isCSS(file)))
const asyncFiles = allFiles
.filter((file) => isJS(file) || isCSS(file))
.filter(file => initialFiles.indexOf(file) < 0)
const manifest = {
publicPath: stats.publicPath,
all: allFiles,
initial: initialFiles,
async: asyncFiles,
modules: { /* [identifier: string]: Array<index: number> */ }
}
const assetModules = stats.modules.filter(m => m.assets.length)
const fileToIndex = asset => manifest.all.indexOf(getAssetName(asset))
stats.modules.forEach(m => {
// ignore modules duplicated in multiple chunks
if (m.chunks.length === 1) {
const cid = m.chunks[0]
const chunk = stats.chunks.find(c => c.id === cid)
if (!chunk || !chunk.files) {
return
}
const id = stripModuleIdHash(m.identifier)
const files = manifest.modules[hash(id)] = chunk.files.map(fileToIndex)
// find all asset modules associated with the same chunk
assetModules.forEach(m => {
if (m.chunks.some(id => id === cid)) {
files.push.apply(files, m.assets.map(fileToIndex))
}
})
}
})
const json = JSON.stringify(manifest, null, 2)
compilation.assets[this.options.filename] = {
source: () => json,
size: () => json.length
}
cb()
})
}
}

View File

@ -1,34 +1,36 @@
const hash = require('hash-sum')
const uniq = require('lodash.uniq')
import { isJS, isCSS, onEmit } from './util'
const hash = require("hash-sum");
const uniq = require("lodash.uniq");
import { isJS, isCSS, getAssetName, onEmit, stripModuleIdHash } from "./util";
export default class VueSSRClientPlugin {
constructor(options = {}) {
//@ts-expect-error
//@ts-expect-error no type on options
this.options = Object.assign(
{
filename: 'vue-ssr-client-manifest.json',
filename: "vue-ssr-client-manifest.json",
},
options
)
);
}
apply(compiler) {
onEmit(compiler, 'vue-client-plugin', (compilation, cb) => {
const stats = compilation.getStats().toJson()
const stage = "PROCESS_ASSETS_STAGE_ADDITIONAL";
onEmit(compiler, "vue-client-plugin", stage, (compilation, cb) => {
const stats = compilation.getStats().toJson();
const allFiles = uniq(stats.assets.map((a) => a.name))
const allFiles = uniq(stats.assets.map((a) => a.name));
const initialFiles = uniq(
Object.keys(stats.entrypoints)
.map((name) => stats.entrypoints[name].assets)
.reduce((assets, all) => all.concat(assets), [])
.map(getAssetName)
.filter((file) => isJS(file) || isCSS(file))
)
);
const asyncFiles = allFiles
.filter((file) => isJS(file) || isCSS(file))
.filter((file) => initialFiles.indexOf(file) < 0)
.filter((file) => initialFiles.indexOf(file) < 0);
const manifest = {
publicPath: stats.publicPath,
@ -38,38 +40,37 @@ export default class VueSSRClientPlugin {
modules: {
/* [identifier: string]: Array<index: number> */
},
}
};
const assetModules = stats.modules.filter((m) => m.assets.length)
const fileToIndex = (file) => manifest.all.indexOf(file)
const assetModules = stats.modules.filter((m) => m.assets.length);
const fileToIndex = (asset) => manifest.all.indexOf(getAssetName(asset));
stats.modules.forEach((m) => {
// ignore modules duplicated in multiple chunks
if (m.chunks.length === 1) {
const cid = m.chunks[0]
const chunk = stats.chunks.find((c) => c.id === cid)
const cid = m.chunks[0];
const chunk = stats.chunks.find((c) => c.id === cid);
if (!chunk || !chunk.files) {
return
return;
}
const id = m.identifier.replace(/\s\w+$/, '') // remove appended hash
const files = (manifest.modules[hash(id)] = chunk.files.map(
fileToIndex
))
const id = stripModuleIdHash(m.identifier);
const files = (manifest.modules[hash(id)] =
chunk.files.map(fileToIndex));
// find all asset modules associated with the same chunk
assetModules.forEach((m) => {
if (m.chunks.some((id) => id === cid)) {
files.push.apply(files, m.assets.map(fileToIndex))
files.push.apply(files, m.assets.map(fileToIndex));
}
})
});
}
})
});
const json = JSON.stringify(manifest, null, 2)
//@ts-expect-error
const json = JSON.stringify(manifest, null, 2);
//@ts-expect-error no type on options
compilation.assets[this.options.filename] = {
source: () => json,
size: () => json.length,
}
cb()
})
};
cb();
});
}
}

View File

@ -1,4 +1,4 @@
import { validate, isJS, onEmit } from './util'
import { validate, isJS, getAssetName, onEmit } from './util'
export default class VueSSRServerPlugin {
constructor(options = {}) {
@ -14,7 +14,8 @@ export default class VueSSRServerPlugin {
apply(compiler) {
validate(compiler)
onEmit(compiler, 'vue-server-plugin', (compilation, cb) => {
const stage = 'PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER'
onEmit(compiler, 'vue-server-plugin', stage, (compilation, cb) => {
const stats = compilation.getStats().toJson()
const entryName = Object.keys(stats.entrypoints)[0]
const entryInfo = stats.entrypoints[entryName]
@ -24,7 +25,9 @@ export default class VueSSRServerPlugin {
return cb()
}
const entryAssets = entryInfo.assets.filter(isJS)
const entryAssets = entryInfo.assets
.map(getAssetName)
.filter(isJS)
if (entryAssets.length > 1) {
throw new Error(
@ -46,16 +49,14 @@ export default class VueSSRServerPlugin {
maps: {},
}
stats.assets.forEach((asset) => {
if (isJS(asset.name)) {
bundle.files[asset.name] = compilation.assets[asset.name].source()
} else if (asset.name.match(/\.js\.map$/)) {
bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(
compilation.assets[asset.name].source()
)
Object.keys(compilation.assets).forEach(name => {
if (isJS(name)) {
bundle.files[name] = compilation.assets[name].source()
} else if (name.match(/\.js\.map$/)) {
bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source())
}
// do not emit anything else for server
delete compilation.assets[asset.name]
delete compilation.assets[name]
})
const json = JSON.stringify(bundle, null, 2)

View File

@ -1,31 +1,51 @@
const { red, yellow } = require('chalk')
const webpack = require('webpack')
const prefix = `[vue-server-renderer-webpack-plugin]`
const warn = (exports.warn = (msg) => console.error(red(`${prefix} ${msg}\n`)))
const tip = (exports.tip = (msg) => console.log(yellow(`${prefix} ${msg}\n`)))
const warn = exports.warn = msg => console.error(red(`${prefix} ${msg}\n`))
const tip = exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`))
export const validate = (compiler) => {
const isWebpack5 = !!(webpack.version && webpack.version[0] > 4)
export const validate = compiler => {
if (compiler.options.target !== 'node') {
warn('webpack config `target` should be "node".')
}
if (
compiler.options.output &&
compiler.options.output.libraryTarget !== 'commonjs2'
) {
warn('webpack config `output.libraryTarget` should be "commonjs2".')
if (compiler.options.output) {
if (compiler.options.output.library) {
// Webpack >= 5.0.0
if (compiler.options.output.library.type !== 'commonjs2') {
warn('webpack config `output.library.type` should be "commonjs2".')
}
} else if (compiler.options.output.libraryTarget !== 'commonjs2') {
// Webpack < 5.0.0
warn('webpack config `output.libraryTarget` should be "commonjs2".')
}
}
if (!compiler.options.externals) {
tip(
'It is recommended to externalize dependencies in the server build for ' +
'better build performance.'
'better build performance.'
)
}
}
export const onEmit = (compiler, name, hook) => {
if (compiler.hooks) {
export const onEmit = (compiler, name, stageName, hook) => {
if (isWebpack5) {
// Webpack >= 5.0.0
compiler.hooks.compilation.tap(name, compilation => {
if (compilation.compiler !== compiler) {
// Ignore child compilers
return
}
const stage = webpack.Compilation[stageName]
compilation.hooks.processAssets.tapAsync({ name, stage }, (assets, cb) => {
hook(compilation, cb)
})
})
} else if (compiler.hooks) {
// Webpack >= 4.0.0
compiler.hooks.emit.tapAsync(name, hook)
} else {
@ -34,4 +54,20 @@ export const onEmit = (compiler, name, hook) => {
}
}
export const stripModuleIdHash = id => {
if (isWebpack5) {
// Webpack >= 5.0.0
return id.replace(/\|\w+$/, '')
}
// Webpack < 5.0.0
return id.replace(/\s\w+$/, '')
}
export const getAssetName = asset => {
if (typeof asset === 'string') {
return asset
}
return asset.name
}
export { isJS, isCSS } from '../util'

View File

@ -34,7 +34,7 @@ export function isPrimitive(value: any): boolean {
/**
* Quick object check - this is primarily used to tell
* Objects from primitive values when we know the value
* objects from primitive values when we know the value
* is a JSON-compliant type.
*/
export function isObject(obj: any): boolean {

View File

@ -52,7 +52,7 @@ describe('SSR: basicRenderer', () => {
})
// #5941
it('should work peoperly when accessing $ssrContext in root component', done => {
it('should work properly when accessing $ssrContext in root component', done => {
let ssrContext
renderToString(new Vue({
template: `

View File

@ -694,6 +694,34 @@ describe('SSR: renderToString', () => {
})
})
// #11963, #10391
it('renders async children passed in slots', done => {
const Parent = {
template: `<div><slot name="child"/></div>`
}
const Child = {
template: `<p>child</p>`
}
renderVmWithOptions({
template: `
<Parent>
<template #child>
<Child/>
</template>
</Parent>
`,
components: {
Parent,
Child: () => Promise.resolve(Child)
}
}, result => {
expect(result).toContain(
`<div data-server-rendered="true"><p>child</p></div>`
)
done()
})
})
it('everything together', done => {
renderVmWithOptions({
template: `
@ -1323,7 +1351,7 @@ describe('SSR: renderToString', () => {
</div>
`
}, result => {
expect(result).toContain(`<div class="a\nb"></div>`)
expect(result).toContain(`<div class="a b"></div>`)
done()
})
})

View File

@ -7,7 +7,7 @@ describe('Component async', () => {
const oldClearTimeout = window.clearTimeout;
// will contain pending timeouts set during the test iteration
// will contain the id of the timeout as the key, and the the millisecond timeout as the value
// will contain the id of the timeout as the key, and the millisecond timeout as the value
// this helps to identify the timeout that is still pending
let timeoutsPending = {};

View File

@ -572,6 +572,73 @@ describe('Component keep-alive', () => {
}).then(done)
})
it('max=1', done => {
const spyA = jasmine.createSpy()
const spyB = jasmine.createSpy()
const spyC = jasmine.createSpy()
const spyAD = jasmine.createSpy()
const spyBD = jasmine.createSpy()
const spyCD = jasmine.createSpy()
function assertCount (calls) {
expect([
spyA.calls.count(),
spyAD.calls.count(),
spyB.calls.count(),
spyBD.calls.count(),
spyC.calls.count(),
spyCD.calls.count()
]).toEqual(calls)
}
const vm = new Vue({
template: `
<keep-alive max="1">
<component :is="n"></component>
</keep-alive>
`,
data: {
n: 'aa'
},
components: {
aa: {
template: '<div>a</div>',
created: spyA,
destroyed: spyAD
},
bb: {
template: '<div>bbb</div>',
created: spyB,
destroyed: spyBD
},
cc: {
template: '<div>ccc</div>',
created: spyC,
destroyed: spyCD
}
}
}).$mount()
assertCount([1, 0, 0, 0, 0, 0])
vm.n = 'bb'
waitForUpdate(() => {
// should prune A because max cache reached
assertCount([1, 1, 1, 0, 0, 0])
vm.n = 'cc'
}).then(() => {
// should prune B because max cache reached
assertCount([1, 1, 1, 1, 1, 0])
vm.n = 'bb'
}).then(() => {
// B is recreated
assertCount([1, 1, 2, 1, 1, 1])
vm.n = 'aa'
}).then(() => {
// B is destroyed and A recreated
assertCount([2, 1, 2, 2, 1, 1])
}).then(done)
})
it('should warn unknown component inside', () => {
new Vue({
template: `<keep-alive><foo/></keep-alive>`
@ -1182,5 +1249,37 @@ describe('Component keep-alive', () => {
}).then(done)
}
})
// #10083
it('should not attach event handler repeatedly', done => {
const vm = new Vue({
template: `
<keep-alive>
<btn v-if="showBtn" @click.native="add" />
</keep-alive>
`,
data: { showBtn: true, n: 0 },
methods: {
add () {
this.n++
}
},
components: {
btn: { template: '<button>add 1</button>' }
}
}).$mount()
const btn = vm.$el
expect(vm.n).toBe(0)
btn.click()
expect(vm.n).toBe(1)
vm.showBtn = false
waitForUpdate(() => {
vm.showBtn = true
}).then(() => {
btn.click()
expect(vm.n).toBe(2)
}).then(done)
})
}
})

View File

@ -1325,4 +1325,28 @@ describe('Component scoped slot', () => {
expect(vm.$el.textContent).toMatch(`1`)
}).then(done)
})
// #11652
it('should update when switching between two components with slot and without slot', done => {
const Child = {
template: `<div><slot/></div>`
}
const parent = new Vue({
template: `<div>
<child v-if="flag"><template #default>foo</template></child>
<child v-else></child>
</div>`,
data: {
flag: true
},
components: { Child }
}).$mount()
expect(parent.$el.textContent).toMatch(`foo`)
parent.flag=false
waitForUpdate(()=>{
expect(parent.$el.textContent).toMatch(``)
}).then(done)
})
})

View File

@ -109,6 +109,47 @@ describe('Component slot', () => {
expect(child.$el.children[1].textContent).toBe('slot b')
})
it('it should work with previous versions of the templates', () => {
const Test = {
render() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || vm._h;
return _c('div', [_vm._t("default", [_c('p', [_vm._v("slot default")])])], 2)
}
}
let vm = new Vue({
template: `<test/>`,
components: { Test }
}).$mount()
expect(vm.$el.textContent).toBe('slot default')
vm = new Vue({
template: `<test>custom content</test>`,
components: { Test }
}).$mount()
expect(vm.$el.textContent).toBe('custom content')
})
it('fallback content should not be evaluated when the parent is providing it', () => {
const test = jasmine.createSpy('test')
const vm = new Vue({
template: '<test>slot default</test>',
components: {
test: {
template: '<div><slot>{{test()}}</slot></div>',
methods: {
test () {
test()
return 'test'
}
}
}
}
}).$mount()
expect(vm.$el.textContent).toBe('slot default')
expect(test).not.toHaveBeenCalled()
})
it('selector matching multiple elements', () => {
mount({
childTemplate: '<div><slot name="t"></slot></div>',
@ -945,4 +986,18 @@ describe('Component slot', () => {
expect(vm.$el.firstChild.innerHTML).toBe('<span><b>2</b></span>')
}).then(done)
})
// #12102
it('v-if inside scoped slot', () => {
const vm = new Vue({
template: `<test><template #custom><span v-if="false">a</span><span>b</span></template></test>`,
components: {
test: {
template: `<div><slot name="custom"/></div>`
}
}
}).$mount()
expect(vm.$el.innerHTML).toBe(`<!----><span>b</span>`)
})
})

View File

@ -152,6 +152,39 @@ describe('Directive v-bind:class', () => {
}).then(done)
})
// css static classes should only contain a single space in between,
// as all the text inside of classes is shipped as a JS string
// and this could lead to useless spacing in static classes
it('condenses whitespace in staticClass', done => {
const vm = new Vue({
template: '<div class=" test1\ntest2\ttest3 test4 test5 \n \n \ntest6\t"></div>',
}).$mount()
expect(vm.$el.className).toBe('test1 test2 test3 test4 test5 test6')
done()
})
it('condenses whitespace in staticClass merge in a component', done => {
const vm = new Vue({
template: `
<component1 class="\n\t staticClass \t\n" :class="componentClass1">
</component1>
`,
data: {
componentClass1: 'componentClass1',
},
components: {
component1: {
template: '<div class="\n\t test \t\n"></div>'
},
}
}).$mount()
expect(vm.$el.className).toBe('test staticClass componentClass1')
vm.componentClass1 = 'c1'
waitForUpdate(() => {
expect(vm.$el.className).toBe('test staticClass c1')
}).then(done)
})
// a vdom patch edge case where the user has several un-keyed elements of the
// same tag next to each other, and toggling them.
it('properly remove staticClass for toggling un-keyed children', done => {

View File

@ -31,7 +31,7 @@ describe('Directive v-on', () => {
expect(event.type).toBe('click')
})
it('should bind event to a inline statement', () => {
it('should bind event to an inline statement', () => {
vm = new Vue({
el,
template: '<div v-on:click="foo(1,2,3,$event)"></div>',
@ -218,7 +218,7 @@ describe('Directive v-on', () => {
})
// ctrl, shift, alt, meta
it('should support system modifers', () => {
it('should support system modifiers', () => {
vm = new Vue({
el,
template: `
@ -976,6 +976,17 @@ describe('Directive v-on', () => {
expect(value).toBe(1)
})
it('should not execute callback if modifiers are present', () => {
vm = new Vue({
el,
template: '<input @keyup.?="foo">',
methods: { foo: spy }
})
// simulating autocomplete event (Event object with type keyup but without keyCode)
triggerEvent(vm.$el, 'keyup')
expect(spy.calls.count()).toBe(0)
})
describe('dynamic arguments', () => {
it('basic', done => {
const spy = jasmine.createSpy()

View File

@ -127,25 +127,25 @@ describe('Error handling', () => {
}).then(done)
})
it('should recover from errors in user watcher callback', done => {
const vm = createTestInstance(components.userWatcherCallback)
vm.n++
waitForUpdate(() => {
expect(`Error in callback for watcher "n"`).toHaveBeenWarned()
expect(`Error: userWatcherCallback`).toHaveBeenWarned()
}).thenWaitFor(next => {
assertBothInstancesActive(vm).end(next)
}).then(done)
})
;[
['userWatcherCallback', 'watcher'],
['userImmediateWatcherCallback', 'immediate watcher']
].forEach(([type, description]) => {
it(`should recover from errors in user ${description} callback`, done => {
const vm = createTestInstance(components[type])
assertBothInstancesActive(vm).then(() => {
expect(`Error in callback for ${description} "n"`).toHaveBeenWarned()
expect(`Error: ${type} error`).toHaveBeenWarned()
}).then(done)
})
it('should recover from errors in user immediate watcher callback', done => {
const vm = createTestInstance(components.userImmediateWatcherCallback)
waitForUpdate(() => {
expect(`Error in callback for immediate watcher "n"`).toHaveBeenWarned()
expect(`Error: userImmediateWatcherCallback error`).toHaveBeenWarned()
}).thenWaitFor(next => {
assertBothInstancesActive(vm).end(next)
}).then(done)
it(`should recover from promise errors in user ${description} callback`, done => {
const vm = createTestInstance(components[`${type}Async`])
assertBothInstancesActive(vm).then(() => {
expect(`Error in callback for ${description} "n" (Promise/async)`).toHaveBeenWarned()
expect(`Error: ${type} error`).toHaveBeenWarned()
}).then(done)
})
})
it('config.errorHandler should capture render errors', done => {
@ -359,6 +359,33 @@ function createErrorTestComponents () {
}
}
components.userWatcherCallbackAsync = {
props: ['n'],
watch: {
n () {
return Promise.reject(new Error('userWatcherCallback error'))
}
},
render (h) {
return h('div', this.n)
}
}
components.userImmediateWatcherCallbackAsync = {
props: ['n'],
watch: {
n: {
immediate: true,
handler () {
return Promise.reject(new Error('userImmediateWatcherCallback error'))
}
}
},
render (h) {
return h('div', this.n)
}
}
// event errors
components.event = {
beforeCreate () {

View File

@ -14,7 +14,7 @@ describe('Global API: set/delete', () => {
}).then(done)
})
it('should update a observing object', done => {
it('should update an observing object', done => {
const vm = new Vue({
template: '<div>{{foo.x}}</div>',
data: { foo: { x: 1 }}
@ -26,7 +26,7 @@ describe('Global API: set/delete', () => {
}).then(done)
})
it('should update a observing array', done => {
it('should update an observing array', done => {
const vm = new Vue({
template: '<div><div v-for="v,k in list">{{k}}-{{v}}</div></div>',
data: { list: ['a', 'b', 'c'] }

View File

@ -206,6 +206,18 @@ describe('Options computed', () => {
expect(`computed property "a" is already defined as a prop`).toHaveBeenWarned()
})
it('warn conflict with methods', () => {
new Vue({
computed: {
a: () => 2
},
methods: {
a: () => {}
}
})
expect(`computed property "a" is already defined as a method`).toHaveBeenWarned()
})
it('rethrow computed error', () => {
const vm = new Vue({
computed: {

View File

@ -247,4 +247,152 @@ describe('Options errorCaptured', () => {
expect(store.errors[0]).toEqual(new Error('render error'))
}).then(done)
})
it('should capture error from watcher', done => {
const spy = jasmine.createSpy()
let child
let err
const Child = {
data () {
return {
foo: null
}
},
watch: {
foo () {
err = new Error('userWatcherCallback error')
throw err
}
},
created () {
child = this
},
render () {}
}
new Vue({
errorCaptured: spy,
render: h => h(Child)
}).$mount()
child.foo = 'bar'
waitForUpdate(() => {
expect(spy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo"')
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo"')
}).then(done)
})
it('should capture promise error from watcher', done => {
const spy = jasmine.createSpy()
let child
let err
const Child = {
data () {
return {
foo: null
}
},
watch: {
foo () {
err = new Error('userWatcherCallback error')
return Promise.reject(err)
}
},
created () {
child = this
},
render () {}
}
new Vue({
errorCaptured: spy,
render: h => h(Child)
}).$mount()
child.foo = 'bar'
child.$nextTick(() => {
waitForUpdate(() => {
expect(spy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo" (Promise/async)')
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo" (Promise/async)')
}).then(done)
})
})
it('should capture error from immediate watcher', done => {
const spy = jasmine.createSpy()
let child
let err
const Child = {
data () {
return {
foo: 'foo'
}
},
watch: {
foo: {
immediate: true,
handler () {
err = new Error('userImmediateWatcherCallback error')
throw err
}
}
},
created () {
child = this
},
render () {}
}
new Vue({
errorCaptured: spy,
render: h => h(Child)
}).$mount()
waitForUpdate(() => {
expect(spy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo"')
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo"')
}).then(done)
})
it('should capture promise error from immediate watcher', done => {
const spy = jasmine.createSpy()
let child
let err
const Child = {
data () {
return {
foo: 'foo'
}
},
watch: {
foo: {
immediate: true,
handler () {
err = new Error('userImmediateWatcherCallback error')
return Promise.reject(err)
}
}
},
created () {
child = this
},
render () {}
}
new Vue({
errorCaptured: spy,
render: h => h(Child)
}).$mount()
waitForUpdate(() => {
expect(spy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo" (Promise/async)')
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo" (Promise/async)')
}).then(done)
})
})

View File

@ -196,7 +196,7 @@ describe('codegen', () => {
it('generate slot fallback content', () => {
assertCodegen(
'<div><slot><div>hi</div></slot></div>',
`with(this){return _c('div',[_t("default",[_c('div',[_v("hi")])])],2)}`
`with(this){return _c('div',[_t("default",function(){return [_c('div',[_v("hi")])]})],2)}`
)
})

View File

@ -1,4 +1,5 @@
import Vue from 'vue'
import { SSR_ATTR } from 'shared/constants'
describe('vdom patch: edge cases', () => {
// exposed by #3406
@ -432,4 +433,22 @@ describe('vdom patch: edge cases', () => {
expect(vm.$el.textContent).not.toMatch('Infinity')
}).then(done)
})
it('should not throw when hydrated pending async component is patched by v-if="false"', done => {
const PendingAsyncComponent = () => new Promise(() => {})
const ssrAsyncComponent = document.createElement('div')
ssrAsyncComponent.setAttribute(SSR_ATTR, 'true')
const vm = new Vue({
data: {
visible: true
},
components: {
PendingAsyncComponent
},
template: '<pending-async-component v-if="visible"></pending-async-component>'
}).$mount(ssrAsyncComponent)
vm.visible = false
vm.$nextTick(done)
})
})

15
types/options.d.ts vendored
View File

@ -12,9 +12,10 @@ export type Component<Data=DefaultData<never>, Methods=DefaultMethods<never>, Co
| FunctionalComponentOptions<Props>
| ComponentOptions<never, Data, Methods, Computed, Props>
interface EsModuleComponent {
default: Component
}
type EsModule<T> = T | { default: T }
type ImportedComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
= EsModule<Component<Data, Methods, Computed, Props>>
export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
= AsyncComponentPromise<Data, Methods, Computed, Props>
@ -23,12 +24,12 @@ export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never
export type AsyncComponentPromise<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = (
resolve: (component: Component<Data, Methods, Computed, Props>) => void,
reject: (reason?: any) => void
) => Promise<Component | EsModuleComponent> | void;
) => Promise<ImportedComponent<Data, Methods, Computed, Props>> | void;
export type AsyncComponentFactory<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = () => {
component: AsyncComponentPromise<Data, Methods, Computed, Props>;
loading?: Component | EsModuleComponent;
error?: Component | EsModuleComponent;
component: Promise<ImportedComponent<Data, Methods, Computed, Props>>;
loading?: ImportedComponent;
error?: ImportedComponent;
delay?: number;
timeout?: number;
}

View File

@ -0,0 +1,44 @@
import Vue, { AsyncComponent, Component } from "../index";
const a: AsyncComponent = () => ({
component: new Promise<Component>((res, rej) => {
res({ template: "" })
})
})
const b: AsyncComponent = () => ({
// @ts-expect-error component has to be a Promise that resolves to a component
component: () =>
new Promise<Component>((res, rej) => {
res({ template: "" })
})
})
const c: AsyncComponent = () =>
new Promise<Component>((res, rej) => {
res({
template: ""
})
})
const d: AsyncComponent = () =>
new Promise<{ default: Component }>((res, rej) => {
res({
default: {
template: ""
}
})
})
const e: AsyncComponent = () => ({
component: new Promise<{ default: Component }>((res, rej) => {
res({
default: {
template: ""
}
})
})
})
// Test that Vue.component accepts any AsyncComponent
Vue.component("async-compponent1", a)

2
types/vue.d.ts vendored
View File

@ -26,7 +26,7 @@ export interface Vue {
readonly $parent: Vue;
readonly $root: Vue;
readonly $children: Vue[];
readonly $refs: { [key: string]: Vue | Element | Vue[] | Element[] };
readonly $refs: { [key: string]: Vue | Element | (Vue | Element)[] | undefined };
readonly $slots: { [key: string]: VNode[] | undefined };
readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined };
readonly $isServer: boolean;

View File

@ -110,7 +110,7 @@ declare class Component {
_render: () => VNode;
__patch__: (
a: Element | VNode | void,
a: Element | VNode | void | null,
b: VNode | null,
hydrating?: boolean,
removeOnly?: boolean,